Nota

Distribuire NVIDIA NIM su OKE per inferenza con il repository di modelli memorizzato nello storage degli oggetti OCI

Introduzione

Questa esercitazione descrive come distribuire NVIDIA NIM su Oracle Cloud Infrastructure Container Engine for Kubernetes (OKE) con il backend NVIDIA TensorRT-LLM e il server di inferenza NVIDIA Triton per servire Large Language Models (LLM) in un'architettura Kubernetes. Il modello utilizzato è Llama2-7B-chat su una GPU A10. Per la scalabilità, stiamo ospitando il repository dei modelli in un bucket in OCI Object Storage.

Nota: tutti i test di questa esercitazione sono stati rilasciati con una versione di accesso anticipato di NVIDIA NIM per LLM con nemollm-inference-ms:24.02.rc4.

Obiettivi

Prerequisiti

Task 1: creare un'istanza GPU in OCI Compute

  1. Eseguire il login a OCI Console, passare al menu OCI, alla computazione, alle istanze e fare clic su Crea istanza.

  2. Seleziona VM.GPU.A10.1 con l'immagine del computer NVIDIA GPU Cloud di Oracle Cloud Marketplace e un volume di avvio di 250 GB. Per ulteriori informazioni, vedere Utilizzo di NVIDIA GPU Cloud con Oracle Cloud Infrastructure.

  3. Una volta che il computer è attivo, connettiti ad esso utilizzando la tua chiave privata e l'IP pubblico del computer.

    ssh -i <private_key> ubuntu@<public_ip>
    
  4. Accertarsi che il volume di avvio abbia aumentato lo spazio.

    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
    

Task 2: aggiornare i driver NVIDIA (facoltativo)

Si consiglia di aggiornare i driver alla versione più recente in base alle indicazioni fornite da NVIDIA con la matrice di compatibilità tra i driver e la versione CUDA. Per ulteriori informazioni, vedere Compatibilità CUDA e Download di CUDA Toolkit 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

Assicurarsi di disporre di nvidia-container-toolkit.

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

Eseguire il comando seguente per controllare la nuova versione.

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

Task 3: Preparare il Registro modello

È possibile utilizzare modelli predefiniti. Tuttavia, scegliamo di eseguire Llama2-7B-chat su una GPU A10. Al momento della scrittura, questa scelta non è disponibile e, pertanto, dobbiamo creare il repository dei modelli da soli.

  1. Creare un bucket denominato NIM nello storage degli oggetti OCI. Per ulteriori informazioni, consulta la sezione relativa alla creazione di un bucket di storage degli oggetti.

  2. Vai alla finestra del terminale, accedi al registro del contenitore NVIDIA con il tuo nome utente e password e tira il contenitore. eseguire il comando seguente.

    docker login nvcr.io
    docker pull nvcr.io/ohlfw0olaadg/ea-participants/nemollm-inference-ms:24.02.rc4
    
  3. Duplicare il modello 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. Creare la configurazione del modello.

    Copiare il file model_config.yaml e creare la directory per ospitare l'area di memorizzazione dei modelli. Questo è dove il comando generatore del repository modelli memorizzerà l'output.

    mkdir model-store
    chmod -R 777 model-store
    
  5. Eseguire il comando generatore del repository modelli.

    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. Esporta il repository del modello in un bucket di OCI Object Storage.

    Il repository dei modelli si trova nella directory model-store. Puoi utilizzare l'interfaccia della riga di comando di Oracle Cloud Infrastructure (OCI CLI) per eseguire un caricamento di massa in uno dei tuoi bucket nell'area. Per questa esercitazione, il bucket è NIM in cui si desidera che l'area di memorizzazione modelli venga caricata in NIM/llama2-7b-hf (nel caso in cui venga caricata una configurazione modello diversa nello stesso bucket).

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

Task 4: inviare una richiesta alla Virtual Machine (esecuzione IaaS)

Ora il repository dei modelli viene caricato in un bucket di storage degli oggetti OCI.

