Remarques :

Déployer NVIDIA NIM sur OKE pour l'inférence avec le référentiel de modèles stocké sur OCI Object Storage

Introduction

Ce tutoriel explique comment déployer NVIDIA NIM sur Oracle Cloud Infrastructure Container Engine for Kubernetes (OKE) avec le back-end NVIDIA TensorRT-LLM et le serveur d'inférence NVIDIA Triton pour servir les modèles LLM (Large Language Models) dans une architecture Kubernetes. Le modèle utilisé est Llama2-7B-chat sur un GPU A10. Pour plus d'évolutivité, nous hébergeons le référentiel de modèles sur un bucket dans OCI Object Storage.

Remarque : tous les tests de ce tutoriel ont été publiés avec une version d'accès anticipé de NVIDIA NIM pour les LLM avec nemollm-inference-ms:24.02.rc4.

Objectifs

Prérequis

Tâche 1 : créer une instance de GPU dans OCI Compute

  1. Connectez-vous à la console OCI, accédez au menu OCI, à Compute, à Instances et cliquez sur Créer une instance.

  2. Sélectionnez VM.GPU.A10.1 avec l'image Oracle Cloud Marketplace NVIDIA GPU Cloud et un volume d'initialisation de 250 Go. Pour plus d'informations, reportez-vous à Utilisation de NVIDIA GPU Cloud avec Oracle Cloud Infrastructure.

  3. Une fois l'ordinateur démarré, connectez-vous à l'aide de votre clé privée et de l'adresse IP publique de l'ordinateur.

    ssh -i <private_key> ubuntu@<public_ip>
    
  4. Assurez-vous que le volume d'initialisation a augmenté l'espace.

    df -h     # check the initial space on disk
    sudo growpart /dev/sda 1
    sudo resize2fs /dev/sda1
    df -h     # check the space after the commands execution
    

Tâche 2 : mise à jour des pilotes NVIDIA (facultatif)

Il est recommandé de mettre à jour vos pilotes vers la dernière version en fonction des conseils fournis par NVIDIA avec la matrice de compatibilité entre les pilotes et votre version CUDA. Pour plus d'informations, reportez-vous aux sections CUDA Compatibility et CUDA Toolkit 12.4 Update 1 Downloads.

sudo apt purge nvidia* libnvidia*
sudo apt-get install -y cuda-drivers-545
sudo apt-get install -y nvidia-kernel-open-545
sudo apt-get -y install cuda-toolkit-12-3
sudo reboot

Assurez-vous que vous disposez de nvidia-container-toolkit.

sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

Exécutez la commande suivante pour vérifier la nouvelle version.

nvidia-smi
/usr/local/cuda/bin/nvcc --version

Tâche 3 : préparer le registre de modèles

Il est possible d'utiliser des modèles prédéfinis. Cependant, nous choisissons d'exécuter Llama2-7B-chat sur un GPU A10. Au moment de la rédaction du présent document, ce choix n'est pas disponible et nous devons donc créer le référentiel de modèles nous-mêmes.

  1. Créez un bucket nommé NIM dans OCI Object Storage. Pour plus d'informations, reportez-vous à Création d'un bucket Object Storage.

  2. Accédez à la fenêtre de terminal, connectez-vous au registre de conteneurs NVIDIA avec votre nom d'utilisateur et votre mot de passe, puis récupérez le conteneur. Exécutez la commande suivante .

    docker login nvcr.io
    docker pull nvcr.io/ohlfw0olaadg/ea-participants/nemollm-inference-ms:24.02.rc4
    
  3. Clonez le modèle HuggingFace.

    # Install git-lfs
    curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
    sudo apt-get install git-lfs
    
    # clone the model from HF
    git clone https://huggingface.co/meta-llama/Llama-2-7b-chat-hf
    
  4. Créez la configuration du modèle.

    Copiez le fichier model_config.yaml et créez le répertoire pour héberger la banque de modèles. C'est là que la commande Model Repository Generator stockera la sortie.

    mkdir model-store
    chmod -R 777 model-store
    
  5. Exécutez la commande Model Repository Generator.

    docker run --rm -it --gpus all -v $(pwd)/model-store:/model-store -v $(pwd)/model_config.yaml:/model_config.yaml -v $(pwd)/Llama-2-7b-chat-hf:/engine_dir nvcr.io/ohlfw0olaadg/ea-participants/nemollm-inference-ms:24.02.rc4 bash -c "model_repo_generator llm --verbose --yaml_config_file=/model_config.yaml"
    
  6. Exportez le référentiel de modèles vers un bucket OCI Object Storage.

    Le référentiel de modèles se trouve dans le répertoire model-store. Vous pouvez utiliser l'interface de ligne de commande Oracle Cloud Infrastructure (interface de ligne de commande OCI) pour effectuer un téléchargement en masse vers l'un de vos buckets de la région. Pour ce tutoriel, le bucket est NIM, où nous voulons que la banque de modèles soit téléchargée dans NIM/llama2-7b-hf (si nous téléchargeons une configuration de modèle différente vers le même bucket).

    cd model-store
    oci os object bulk-upload -bn NIM --src-dir . --prefix llama2-7b-hf/ --auth instance_principal
    

