Observação:

Implantar NVIDIA NIM no OKE para Inferência com o Repositório de Modelos Armazenado no OCI Object Storage

Introdução

Este tutorial demonstra como implantar o NVIDIA NIM no Oracle Cloud Infrastructure Container Engine for Kubernetes (OKE) com o backend NVIDIA TensorRT-LLM e o servidor de inferência NVIDIA Triton para atender aos LMs (Large Language Models) em uma arquitetura Kubernetes. O modelo usado é Llama2-7B-chat em uma GPU A10. Para escalabilidade, estamos hospedando o repositório de modelos em um bucket no OCI Object Storage.

Observação: Todos os testes deste tutorial foram lançados com uma versão de acesso antecipado do NVIDIA NIM para LLM's com nemollm-inference-ms:24.02.rc4.

Objetivos

Pré-requisitos

Tarefa 1: Criar uma Instância de GPU no OCI Compute

  1. Faça log-in na Console do OCI, navegue até Menu do OCI, Compute, Instâncias e clique em Criar Instância.

  2. Selecione VM.GPU.A10.1 com a imagem da máquina NVIDIA GPU Cloud da imagem do Oracle Cloud Marketplace e um volume de inicialização de 250 GB. Para obter mais informações, consulte Usando a NVIDIA GPU Cloud com o Oracle Cloud Infrastructure.

  3. Quando a máquina estiver ativa, conecte-se a ela usando sua chave privada e o IP público da máquina.

    ssh -i <private_key> ubuntu@<public_ip>
    
  4. Certifique-se de que o volume de inicialização tenha maior espaço.

    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
    

Tarefa 2: Atualizar os Drivers NVIDIA (Opcional)

É recomendável atualizar os drivers para a versão mais recente com base nas orientações fornecidas pela NVIDIA com a matriz de compatibilidade entre os drivers e a versão do CUDA. Para obter mais informações, consulte Compatibilidade com o CUDA e Downloads de Atualização 1 do CUDA Toolkit 12.4.

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

Verifique se você tem nvidia-container-toolkit.

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

Execute o seguinte comando para verificar a nova versão.

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

Tarefa 3: Preparar o Registro de Modelo

É possível usar modelos pré-criados. No entanto, optamos por executar Llama2-7B-chat em uma GPU A10. No momento da gravação, essa opção não está disponível e, portanto, temos que criar o repositório de modelos nós mesmos.

  1. Crie um bucket chamado NIM no OCI Object Storage. Para obter mais informações, consulte Criando um Bucket de Armazenamento de Objetos.

  2. Vá para a janela do terminal, faça login no registro de contêiner NVIDIA com seu nome de usuário e senha e extraia o contêiner. Execute o seguinte comando.

    docker login nvcr.io
    docker pull nvcr.io/ohlfw0olaadg/ea-participants/nemollm-inference-ms:24.02.rc4
    
  3. Clone o modelo 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. Crie a configuração do modelo.

    Copie o arquivo model_config.yaml e crie o diretório para hospedar o armazenamento de modelos. É aqui que o comando do gerador do repositório do modelo armazenará a saída.

    mkdir model-store
    chmod -R 777 model-store
    
  5. Execute o comando do gerador de repositório de modelo.

    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. Exporte o repositório de modelos para um bucket do OCI Object Storage.

    O repositório de modelos está localizado no diretório model-store. Você pode usar a Interface de Linha de Comando (CLI do OCI) do Oracle Cloud Infrastructure para fazer um upload em massa para um de seus buckets na região. Para este tutorial, o bucket é NIM no qual queremos que o armazenamento de modelos seja submetido a upload em NIM/llama2-7b-hf (no caso de fazer upload de uma configuração de modelo diferente para o mesmo bucket).

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

Tarefa 4: Enviar uma Solicitação à Máquina Virtual (Execução IaaS)

Agora, o upload do repositório de modelos é feito em um bucket do OCI Object Storage.

Observação: No momento, o parâmetro de opção --model-repository está codificado no contêiner. Não podemos simplesmente apontar para o bucket quando o iniciamos. Uma opção será adaptar o script Python dentro do contêiner, mas precisaremos do privilégio sudo. A outra será montar o bucket como um sistema de arquivos na máquina diretamente. Para este tutorial, escolhemos o segundo método com rclone. Certifique-se de que fuse3 e jq estejam instalados na máquina. No Ubuntu, você pode executar sudo apt install fuse3 jq.

  1. Obtenha seu Namespace, OCID do Compartimento e Região, extraindo-os da Console do OCI ou executando os comandos a seguir na sua instância de computação.

    #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. Baixe e instale o rclone.

    curl https://rclone.org/install.sh | sudo bash
    
  3. Prepare o arquivo de configuração rclone. Certifique-se de atualizar ##NAMESPACE## ##COMPARTMENT_OCID## ##REGION## com seus valores.

    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. Monte o bucket usando 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. Em outra janela de terminal, você pode verificar se ls $HOME/test_directory/model_bucket_oci retorna o conteúdo do bucket.

  6. Em outra janela de terminal, inicie o contêiner passando o caminho para model-store como argumento.

    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. Após 3 minutos, o servidor de inferência deve estar pronto para servir. Em outra janela de terminal, você pode executar a solicitação a seguir.

    Observação: Se quiser executá-lo em sua máquina local, você precisará usar o IP público e abrir a porta 9999 no nível da máquina e da sub-rede.

    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"
    

Tarefa 5: Atualizar o Script cloud-init