Nota: il parametro di opzione --model-repository è attualmente non modificabile nel contenitore. Non è possibile puntare semplicemente al bucket all'avvio. Un'opzione sarà quella di adattare lo script Python all'interno del contenitore, ma avremo bisogno del privilegio sudo. L'altro sarà quello di montare direttamente il bucket come file system sul computer. Per questa esercitazione, viene scelto il secondo metodo con rclone. Assicurarsi che sul sistema siano installati fuse3 e jq. Su Ubuntu, è possibile eseguire sudo apt install fuse3 jq.

  1. Ottenere lo spazio di nomi, l'OCID compartimento e l'area, recuperandoli dalla console OCI o eseguendo i comandi seguenti dall'istanza di computazione.

    #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. Scaricare e installare rclone.

    curl https://rclone.org/install.sh | sudo bash
    
  3. Preparare il file di configurazione rclone. Assicurarsi di aggiornare ##NAMESPACE## ##COMPARTMENT_OCID## ##REGION## con i valori specificati.

    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. Installare il bucket utilizzando 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. In un'altra finestra del terminale, è possibile controllare che ls $HOME/test_directory/model_bucket_oci restituisca il contenuto del bucket.

  6. In un'altra finestra del terminale, avviare il contenitore che passa il percorso a model-store come argomento.

    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. Dopo 3 minuti, il server di inferenza deve essere pronto per essere utilizzato. In un'altra finestra del terminale, è possibile eseguire la richiesta seguente.

    Nota: se si desidera eseguirlo dal computer locale, sarà necessario utilizzare l'IP pubblico e aprire la porta 9999 sia a livello di computer che di subnet.

    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"
    

Task 5: aggiornare lo script cloud-init

Nota: in teoria, un modo più semplice per utilizzare rclone in Kubernetes sarebbe quello di utilizzare il contenitore rclone come sidecar prima di avviare il server di inferenza. Funziona bene localmente utilizzando Docker, ma poiché ha bisogno dell'opzione --device per utilizzare fuse, questo rende complicato l'uso con Kubernetes a causa della mancanza di supporto per questa funzione (volumi FUSE, una richiesta di funzionalità del 2015 ancora molto attiva a partire da marzo 2024). Per questa esercitazione, la soluzione che scegliamo è impostare rclone come servizio sull'host e installare il bucket all'avvio.

Nello script cloud-init, sostituire il valore delle righe 17, 18 e 19 ##NAMESPACE##, ##COMPARTMENT_OCID## e ##REGION## con i valori recuperati nel task 4.1. È inoltre possibile aggiornare il valore del periodo fisso nella riga 57. Per impostazione predefinita, è denominata NIM e dispone di una directory denominata llama2-7b-hf.

Questo script cloud-init verrà caricato sul nodo GPU nel cluster OKE. La prima parte consiste nell'aumentare il volume di avvio al set di valori. Quindi scarica rclone, crea le directory corrette e crea il file di configurazione, allo stesso modo in cui abbiamo fatto sulla VM GPU. Infine, avvia rclone come servizio e installa il bucket in /opt/mnt/model_bucket_oci.

Task 6: Distribuisci su OKE

L'architettura di destinazione alla fine della distribuzione è illustrata nella seguente immagine.

Diagramma dell'architettura

Ora, mettere tutto insieme in OKE.

Creare un cluster OKE con lievi adattamenti. Per ulteriori informazioni, vedere Utilizzo della console per creare un cluster con impostazioni predefinite nel workflow 'Creazione rapida'.

Task 7: Distribuisci utilizzando Helm in OCI Cloud Shell

Per accedere a OCI Cloud Shell, vedere Per accedere a Cloud Shell tramite la console.

  1. La configurazione Helm è disponibile nell'archivio oke.zip, in cui è necessario aggiornare values.yaml. Caricare l'archivio nella Cloud Shell OCI ed estrarlo. Per ulteriori informazioni, vedere Per caricare un file in Cloud Shell utilizzando il menu.

    unzip oke.zip
    cd oke
    
  2. Rivedere le credenziali per il segreto per estrarre l'immagine in values.yaml. Per ulteriori informazioni, vedere Creazione di segreti pull immagine.

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