Tâche 4 : soumettre une demande à la machine virtuelle (exécution IaaS)

Désormais, le référentiel de modèles est téléchargé vers un bucket OCI Object Storage.

Remarque : le paramètre d'option --model-repository est actuellement codé en dur dans le conteneur. Nous ne pouvons pas simplement pointer vers le bucket au démarrage. Une option consiste à adapter le script Python dans le conteneur, mais nous aurons besoin du privilège sudo. L'autre consiste à monter le bucket en tant que système de fichiers directement sur l'ordinateur. Pour ce tutoriel, nous choisissons la deuxième méthode avec rclone. Assurez-vous que fuse3 et jq sont installés sur l'ordinateur. Sur Ubuntu, vous pouvez exécuter sudo apt install fuse3 jq.

  1. Obtenez votre espace de noms, votre OCID de compartiment et votre région, en les extrayant de la console OCI ou en exécutant les commandes suivantes à partir de votre instance de calcul.

    #NAMESPACE:
    echo namespace is : `oci os ns get --auth instance_principal | jq .data`
    
    #COMPARTMENT_OCID:
    echo compartment ocid is: `curl -H "Authorization: Bearer Oracle" -L http://169.254.169.254/opc/v2/instance/ | jq .compartmentId`
    
    #REGION:
    echo region is: `curl -H "Authorization: Bearer Oracle" -L http://169.254.169.254/opc/v2/instance/ | jq .region`
    
  2. Téléchargez et installez rclone.

    curl https://rclone.org/install.sh | sudo bash
    
  3. Préparez le fichier de configuration du clone. Veillez à mettre à jour ##NAMESPACE## ##COMPARTMENT_OCID## ##REGION## avec vos valeurs.

    mkdir -p ~/rclone
    mkdir -p ~/test_directory/model_bucket_oci
    
    
    cat << EOF > ~/rclone/rclone.conf
    [model_bucket_oci]
    type = oracleobjectstorage
    provider = instance_principal_auth
    namespace = ##NAMESPACE##
    compartment = ##COMPARTMENT_OCID##
    region = ##REGION##
    
    EOF
    
  4. Montez le bucket à l'aide de rclone.

    sudo /usr/bin/rclone mount --config=$HOME/rclone/rclone.conf --tpslimit 50 --vfs-cache-mode writes --allow-non-empty --transfers 10 --allow-other model_bucket_oci:NIM/llama2-7b-hf $HOME/test_directory/model_bucket_oci
    
  5. Dans une autre fenêtre de terminal, vous pouvez vérifier que ls $HOME/test_directory/model_bucket_oci renvoie le contenu du bucket.

  6. Dans une autre fenêtre de terminal, démarrez le conteneur en transmettant le chemin à model-store en tant qu'argument.

    docker run --gpus all -p9999:9999 -p9998:9998 -v  $HOME/test_directory/model_bucket_oci:/model-store nvcr.io/ohlfw0olaadg/ea-participants/nemollm-inference-ms:24.02.rc4 nemollm_inference_ms --model llama2-7b-chat --openai_port="9999" --nemo_port="9998" --num_gpus 1
    
  7. Au bout de 3 minutes, le serveur d'inférence doit être prêt à être utilisé. Dans une autre fenêtre de terminal, vous pouvez exécuter la demande suivante.

    Remarque : si vous voulez l'exécuter à partir de votre ordinateur local, vous devez utiliser l'adresse IP publique et ouvrir le port 9999 au niveau de l'ordinateur et du sous-réseau.

    curl -X "POST" 'http://localhost:9999/v1/completions' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{ "model": "llama2-7b-chat", "prompt": "Can you briefly describe Oracle Cloud?", "max_tokens": 100, "temperature": 0.7, "n": 1, "stream": false, "stop": "string", "frequency_penalty": 0.0 }' | jq ".choices[0].text"
    

Tâche 5 : mettre à jour le script cloud-init