Observação: Idealmente, uma maneira mais limpa de usar o rclone no Kubernetes seria usar o contêiner rclone como um sidecar antes de iniciar o servidor de inferência. Isso funciona bem localmente usando o Docker, mas como ele precisa da opção --device para usar fuse, isso torna complicado o uso com o Kubernetes devido à falta de suporte para esse recurso (volumes FUSE, uma solicitação de recurso de 2015 ainda muito ativa a partir de março de 2024). Para este tutorial, a solução alternativa que escolhemos é configurar o rclone como um serviço no host e montar o bucket na inicialização.

No script cloud-init, substitua o valor das linhas 17, 18 e 19 de ##NAMESPACE##, ##COMPARTMENT_OCID## e ##REGION## pelos valores recuperados na Tarefa 4.1. Você também pode atualizar o valor do bloco na linha 57. Por padrão, ele é chamado de NIM e tem um diretório chamado llama2-7b-hf.

Este script cloud-init será submetido a upload no nó da GPU do cluster do OKE. A primeira parte consiste em aumentar o volume de inicialização para o conjunto de valores. Em seguida, ele baixa o rclone, cria os diretórios corretos e cria o arquivo de configuração, da mesma forma que fizemos na VM da GPU. Por fim, ele inicia o rclone como um serviço e monta o bucket em /opt/mnt/model_bucket_oci.

Tarefa 6: Implantar no OKE

A arquitetura de destino no final da implantação é a mostrada na imagem a seguir.

Diagrama de Arquitetura

Agora, junte tudo no OKE.

Crie um cluster do OKE com pequenas adaptações. Para obter mais informações, consulte Usando a Console para criar um Cluster com Definições Padrão no workflow "Criação Rápida".

Tarefa 7: Implantar usando Helm no OCI Cloud Shell

Para acessar o OCI Cloud Shell, consulte Para acessar o Cloud Shell pela Console.

  1. Você pode encontrar a configuração do Helm no arquivo compactado oke.zip, no qual você precisa atualizar values.yaml. Faça upload do arquivo compactado no OCI Cloud Shell e descompacte-o. Para obter mais informações, consulte Para fazer upload de um arquivo para o Cloud Shell usando o menu.

    unzip oke.zip
    cd oke
    
  2. Verifique suas credenciais do segredo para extrair a imagem em values.yaml. Para obter mais informações, consulte Criando Segredos de Extração de Imagem.

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

Tarefa 8: Implantar o Monitoramento

O monitoramento consiste em pods Grafana e Prometheus. A configuração vem de kube-prometheus-stack.

Aqui, adicionamos um balanceador de carga público para acessar o painel do Grafana pela Internet. Use username=admin e password=xxxxxxxxx para fazer log-in. O flag serviceMonitorSelectorNilUsesHelmValues é necessário para que o Prometheus possa encontrar as métricas do servidor de inferência na release de exemplo implantada.

  1. Implante os pods de monitoramento.

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

Observação: O balanceador de carga padrão criado com uma forma fixa e uma largura de banda de 100Mbps. Você pode alternar para uma forma flexível e adaptar a largura de banda de acordo com seus limites da OCI, caso a largura de banda seja um gargalo. Para obter mais informações, consulte Provisionando Balanceadores de Carga do OCI para Serviços do Kubernetes do Tipo LoadBalancer.

  1. Um exemplo de painel de controle do Grafana está disponível em dashboard-review.json localizado em oke.zip. Use a função de importação no Grafana para importar e exibir este painel.

  2. Você pode ver o IP público do painel do Grafana executando o comando a seguir.

    $ 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
    

Tarefa 9: Implantar o Servidor de Inferência

  1. Execute o comando a seguir para implantar o servidor de inferência usando a configuração padrão.

    cd <directory containing Chart.yaml>
    helm install example . -f values.yaml --debug
    
  2. Use kubectl para ver o status e aguardar até que os pods do servidor de inferência estejam em execução. A primeira puxada pode levar alguns minutos. Depois que o contêiner é criado, o carregamento do modelo também leva alguns minutos. Você pode monitorar o pod com o comando a seguir.

    kubectl describe pods <POD_NAME>
    kubectl logs <POD_NAME>
    
  3. Quando a configuração estiver concluída, o contêiner deverá estar em execução.

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

Tarefa 10: Usar o servidor de inferência Triton no seu contêiner NIM NVIDIA

O servidor de inferência está em execução. Você pode enviar solicitações HTTP ou gRPC (Google Remote Procedure Call) para executar inferência. Por padrão, o serviço de inferência é exposto com um tipo de serviço LoadBalancer. Use o seguinte para localizar o IP externo para o servidor de inferência. Neste tutorial, é 34.83.9.133.

  1. Obtenha os serviços para obter o IP público do seu servidor de inferência.

    $ 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. O servidor de inferência expõe um ponto final HTTP na porta 8000 e um ponto final gRPC na porta 8001 e um ponto final de métricas Prometheus na porta 8002. Você pode usar curl para obter os metadados do servidor de inferência do ponto final HTTP.

    $ curl 34.83.9.133:8000/v2
    
  3. Na sua máquina cliente, você pode enviar uma solicitação ao IP público na 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"
    

    A saída deve ser semelhante a:

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

Tarefa 11: Limpar a Implantação

  1. Depois de terminar de usar o servidor de inferência, use o helm para excluir a implantação.

    $ 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. Para os serviços Prometheus e Grafana, você deve excluir explicitamente CRDs. Para obter mais informações, consulte Desinstalar Gráfico 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. Você também pode excluir o bucket do OCI Object Storage criado para conter o repositório de modelos.

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

Confirmação

Mais Recursos de Aprendizagem

Explore outros laboratórios em docs.oracle.com/learn ou acesse mais conteúdo de aprendizado gratuito no canal Oracle Learning YouTube. Além disso, visite education.oracle.com/learning-explorer para se tornar um Oracle Learning Explorer.

Para obter a documentação do produto, visite o Oracle Help Center.