Note :

Déployer NVIDIA NIM sur OKE pour l'inférence avec le référentiel de modèles stocké dans le stockage d'objets OCI

Présentation

Ce tutoriel explique comment déployer NVIDIA NIM sur Oracle Cloud Infrastructure Container Engine for Kubernetes (OKE) avec le serveur dorsal NVIDIA TensorRT-LLM et le serveur d'inférence NVIDIA Triton pour servir les modèles de langage étendu (LLM) 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 seau dans le service de stockage d'objets pour OCI.

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

Objectifs

Préalables

Tâche 1 : Créer une instance GPU dans le service de calcul OCI

  1. Connectez-vous à la console OCI, naviguez jusqu'au menu OCI, au calcul, aux instances et cliquez sur Créer une instance.

  2. Sélectionnez VM.GPU.A10.1 avec l'image de machine NVIDIA GPU Cloud pour Oracle Cloud Marketplace et un volume de démarrage de 250 Go. Pour plus d'informations, voir Utilisation de NVIDIA GPU Cloud avec Oracle Cloud Infrastructure.

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

    ssh -i <private_key> ubuntu@<public_ip>
    
  4. Vérifiez que le volume de démarrage 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 : Mettre à jour les 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, voir Compatibilité CUDA et Téléchargements de la boîte à outils CUDA 12.4 Update 1.

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 d'avoir 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. Toutefois, nous choisissons d'exécuter Llama2-7B-chat sur un processeur graphique A10. Au moment de l'écriture, 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 seau nommé NIM dans le service de stockage d'objets pour OCI. Pour plus d'informations, voir Création d'un seau de stockage d'objets.

  2. Allez à la fenêtre de terminal, connectez-vous au registre de conteneurs NVIDIA avec votre nom d'utilisateur et votre mot de passe, puis extrayez 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 le magasin de modèles. C'est là que la commande du générateur de référentiel de modèles stockera la sortie.

    mkdir model-store
    chmod -R 777 model-store
    
  5. Exécutez la commande du générateur de référentiel de modèles.

    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 seau de stockage d'objets OCI.

    Le référentiel de modèles se trouve dans le répertoire model-store. Vous pouvez utiliser l'interface de ligne de commande d'Oracle Cloud Infrastructure pour effectuer un chargement en masse vers l'un de vos seaux de la région. Pour ce tutoriel, le seau est NIM où le magasin de modèles doit être chargé dans NIM/llama2-7b-hf (au cas où nous chargerions une configuration de modèle différente dans le même seau).

    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)

Maintenant, le référentiel de modèles est chargé dans un seau de stockage d'objets OCI.

Note : Le paramètre d'option --model-repository est actuellement codé en dur dans le conteneur. Nous ne pouvons pas simplement pointer vers le seau lorsque nous le démarrons. Une option consistera à adapter le script Python dans le conteneur, mais nous aurons besoin du privilège sudo. L'autre sera de monter le seau en tant que système de fichiers directement sur l'ordinateur. Pour ce tutoriel, nous sélectionnons 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 rclone. 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 seau à 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 retourne le contenu du seau.

  6. Dans une autre fenêtre de terminal, démarrez le conteneur transmettant le chemin d'accès à 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. Après 3 minutes, le serveur d'inférence doit être prêt à servir. Dans une autre fenêtre de terminal, vous pouvez exécuter la demande suivante.

    Note : 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 la machine 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

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

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

Ce script cloud-init sera chargé sur votre noeud GPU dans votre grappe OKE. La première partie consiste à augmenter le volume de démarrage au jeu de valeurs. Ensuite, il télécharge rclone, crée les répertoires corrects 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 seau sur /opt/mnt/model_bucket_oci.

Tâche 6 : Déployer sur OKE

L'architecture cible à la fin du déploiement est présentée 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, voir Utilisation de la console pour créer une grappe avec les paramètres par défaut dans le flux de création rapide.

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

Pour accéder à Cloud Shell pour OCI, voir Pour accéder à Cloud Shell au moyen de la console.

  1. Vous pouvez trouver la configuration Helm dans l'archive oke.zip, où vous devez mettre à jour values.yaml. Chargez l'archive dans votre Cloud Shell pour OCI et décompressez-la. Pour plus d'informations, voir Pour charger un fichier dans Cloud Shell au moyen du menu.

    unzip oke.zip
    cd oke
    
  2. Vérifiez vos données d'identification pour la clé secrète afin d'extraire l'image dans values.yaml. Pour plus d'informations, voir 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 atteindre le 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
    

Note : L'équilibreur de charge par défaut créé avec une forme fixe et une bande passante de 100 Mbit/s. Vous pouvez passer à une forme flexible et adapter la bande passante en fonction des limites OCI au cas où la bande passante serait un goulot d'étranglement. Pour plus d'informations, voir 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 voir 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 l'exécution des pods du serveur d'inférence. 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 d'appel de procédure distante HTTP ou Google (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 un point d'extrémité HTTP sur le port 8000, et un point d'extrémité gRPC sur le port 8001 et un point d'extrémité de mesures Prometheus sur le port 8002. Vous pouvez utiliser curl pour obtenir les métadonnées du serveur d'inférence à partir du point d'extrémité HTTP.

    $ curl 34.83.9.133:8000/v2
    
  3. À partir de 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, voir Désinstaller le 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 seau de stockage d'objets OCI créé pour contenir le référentiel de modèles.

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

Confirmation

Autres ressources d'apprentissage

Explorez d'autres laboratoires sur la page docs.oracle.com/learn ou accédez à plus de contenu d'apprentissage gratuit sur le canal YouTube d'Oracle Learning. De plus, visitez education.oracle.com/learning-explorer pour devenir un explorateur Oracle Learning.

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