Remarque : idéalement, une façon plus propre d'utiliser rclone dans Kubernetes consisterait à utiliser le conteneur rclone en tant que sidecar avant de démarrer le serveur d'inférence. Cela fonctionne très bien localement avec Docker, mais comme il a besoin de l'option --device pour utiliser fuse, son utilisation avec Kubernetes est compliquée en raison du manque de prise en charge de cette fonctionnalité (volumes FUSE, une demande de fonctionnalité de 2015 toujours très active en mars 2024). Pour ce tutoriel, la solution de contournement que nous choisissons consiste à configurer rclone en tant que service sur l'hôte et à monter le bucket au démarrage.

Dans le script cloud-init, remplacez la valeur des lignes 17, 18 et 19 des lignes ##NAMESPACE##, ##COMPARTMENT_OCID## et ##REGION## par les valeurs extraites dans la tâche 4.1. Vous pouvez également mettre à jour la valeur du regroupement à la ligne 57. Par défaut, il est appelé NIM et dispose d'un répertoire appelé llama2-7b-hf.

Ce script cloud-init sera téléchargé sur le noeud de GPU de votre cluster OKE. La première partie consiste à augmenter le volume d'initialisation à la valeur définie. Il télécharge ensuite rclone, crée les répertoires appropriés et crée le fichier de configuration, comme nous l'avons fait sur la machine virtuelle GPU. Enfin, il démarre rclone en tant que service et monte le bucket vers /opt/mnt/model_bucket_oci.

Tâche 6 : déploiement sur OKE

L'architecture cible à la fin du déploiement est comme indiqué dans l'image suivante.

Diagramme d'architecture

Maintenant, mettez tout ensemble dans OKE.

Créez un cluster OKE avec de légères adaptations. Pour plus d'informations, reportez-vous à Utilisation de la console pour créer un cluster avec des paramètres par défaut dans le workflow Création rapide.

Tâche 7 : déploiement à l'aide de Helm dans OCI Cloud Shell

Pour accéder à OCI Cloud Shell, reportez-vous à Procédure d'accès à Cloud Shell via la console.

  1. Vous pouvez trouver la configuration Helm dans l'archive oke.zip, où vous devez mettre à jour values.yaml. Téléchargez l'archive vers OCI Cloud Shell et décompressez-la. Pour plus d'informations, reportez-vous à Procédure de téléchargement d'un fichier vers Cloud Shell à l'aide du menu.

    unzip oke.zip
    cd oke
    
  2. Vérifiez les informations d'identification de la clé secrète pour extraire l'image dans values.yaml. Pour plus d'informations, reportez-vous à Création de clés secrètes d'extraction d'image.

    registry: nvcr.io
    username: $oauthtoken
    password: <YOUR_KEY_FROM_NVIDIA>
    email: someone@host.com
    

Tâche 8 : déployer la surveillance

La surveillance se compose de pods Grafana et Prometheus. La configuration provient de kube-prometheus-stack.

Ici, nous ajoutons un équilibreur de charge public pour accéder au tableau de bord Grafana à partir d'Internet. Utilisez username=admin et password=xxxxxxxxx pour vous connecter. L'indicateur serviceMonitorSelectorNilUsesHelmValues est nécessaire pour que Prometheus puisse trouver les mesures du serveur d'inférence dans l'exemple de version déployée.

  1. Déployez les pods de surveillance.

    helm install example-metrics --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false --set grafana.service.type=LoadBalancer prometheus-community/kube-prometheus-stack --debug
    

Remarque : équilibreur de charge par défaut créé avec une forme fixe et une bande passante de 100 Mbits/s. Vous pouvez passer à une forme flexible et adapter la bande passante en fonction de vos limites OCI au cas où la bande passante serait un goulet d'étranglement. Pour plus d'informations, reportez-vous à Provisionnement des équilibreurs de charge OCI pour les services Kubernetes de type LoadBalancer.

  1. Un exemple de tableau de bord Grafana est disponible dans dashboard-review.json situé dans oke.zip. Utilisez la fonction d'importation dans Grafana pour importer et afficher ce tableau de bord.

  2. Vous pouvez voir l'adresse IP publique de votre tableau de bord Grafana en exécutant la commande suivante.

    $ kubectl get svc
    NAME                                       TYPE           CLUSTER-IP     EXTERNAL-IP       PORT(S)                      AGE
    alertmanager-operated                      ClusterIP      None           <none>            9093/TCP,9094/TCP,9094/UDP   2m33s
    example-metrics-grafana                    LoadBalancer   10.96.82.33    141.145.220.114   80:31005/TCP                 2m38s
    