Task 8: Distribuire il monitoraggio

Il monitoraggio consiste in pod Grafana e Prometheus. La configurazione proviene da kube-prometheus-stack.

Qui aggiungiamo un load balancer pubblico per raggiungere il dashboard Grafana da Internet. Utilizzare username=admin e password=xxxxxxxxx per eseguire il login. Il flag serviceMonitorSelectorNilUsesHelmValues è necessario in modo che Prometheus possa trovare le metriche del server di inferenza nella release di esempio distribuita.

  1. Distribuire i pod di monitoraggio.

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

Nota: il load balancer predefinito creato con una forma fissa e una larghezza di banda di 100Mbps. Puoi passare a una forma flessibile e adattare la larghezza di banda in base ai tuoi limiti OCI nel caso in cui la larghezza di banda sia un collo di bottiglia. Per ulteriori informazioni, vedere Provisioning dei load balancer OCI per i servizi Kubernetes di tipo LoadBalancer.

  1. Un dashboard Grafana di esempio è disponibile in dashboard-review.json in oke.zip. Utilizzare la funzione di importazione in Grafana per importare e visualizzare questo dashboard.

  2. È possibile visualizzare l'IP pubblico del dashboard Grafana eseguendo il comando seguente.

    $ 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
    

Task 9: Distribuzione del server inferenziale

  1. Eseguire il comando seguente per distribuire il server inferenza utilizzando la configurazione predefinita.

    cd <directory containing Chart.yaml>
    helm install example . -f values.yaml --debug
    
  2. Utilizzare kubectl per visualizzare lo stato e attendere l'esecuzione dei pod del server di inferenza. La prima estrazione potrebbe richiedere alcuni minuti. Una volta creato il contenitore, il caricamento del modello richiede anche alcuni minuti. Il comando seguente consente di monitorare il pod.

    kubectl describe pods <POD_NAME>
    kubectl logs <POD_NAME>
    
  3. Una volta completata l'impostazione, il contenitore dovrebbe essere in esecuzione.

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

Task 10: Utilizza Triton Inference Server sul tuo NIM Container NVIDIA

Il server di inferenza è in esecuzione. È possibile inviare richieste HTTP o Google Remote Procedure Call (gRPC) per eseguire l'inferenza. Per impostazione predefinita, il servizio di inferenza viene esposto con un tipo di servizio LoadBalancer. Utilizzare quanto segue per trovare l'IP esterno per il server inferenza. In questa esercitazione si trova 34.83.9.133.

  1. Ottenere i servizi per ottenere l'IP pubblico del server inferenza.

    $ 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. Il server di inferenza espone un endpoint HTTP sulla porta 8000 e un endpoint gRPC sulla porta 8001 e un endpoint delle metriche Prometheus sulla porta 8002. È possibile utilizzare curl per ottenere i metadati del server inferenza dall'endpoint HTTP.

    $ curl 34.83.9.133:8000/v2
    
  3. Dal computer client, è possibile inviare una richiesta all'IP pubblico sulla porta 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"
    

    L'output dovrebbe essere il seguente:

    "\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."
    

Task 11: eseguire il cleanup della distribuzione

  1. Una volta terminato l'utilizzo del server inferenza, è necessario utilizzare la timeline per eliminare la distribuzione.

    $ 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. Per i servizi Prometheus e Grafana, è necessario eliminare in modo esplicito i CRD. Per ulteriori informazioni, vedere Disinstalla grafico 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. Puoi anche eliminare il bucket di storage degli oggetti OCI creato per contenere il repository dei modelli.

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

Conferme

Altre risorse di apprendimento

Esplora altri laboratori su docs.oracle.com/learn o accedi a più contenuti gratuiti sulla formazione su Oracle Learning YouTube channel. Inoltre, visita education.oracle.com/learning-explorer per diventare un Oracle Learning Explorer.

Per la documentazione del prodotto, visita l'Oracle Help Center.