Tâche 9 : déployer le serveur d'inférence

  1. Exécutez la commande suivante pour déployer le serveur d'inférence à l'aide de la configuration par défaut.

    cd <directory containing Chart.yaml>
    helm install example . -f values.yaml --debug
    
  2. Utilisez kubectl pour voir le statut et attendre que les pods du serveur d'inférence soient en cours d'exécution. La première traction peut prendre quelques minutes. Une fois le conteneur créé, le chargement du modèle prend également quelques minutes. Vous pouvez surveiller le pod à l'aide de la commande suivante.

    kubectl describe pods <POD_NAME>
    kubectl logs <POD_NAME>
    
  3. Une fois la configuration terminée, votre conteneur doit être en cours d'exécution.

    $ kubectl get pods
    NAME                                               READY   STATUS    RESTARTS   AGE
    example-triton-inference-server-5f74b55885-n6lt7   1/1     Running   0          2m21s
    

Tâche 10 : utiliser le serveur d'inférence Triton sur votre conteneur NIM NVIDIA

Le serveur d'inférence est en cours d'exécution. Vous pouvez lui envoyer des demandes HTTP ou Google Remote Procedure Call (gRPC) pour effectuer l'inférence. Par défaut, le service d'inférence est exposé avec un type de service LoadBalancer. Utilisez ce qui suit pour rechercher l'adresse IP externe du serveur d'inférence. Dans ce tutoriel, il s'agit de 34.83.9.133.

  1. Obtenez les services pour obtenir l'adresse IP publique de votre serveur d'inférence.

    $ kubectl get services
    NAME                             TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                                        AGE
    ...
    example-triton-inference-server  LoadBalancer   10.18.13.28    34.83.9.133   8000:30249/TCP,8001:30068/TCP,8002:32723/TCP   47m
    
  2. Le serveur d'inférence expose une adresse HTTP sur le port 8000, et une adresse gRPC sur le port 8001 et une adresse de mesures Prometheus sur le port 8002. Vous pouvez utiliser curl pour obtenir les métadonnées du serveur d'inférence à partir de l'adresse HTTP.

    $ curl 34.83.9.133:8000/v2
    
  3. Sur votre ordinateur client, vous pouvez envoyer une demande à l'adresse IP publique sur le port 9999.

    curl -X "POST" 'http://34.83.9.133:9999/v1/completions' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{ "model": "llama2-7b-chat", "prompt": "Can you briefly describe Oracle Cloud?", "max_tokens": 100, "temperature": 0.7, "n": 1, "stream": false, "stop": "string", "frequency_penalty": 0.0 }' | jq ".choices[0].text"
    

    La sortie doit ressembler à :

    "\n\nOracle Cloud is a comprehensive cloud computing platform offered by Oracle Corporation. It provides a wide range of cloud services, including Infrastructure as a Service (IaaS), Platform as a Service (PaaS), and Software as a Service (SaaS). Oracle Cloud offers a variety of benefits, including:\n\n1. Scalability: Oracle Cloud allows customers to scale their resources up or down as needed, providing the flexibility to handle changes in business demand."
    

Tâche 11 : nettoyer le déploiement

  1. Une fois que vous avez terminé d'utiliser le serveur d'inférence, vous devez utiliser helm pour supprimer le déploiement.

    $ helm list
    NAME            REVISION  UPDATED                   STATUS    CHART                          APP VERSION   NAMESPACE
    example         1         Wed Feb 27 22:16:55 2019  DEPLOYED  triton-inference-server-1.0.0  1.0           default
    example-metrics	1       	Tue Jan 21 12:24:07 2020	DEPLOYED	prometheus-operator-6.18.0   	 0.32.0     	 default
    
    $ helm uninstall example --debug
    $ helm uninstall example-metrics
    
  2. Pour les services Prometheus et Grafana, vous devez supprimer explicitement les CRD. Pour plus d'informations, reportez-vous à Désinstallation du graphique Helm.

    $ kubectl delete crd alertmanagerconfigs.monitoring.coreos.com alertmanagers.monitoring.coreos.com podmonitors.monitoring.coreos.com probes.monitoring.coreos.com prometheuses.monitoring.coreos.com prometheusrules.monitoring.coreos.com servicemonitors.monitoring.coreos.com thanosrulers.monitoring.coreos.com
    
  3. Vous pouvez également supprimer le bucket OCI Object Storage créé pour contenir le référentiel de modèles.

    $ oci os bucket delete --bucket-name NIM --empty
    

Remerciements

Ressources de formation supplémentaires

Parcourez d'autres ateliers sur docs.oracle.com/learn ou accédez à davantage de contenus de formation gratuits sur le canal Oracle Learning YouTube. De plus, rendez-vous sur education.oracle.com/learning-explorer pour devenir un explorateur Oracle Learning.

Pour obtenir de la documentation sur le produit, visitez Oracle Help Center.