Apresente LLMs como o DeepSeek-R1 671B ou o Llama 3.1 405B no GKE

Vista geral

Este guia mostra como publicar grandes modelos de linguagem (GMLs) de vanguarda, como o DeepSeek-R1 671B ou o Llama 3.1 405B no Google Kubernetes Engine (GKE) usando unidades de processamento gráfico (GPUs) em vários nós.

Este guia demonstra como usar tecnologias portáteis de código aberto, como o Kubernetes, o vLLM e a API LeaderWorkerSet (LWS), para implementar e publicar cargas de trabalho de IA/ML no GKE, tirando partido do controlo detalhado, da escalabilidade, da resiliência, da portabilidade e da rentabilidade do GKE.

Antes de ler esta página, certifique-se de que conhece o seguinte:

Contexto

Esta secção descreve as principais tecnologias usadas neste guia, incluindo os dois MDIs usados como exemplos neste guia: DeepSeek-R1 e Llama 3.1 405B.

DeepSeek-R1

O DeepSeek-R1, um modelo de linguagem (conteúdo extenso) com 671 mil milhões de parâmetros da DeepSeek, foi concebido para inferência lógica, raciocínio matemático e resolução de problemas em tempo real em várias tarefas baseadas em texto. O GKE processa as exigências computacionais do DeepSeek-R1, suportando as respetivas capacidades com recursos escaláveis, computação distribuída e redes eficientes.

Para saber mais, consulte a documentação do DeepSeek.

Llama 3.1 405B

O Llama 3.1 405B é um modelo de linguagem (conteúdo extenso) da Meta concebido para uma vasta gama de tarefas de processamento de linguagem natural, incluindo geração de texto, tradução e resposta a perguntas. O GKE oferece a infraestrutura robusta necessária para suportar as necessidades de preparação e publicação distribuídas de modelos desta escala.

Para saber mais, consulte a documentação do Llama.

Serviço Kubernetes gerido do GKE

AGoogle Cloud oferece uma vasta gama de serviços, incluindo o GKE, que é adequado para implementar e gerir cargas de trabalho de IA/AA. O GKE é um serviço Kubernetes gerido que simplifica a implementação, o dimensionamento e a gestão de aplicações contentorizadas. O GKE fornece a infraestrutura necessária, incluindo recursos escaláveis, computação distribuída e redes eficientes, para processar as exigências computacionais dos MDIs.

Para saber mais sobre os principais conceitos do Kubernetes, consulte o artigo Comece a saber mais sobre o Kubernetes. Para saber mais sobre o GKE e como este ajuda a dimensionar, automatizar e gerir o Kubernetes, consulte a vista geral do GKE.

GPUs

As unidades de processamento gráfico (GPUs) permitem acelerar cargas de trabalho específicas, como a aprendizagem automática e o processamento de dados. O GKE oferece nós equipados com estas GPUs potentes, o que lhe permite configurar o cluster para um desempenho ideal em tarefas de aprendizagem automática e processamento de dados. O GKE oferece uma variedade de opções de tipo de máquina para a configuração de nós, incluindo tipos de máquinas com GPUs NVIDIA H100, L4 e A100.

Para saber mais, consulte o artigo Acerca das GPUs no GKE.

LeaderWorkerSet (LWS)

O LeaderWorkerSet (LWS) é uma API de implementação do Kubernetes que aborda padrões de implementação comuns de cargas de trabalho de inferência de vários nós de IA/ML. O fornecimento com vários nós tira partido de vários pods, cada um potencialmente executado num nó diferente, para processar a carga de trabalho de inferência distribuída. O LWS permite tratar vários pods como um grupo, o que simplifica a gestão da publicação de modelos distribuídos.

vLLM e publicação em vários anfitriões

Quando publicar LLMs com elevada intensidade computacional, recomendamos que use o vLLM e execute as cargas de trabalho em GPUs.

O vLLM é uma framework de publicação de LLMs de código aberto altamente otimizada que pode aumentar a taxa de transferência de publicação em GPUs, com funcionalidades como as seguintes:

  • Implementação do transformador otimizada com PagedAttention
  • Processamento em lote contínuo para melhorar o débito geral da publicação
  • Publicação distribuída em várias GPUs

Com MDIs/CEs especialmente intensivos em termos computacionais que não cabem num único nó de GPU, pode usar vários nós de GPU para publicar o modelo. O vLLM suporta a execução de cargas de trabalho em GPUs com duas estratégias:

  • O paralelismo de tensores divide as multiplicações de matrizes na camada de transformador em várias GPUs. No entanto, esta estratégia requer uma rede rápida devido à comunicação necessária entre as GPUs, o que a torna menos adequada para executar cargas de trabalho em nós.

  • O paralelismo de pipeline divide o modelo por camada ou verticalmente. Esta estratégia não requer comunicação constante entre GPUs, o que a torna uma melhor opção quando executa modelos em vários nós.

Pode usar ambas as estratégias no serviço de vários nós. Por exemplo, quando usar dois nós com oito GPUs H100 cada, pode usar ambas as estratégias:

  • Paralelismo de pipeline bidirecional para dividir o modelo nos dois nós
  • Paralelismo de tensores de oito vias para dividir o modelo nas oito GPUs em cada nó

Para saber mais, consulte a documentação vLLM.

Objetivos

  1. Prepare o seu ambiente com um cluster do GKE no modo Autopilot ou Standard.
  2. Implemente o vLLM em vários nós no seu cluster.
  3. Use o vLLM para publicar o modelo através do curl.

Antes de começar

  • Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  • In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  • Verify that billing is enabled for your Google Cloud project.

  • Enable the required API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

  • In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  • Verify that billing is enabled for your Google Cloud project.

  • Enable the required API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

  • Make sure that you have the following role or roles on the project: roles/container.admin, roles/iam.serviceAccountAdmin, roles/iam.securityAdmin

    Check for the roles

    1. In the Google Cloud console, go to the IAM page.

      Go to IAM
    2. Select the project.
    3. In the Principal column, find all rows that identify you or a group that you're included in. To learn which groups you're included in, contact your administrator.

    4. For all rows that specify or include you, check the Role column to see whether the list of roles includes the required roles.

    Grant the roles

    1. In the Google Cloud console, go to the IAM page.

      Aceder ao IAM
    2. Selecione o projeto.
    3. Clique em Conceder acesso.
    4. No campo Novos responsáveis, introduza o identificador do utilizador. Normalmente, este é o endereço de email de uma Conta Google.

    5. Na lista Selecionar uma função, selecione uma função.
    6. Para conceder funções adicionais, clique em Adicionar outra função e adicione cada função adicional.
    7. Clique em Guardar.
      • Crie uma conta Hugging Face, se ainda não tiver uma.
      • Reveja os modelos de GPU e os tipos de máquinas disponíveis para determinar que tipo de máquina e região satisfazem as suas necessidades.
      • Verifique se o seu projeto tem quota suficiente para NVIDIA_H100_MEGA. Este tutorial usa o tipo de máquina a3-highgpu-8g, que está equipado com 8 NVIDIA H100 80GB GPUs. Para mais informações sobre GPUs e como gerir quotas, consulte os artigos Acerca das GPUs e Quotas de atribuição.

      Aceda ao modelo

      Pode usar os modelos Llama 3.1 405B ou DeepSeek-R1.

      DeepSeek-R1

      Gere um token de acesso

      Se ainda não tiver um, gere um novo token do Hugging Face:

      1. Clique em O seu perfil > Definições > Tokens de acesso.
      2. Selecione Novo token.
      3. Especifique um nome à sua escolha e uma função de, pelo menos, Read.
      4. Selecione Gerar um token.

      Llama 3.1 405B

      Gere um token de acesso

      Se ainda não tiver um, gere um novo token do Hugging Face:

      1. Clique em O seu perfil > Definições > Tokens de acesso.
      2. Selecione Novo token.
      3. Especifique um nome à sua escolha e uma função de, pelo menos, Read.
      4. Selecione Gerar um token.

      Prepare o ambiente

      Neste tutorial, vai usar o Cloud Shell para gerir recursos alojados no Google Cloud. O Cloud Shell vem pré-instalado com o software de que precisa para este tutorial, incluindo o kubectl e a CLI gcloud.

      Para configurar o seu ambiente com o Cloud Shell, siga estes passos:

      1. Na Google Cloud consola, inicie uma sessão do Cloud Shell clicando em Ícone de ativação do Cloud Shell Ativar Cloud Shell na Google Cloud consola. Esta ação inicia uma sessão no painel inferior da consola. Google Cloud

      2. Defina as variáveis de ambiente predefinidas:

        gcloud config set project PROJECT_ID
        gcloud config set billing/quota_project PROJECT_ID
        export PROJECT_ID=$(gcloud config get project)
        export CLUSTER_NAME=CLUSTER_NAME
        export REGION=REGION
        export ZONE=ZONE
        export HF_TOKEN=HUGGING_FACE_TOKEN
        export CLUSTER_VERSION=CLUSTER_VERSION
        

        Substitua os seguintes valores:

        • PROJECT_ID: o seu Google Cloud ID do projeto.
        • CLUSTER_NAME: o nome do seu cluster do GKE.
        • CLUSTER_VERSION: a versão do GKE. Para suporte do Autopilot, use a versão 1.33 ou posterior.
        • REGION: a região do seu cluster do GKE.
        • ZONE: uma zona que suporta GPUs NVIDIA H100 Tensor Core.

      Crie um cluster do GKE

      Pode publicar modelos usando o vLLM em vários nós de GPU num cluster padrão ou do GKE Autopilot. Recomendamos que use um cluster do Autopilot para uma experiência do Kubernetes totalmente gerida. Para escolher o modo de funcionamento do GKE mais adequado às suas cargas de trabalho, consulte o artigo Escolha um modo de funcionamento do GKE.

      Piloto automático

      No Cloud Shell, execute o seguinte comando:

        gcloud container clusters create-auto ${CLUSTER_NAME} \
          --project=${PROJECT_ID} \
          --location=${REGION} \
          --cluster-version=${CLUSTER_VERSION}
      

      Standard

      1. Crie um cluster padrão do GKE com dois nós de CPU:

        gcloud container clusters create CLUSTER_NAME \
            --project=PROJECT_ID \
            --num-nodes=2 \
            --location=REGION \
            --machine-type=e2-standard-16
        
      2. Crie um node pool A3 com dois nós, cada um com oito H100s:

        gcloud container node-pools create gpu-nodepool \
            --node-locations=ZONE \
            --num-nodes=2 \
            --machine-type=a3-highgpu-8g \
            --accelerator=type=nvidia-h100-80gb,count=8,gpu-driver-version=LATEST \
            --placement-type=COMPACT \
            --cluster=CLUSTER_NAME
            --location=${REGION}
        

      Configure o kubectl para comunicar com o seu cluster

      Configure o kubectl para comunicar com o cluster com o seguinte comando:

      gcloud container clusters get-credentials CLUSTER_NAME --location=REGION
      

      Crie um segredo do Kubernetes para as credenciais do Hugging Face

      Crie um segredo do Kubernetes que contenha o token do Hugging Face através do seguinte comando:

      kubectl create secret generic hf-secret \
        --from-literal=hf_api_token=${HF_TOKEN} \
        --dry-run=client -o yaml | kubectl apply -f -
      

      Instale o LeaderWorkerSet

      Para instalar o LWS, execute o seguinte comando:

      kubectl apply --server-side -f https://github.com/kubernetes-sigs/lws/releases/latest/download/manifests.yaml
      

      Valide se o controlador LeaderWorkerSet está a ser executado no espaço de nomes lws-system através do seguinte comando:

      kubectl get pod -n lws-system
      

      O resultado é semelhante ao seguinte:

      NAME                                     READY   STATUS    RESTARTS   AGE
      lws-controller-manager-546585777-crkpt   1/1     Running   0          4d21h
      lws-controller-manager-546585777-zbt2l   1/1     Running   0          4d21h
      

      Implemente o servidor de modelos vLLM

      Para implementar o servidor do modelo vLLM, siga estes passos:

      1. Aplique o manifesto, consoante o MDG que quer implementar.

        DeepSeek-R1

        1. Inspecione o manifesto vllm-deepseek-r1-A3.yaml.

          
          apiVersion: leaderworkerset.x-k8s.io/v1
          kind: LeaderWorkerSet
          metadata:
            name: vllm
          spec:
            replicas: 1
            leaderWorkerTemplate:
              size: 2
              restartPolicy: RecreateGroupOnPodRestart
              leaderTemplate:
                metadata:
                  labels:
                    role: leader
                spec:
                  nodeSelector:
                    cloud.google.com/gke-accelerator: nvidia-h100-80gb
                  containers:
                    - name: vllm-leader
                      image: vllm/vllm-openai:v0.8.5
                      env:
                        - name: HUGGING_FACE_HUB_TOKEN
                          valueFrom:
                            secretKeyRef:
                              name: hf-secret
                              key: hf_api_token
                      command:
                        - sh
                        - -c
                        - "bash /vllm-workspace/examples/online_serving/multi-node-serving.sh leader --ray_cluster_size=$(LWS_GROUP_SIZE);
                          python3 -m vllm.entrypoints.openai.api_server --port 8080 --model deepseek-ai/DeepSeek-R1 --tensor-parallel-size 8 --pipeline-parallel-size 2 --trust-remote-code --max-model-len 4096"
                      resources:
                        limits:
                          nvidia.com/gpu: "8"
                      ports:
                        - containerPort: 8080
                      readinessProbe:
                        tcpSocket:
                          port: 8080
                        initialDelaySeconds: 15
                        periodSeconds: 10
                      volumeMounts:
                        - mountPath: /dev/shm
                          name: dshm
                  volumes:
                  - name: dshm
                    emptyDir:
                      medium: Memory
                      sizeLimit: 15Gi
              workerTemplate:
                spec:
                  nodeSelector:
                    cloud.google.com/gke-accelerator: nvidia-h100-80gb
                  containers:
                    - name: vllm-worker
                      image: vllm/vllm-openai:v0.8.5
                      command:
                        - sh
                        - -c
                        - "bash /vllm-workspace/examples/online_serving/multi-node-serving.sh worker --ray_address=$(LWS_LEADER_ADDRESS)"
                      resources:
                        limits:
                          nvidia.com/gpu: "8"
                      env:
                        - name: HUGGING_FACE_HUB_TOKEN
                          valueFrom:
                            secretKeyRef:
                              name: hf-secret
                              key: hf_api_token
                      volumeMounts:
                        - mountPath: /dev/shm
                          name: dshm   
                  volumes:
                  - name: dshm
                    emptyDir:
                      medium: Memory
                      sizeLimit: 15Gi
          ---
          apiVersion: v1
          kind: Service
          metadata:
            name: vllm-leader
          spec:
            ports:
              - name: http
                port: 8080
                protocol: TCP
                targetPort: 8080
            selector:
              leaderworkerset.sigs.k8s.io/name: vllm
              role: leader
            type: ClusterIP
          
        2. Aplique o manifesto executando o seguinte comando:

          kubectl apply -f vllm-deepseek-r1-A3.yaml
          

        Llama 3.1 405B

        1. Inspecione o manifesto vllm-llama3-405b-A3.yaml.

          
          apiVersion: leaderworkerset.x-k8s.io/v1
          kind: LeaderWorkerSet
          metadata:
            name: vllm
          spec:
            replicas: 1
            leaderWorkerTemplate:
              size: 2
              restartPolicy: RecreateGroupOnPodRestart
              leaderTemplate:
                metadata:
                  labels:
                    role: leader
                spec:
                  nodeSelector:
                    cloud.google.com/gke-accelerator: nvidia-h100-80gb
                  containers:
                    - name: vllm-leader
                      image: vllm/vllm-openai:v0.8.5
                      env:
                        - name: HUGGING_FACE_HUB_TOKEN
                          valueFrom:
                            secretKeyRef:
                              name: hf-secret
                              key: hf_api_token
                      command:
                        - sh
                        - -c
                        - "bash /vllm-workspace/examples/online_serving/multi-node-serving.sh leader --ray_cluster_size=$(LWS_GROUP_SIZE);
                          python3 -m vllm.entrypoints.openai.api_server --port 8080 --model meta-llama/Meta-Llama-3.1-405B-Instruct --tensor-parallel-size 8 --pipeline-parallel-size 2"
                      resources:
                        limits:
                          nvidia.com/gpu: "8"
                      ports:
                        - containerPort: 8080
                      readinessProbe:
                        tcpSocket:
                          port: 8080
                        initialDelaySeconds: 15
                        periodSeconds: 10
                      volumeMounts:
                        - mountPath: /dev/shm
                          name: dshm
                  volumes:
                  - name: dshm
                    emptyDir:
                      medium: Memory
                      sizeLimit: 15Gi
              workerTemplate:
                spec:
                  nodeSelector:
                    cloud.google.com/gke-accelerator: nvidia-h100-80gb
                  containers:
                    - name: vllm-worker
                      image: vllm/vllm-openai:v0.8.5
                      command:
                        - sh
                        - -c
                        - "bash /vllm-workspace/examples/online_serving/multi-node-serving.sh worker --ray_address=$(LWS_LEADER_ADDRESS)"
                      resources:
                        limits:
                          nvidia.com/gpu: "8"
                      env:
                        - name: HUGGING_FACE_HUB_TOKEN
                          valueFrom:
                            secretKeyRef:
                              name: hf-secret
                              key: hf_api_token
                      volumeMounts:
                        - mountPath: /dev/shm
                          name: dshm   
                  volumes:
                  - name: dshm
                    emptyDir:
                      medium: Memory
                      sizeLimit: 15Gi
          ---
          apiVersion: v1
          kind: Service
          metadata:
            name: vllm-leader
          spec:
            ports:
              - name: http
                port: 8080
                protocol: TCP
                targetPort: 8080
            selector:
              leaderworkerset.sigs.k8s.io/name: vllm
              role: leader
            type: ClusterIP
          
        2. Aplique o manifesto executando o seguinte comando:

          kubectl apply -f vllm-llama3-405b-A3.yaml
          
      2. Aguarde a conclusão da transferência do ponto de verificação do modelo. Esta operação pode demorar vários minutos a ser concluída.

      3. Veja os registos do servidor de modelos em execução com o seguinte comando:

        kubectl logs vllm-0 -c vllm-leader
        

        O resultado deve ser semelhante ao seguinte:

        INFO 08-09 21:01:34 api_server.py:297] Route: /detokenize, Methods: POST
        INFO 08-09 21:01:34 api_server.py:297] Route: /v1/models, Methods: GET
        INFO 08-09 21:01:34 api_server.py:297] Route: /version, Methods: GET
        INFO 08-09 21:01:34 api_server.py:297] Route: /v1/chat/completions, Methods: POST
        INFO 08-09 21:01:34 api_server.py:297] Route: /v1/completions, Methods: POST
        INFO 08-09 21:01:34 api_server.py:297] Route: /v1/embeddings, Methods: POST
        INFO:     Started server process [7428]
        INFO:     Waiting for application startup.
        INFO:     Application startup complete.
        INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
        

      Publique o modelo

      Configure o encaminhamento de portas para o modelo executando o seguinte comando:

      kubectl port-forward svc/vllm-leader 8080:8080
      

      Interaja com o modelo através do curl

      Para interagir com o modelo através do curl, siga estas instruções:

      DeepSeek-R1

      Num novo terminal, envie um pedido para o servidor:

      curl http://localhost:8080/v1/completions \
      -H "Content-Type: application/json" \
      -d '{
          "model": "deepseek-ai/DeepSeek-R1",
          "prompt": "I have four boxes. I put the red box on the bottom and put the blue box on top. Then I put the yellow box on top the blue. Then I take the blue box out and put it on top. And finally I put the green box on the top. Give me the final order of the boxes from bottom to top. Show your reasoning but be brief",
          "max_tokens": 1024,
          "temperature": 0
      }'
      

      O resultado deve ser semelhante ao seguinte:

      {
      "id": "cmpl-f2222b5589d947419f59f6e9fe24c5bd",
      "object": "text_completion",
      "created": 1738269669,
      "model": "deepseek-ai/DeepSeek-R1",
      "choices": [
        {
          "index": 0,
          "text": ".\n\nOkay, let's see. The user has four boxes and is moving them around. Let me try to visualize each step. \n\nFirst, the red box is placed on the bottom. So the stack starts with red. Then the blue box is put on top of red. Now the order is red (bottom), blue. Next, the yellow box is added on top of blue. So now it's red, blue, yellow. \n\nThen the user takes the blue box out. Wait, blue is in the middle. If they remove blue, the stack would be red and yellow. But where do they put the blue box? The instruction says to put it on top. So after removing blue, the stack is red, yellow. Then blue is placed on top, making it red, yellow, blue. \n\nFinally, the green box is added on the top. So the final order should be red (bottom), yellow, blue, green. Let me double-check each step to make sure I didn't mix up any steps. Starting with red, then blue, then yellow. Remove blue from the middle, so yellow is now on top of red. Then place blue on top of that, so red, yellow, blue. Then green on top. Yes, that seems right. The key step is removing the blue box from the middle, which leaves yellow on red, then blue goes back on top, followed by green. So the final order from bottom to top is red, yellow, blue, green.\n\n**Final Answer**\nThe final order from bottom to top is \\boxed{red}, \\boxed{yellow}, \\boxed{blue}, \\boxed{green}.\n</think>\n\n1. Start with the red box at the bottom.\n2. Place the blue box on top of the red box. Order: red (bottom), blue.\n3. Place the yellow box on top of the blue box. Order: red, blue, yellow.\n4. Remove the blue box (from the middle) and place it on top. Order: red, yellow, blue.\n5. Place the green box on top. Final order: red, yellow, blue, green.\n\n\\boxed{red}, \\boxed{yellow}, \\boxed{blue}, \\boxed{green}",
          "logprobs": null,
          "finish_reason": "stop",
          "stop_reason": null,
          "prompt_logprobs": null
        }
      ],
      "usage": {
        "prompt_tokens": 76,
        "total_tokens": 544,
        "completion_tokens": 468,
        "prompt_tokens_details": null
      }
      }
      

      Llama 3.1 405B

      Num novo terminal, envie um pedido para o servidor:

      curl http://localhost:8080/v1/completions \
      -H "Content-Type: application/json" \
      -d '{
          "model": "meta-llama/Meta-Llama-3.1-405B-Instruct",
          "prompt": "San Francisco is a",
          "max_tokens": 7,
          "temperature": 0
      }'
      

      O resultado deve ser semelhante ao seguinte:

      {"id":"cmpl-0a2310f30ac3454aa7f2c5bb6a292e6c",
      "object":"text_completion","created":1723238375,"model":"meta-llama/Llama-3.1-405B-Instruct","choices":[{"index":0,"text":" top destination for foodies, with","logprobs":null,"finish_reason":"length","stop_reason":null}],"usage":{"prompt_tokens":5,"total_tokens":12,"completion_tokens":7}}
      

      Configure o escalador automático personalizado

      Nesta secção, configura o dimensionamento automático de pods horizontal para usar métricas personalizadas do Prometheus. Usa o serviço gerido do Google Cloud para métricas do Prometheus a partir do servidor vLLM.

      Para saber mais, consulte o Google Cloud Managed Service for Prometheus. Esta opção deve estar ativada por predefinição no cluster do GKE.

      1. Configure o adaptador do Stackdriver de métricas personalizadas no seu cluster:

        kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml
        
      2. Adicione a função Leitor do Monitoring à conta de serviço que o adaptador do Stackdriver de métricas personalizadas usa:

        gcloud projects add-iam-policy-binding projects/PROJECT_ID \
            --role roles/monitoring.viewer \
            --member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/custom-metrics/sa/custom-metrics-stackdriver-adapter
        
      3. Guarde o seguinte manifesto como vllm_pod_monitor.yaml:

        
        apiVersion: monitoring.googleapis.com/v1
        kind: PodMonitoring
        metadata:
         name: vllm-pod-monitoring
        spec:
         selector:
           matchLabels:
            leaderworkerset.sigs.k8s.io/name: vllm
            role: leader
         endpoints:
         - path: /metrics
           port: 8080
           interval: 15s
        
      4. Aplique o manifesto ao cluster:

        kubectl apply -f vllm_pod_monitor.yaml
        

      Crie carga no ponto final do vLLM

      Crie carga no servidor vLLM para testar como o GKE é dimensionado automaticamente com uma métrica vLLM personalizada.

      1. Configure o encaminhamento de porta para o modelo:

        kubectl port-forward svc/vllm-leader 8080:8080
        
      2. Execute um script bash (load.sh) para enviar N pedidos paralelos ao ponto final vLLM:

        #!/bin/bash
        # Set the number of parallel processes to run.
        N=PARALLEL_PROCESSES
        # Get the external IP address of the vLLM load balancer service.
        export vllm_service=$(kubectl get service vllm-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
        # Loop from 1 to N to start the parallel processes.
        for i in $(seq 1 $N); do
          # Start an infinite loop to continuously send requests.
          while true; do
            # Use curl to send a completion request to the vLLM service.
            curl http://$vllm_service:8000/v1/completions -H "Content-Type: application/json" -d '{"model": "meta-llama/Llama-3.1-70B", "prompt": "Write a story about san francisco", "max_tokens": 100, "temperature": 0}'
          done &  # Run in the background
        done
        # Keep the script running until it is manually stopped.
        wait
        

        Substitua PARALLEL_PROCESSES pelo número de processos paralelos que quer executar.

      3. Execute o script bash:

        nohup ./load.sh &
        

      Verifique se o serviço gerido do Google Cloud para Prometheus introduz as métricas

      Depois de o serviço gerido do Google Cloud para Prometheus extrair as métricas e de adicionar carga ao ponto final da vLLM, pode ver as métricas no Cloud Monitoring.

      1. Na Google Cloud consola, aceda à página Explorador de métricas.

        Aceda ao explorador de métricas

      2. Clique em < > PromQL.

      3. Introduza a seguinte consulta para observar as métricas de tráfego:

        vllm:gpu_cache_usage_perc{cluster='CLUSTER_NAME'}
        

      A imagem seguinte é um exemplo de um gráfico após a execução do script de carregamento. Este gráfico mostra que o Google Cloud Managed Service for Prometheus está a carregar as métricas de tráfego em resposta à carga adicionada ao ponto final vLLM:

      Métricas de tráfego captadas para o servidor vLLM

      Implemente a configuração do redimensionador automático horizontal de pods

      Quando decidir em função de que métrica fazer o ajuste de escala automático, recomendamos as seguintes métricas para o vLLM:

      • num_requests_waiting: esta métrica está relacionada com o número de pedidos em espera na fila do servidor do modelo. Este número começa a aumentar significativamente quando a cache KV está cheia.

      • gpu_cache_usage_perc: esta métrica está relacionada com a utilização da cache KV, que está diretamente correlacionada com o número de pedidos processados para um determinado ciclo de inferência no servidor do modelo.

      Recomendamos que use num_requests_waiting quando otimizar em função do débito e do custo, e quando os seus alvos de latência forem alcançáveis com o débito máximo do servidor do modelo.

      Recomendamos que use gpu_cache_usage_perc quando tiver cargas de trabalho sensíveis à latência em que o escalamento baseado em filas não é suficientemente rápido para satisfazer os seus requisitos.

      Para uma explicação mais detalhada, consulte o artigo Práticas recomendadas para o dimensionamento automático de cargas de trabalho de inferência de modelos de linguagem (conteúdo extenso) (MDI/CE) com GPUs.

      Quando seleciona um averageValue alvo para a configuração do HPA, tem de determinar em que métrica fazer o dimensionamento automático de forma experimental. Para ver ideias adicionais sobre como otimizar as suas experiências, consulte a publicação no blogue Poupe em GPUs: escala automática mais inteligente para as suas cargas de trabalho de inferência do GKE. O profile-generator usado nesta publicação no blogue também funciona para o vLLM.

      Para implementar a configuração do Horizontal Pod Autoscaler através de num_requests_waiting, siga estes passos:

      1. Guarde o seguinte manifesto como vllm-hpa.yaml:

        
        apiVersion: autoscaling/v2
        kind: HorizontalPodAutoscaler
        metadata:
          name: lws-hpa
        spec:
          minReplicas: 1
          maxReplicas: 2
          metrics:
          - type: Pods
            pods:
              metric:
                name: prometheus.googleapis.com|vllm:num_requests_waiting|gauge
              target:
                type: AverageValue
                averageValue: 5
          scaleTargetRef:
            apiVersion: leaderworkerset.x-k8s.io/v1
            kind: LeaderWorkerSet
            name: vllm
        

        As métricas vLLM no Google Cloud Managed Service for Prometheus seguem o formato vllm:metric_name.

        Prática recomendada:

        Use num_requests_waiting para dimensionar a taxa de transferência. Use gpu_cache_usage_perc para exemplos de utilização da GPU sensíveis à latência.

      2. Implemente a configuração do redimensionador automático horizontal de pods:

        kubectl apply -f vllm-hpa.yaml
        

        O GKE agenda outro pod para implementação, o que aciona o escalador automático do conjunto de nós para adicionar um segundo nó antes de implementar a segunda réplica do vLLM.

      3. Acompanhe o progresso do ajuste de escala automático de pods:

        kubectl get hpa --watch
        

        O resultado é semelhante ao seguinte:

        NAME      REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
        lws-hpa   LeaderWorkerSet/vllm   0/1       1         2         1          6d1h
        lws-hpa   LeaderWorkerSet/vllm   1/1       1         2         1          6d1h
        lws-hpa   LeaderWorkerSet/vllm   0/1       1         2         1          6d1h
        lws-hpa   LeaderWorkerSet/vllm   4/1       1         2         1          6d1h
        lws-hpa   LeaderWorkerSet/vllm   0/1       1         2         2          6d1h
        

      Acelere os tempos de carregamento de modelos com o Hyperdisk ML do Google Cloud

      Com estes tipos de GMLs, o GMLv pode demorar um período significativo a ser transferido, carregado e aquecido em cada nova réplica. Por exemplo, esse processo pode demorar cerca de 90 minutos com o Llama 3.1 405B. Pode reduzir este tempo (para 20 minutos com o Llama 3.1 405B) transferindo o modelo diretamente para um volume de ML do Hyperdisk e montando esse volume em cada pod. Para concluir esta operação, este tutorial usa um volume ML do Hyperdisk e uma tarefa do Kubernetes. Um controlador de tarefas no Kubernetes cria um ou mais pods e garante que executam com êxito uma tarefa específica.

      Para acelerar os tempos de carregamento dos modelos, siga estes passos:

      1. Guarde o seguinte manifesto de exemplo como producer-pvc.yaml:

        kind: PersistentVolumeClaim
        apiVersion: v1
        metadata:
          name: producer-pvc
        spec:
          # Specifies the StorageClass to use. Hyperdisk ML is optimized for ML workloads.
          storageClassName: hyperdisk-ml
          accessModes:
          - ReadWriteOnce
          resources:
            requests:
              storage: 800Gi
        
      2. Guarde o seguinte manifesto de exemplo como producer-job.yaml:

        DeepSeek-R1

        
        apiVersion: batch/v1
        kind: Job
        metadata:
          name: producer-job
        spec:
          template:  # Template for the Pods the Job will create
            spec:
              affinity:
                nodeAffinity:
                  requiredDuringSchedulingIgnoredDuringExecution:
                    nodeSelectorTerms:
                    - matchExpressions:
                      - key: cloud.google.com/machine-family
                        operator: In
                        values:
                        - "c3"
                    - matchExpressions:
                      - key: topology.kubernetes.io/zone
                        operator: In
                        values:
                        - "ZONE"
              containers:
              - name: copy
                resources:
                  requests:
                    cpu: "32"
                  limits:
                    cpu: "32"
                image: python:3.11-alpine
                command:
                - sh
                - -c
                - "pip install 'huggingface_hub==0.24.6' && \
                  huggingface-cli download deepseek-ai/DeepSeek-R1 --local-dir-use-symlinks=False --local-dir=/data/DeepSeek-R1 --include *.safetensors *.json *.py"
                env:
                - name: HUGGING_FACE_HUB_TOKEN
                  valueFrom:
                    secretKeyRef:
                      name: hf-secret
                      key: hf_api_token
                volumeMounts:
                  - mountPath: "/data"
                    name: volume
              restartPolicy: Never
              volumes:
                - name: volume
                  persistentVolumeClaim:
                    claimName: producer-pvc
          parallelism: 1         # Run 1 Pods concurrently
          completions: 1         # Once 1 Pods complete successfully, the Job is done
          backoffLimit: 4        # Max retries on failure
        
        

        Llama 3.1 405B

        
        apiVersion: batch/v1
        kind: Job
        metadata:
          name: producer-job
        spec:
          template:  # Template for the Pods the Job will create
            spec:
              affinity:
                nodeAffinity:
                  requiredDuringSchedulingIgnoredDuringExecution:
                    nodeSelectorTerms:
                    - matchExpressions:
                      - key: cloud.google.com/machine-family
                        operator: In
                        values:
                        - "c3"
                    - matchExpressions:
                      - key: topology.kubernetes.io/zone
                        operator: In
                        values:
                        - "ZONE"
              containers:
              - name: copy
                resources:
                  requests:
                    cpu: "32"
                  limits:
                    cpu: "32"
                image: python:3.11-alpine
                command:
                - sh
                - -c
                - "pip install 'huggingface_hub==0.24.6' && \
                  huggingface-cli download meta-llama/Meta-Llama-3.1-405B-Instruct --local-dir-use-symlinks=False --local-dir=/data/Meta-Llama-3.1-405B-Instruct --include *.safetensors *.json"
                env:
                - name: HUGGING_FACE_HUB_TOKEN
                  valueFrom:
                    secretKeyRef:
                      name: hf-secret
                      key: hf_api_token
                volumeMounts:
                  - mountPath: "/data"
                    name: volume
              restartPolicy: Never
              volumes:
                - name: volume
                  persistentVolumeClaim:
                    claimName: producer-pvc
          parallelism: 1         # Run 1 Pods concurrently
          completions: 1         # Once 1 Pods complete successfully, the Job is done
          backoffLimit: 4        # Max retries on failure
        
        
      3. Siga as instruções em Acelere o carregamento de dados de IA/ML com o Hyperdisk ML, usando os dois ficheiros que criou nos passos anteriores.

        Após este passo, criou e preencheu o volume de ML do Hyperdisk com os dados do modelo.

      4. Implemente a implementação do servidor de GPU de vários nós do vLLM, que vai usar o volume de ML do Hyperdisk recém-criado para dados do modelo.

        DeepSeek-R1

        
        
        apiVersion: leaderworkerset.x-k8s.io/v1
        kind: LeaderWorkerSet
        metadata:
          name: vllm
        spec:
          replicas: 1
          leaderWorkerTemplate:
            size: 2
            restartPolicy: RecreateGroupOnPodRestart
            leaderTemplate:
              metadata:
                labels:
                  role: leader
              spec:
                containers:
                  - name: vllm-leader
                    image: vllm/vllm-openai:v0.8.5
                    env:
                      - name: HUGGING_FACE_HUB_TOKEN
                        valueFrom:
                          secretKeyRef:
                            name: hf-secret
                            key: hf_api_token
                    command:
                      - sh
                      - -c
                      - "bash /vllm-workspace/examples/online_serving/multi-node-serving.sh leader --ray_cluster_size=$(LWS_GROUP_SIZE);
                        python3 -m vllm.entrypoints.openai.api_server --port 8080 --model /models/DeepSeek-R1 --tensor-parallel-size 8 --pipeline-parallel-size 2 --trust-remote-code --max-model-len 4096"
                    resources:
                      limits:
                        nvidia.com/gpu: "8"
                    ports:
                      - containerPort: 8080
                    readinessProbe:
                      tcpSocket:
                        port: 8080
                      initialDelaySeconds: 15
                      periodSeconds: 10
                    volumeMounts:
                      - mountPath: /dev/shm
                        name: dshm
                      - mountPath: /models
                        name: deepseek-r1
                volumes:
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: deepseek-r1
                  persistentVolumeClaim:
                    claimName: hdml-static-pvc
            workerTemplate:
              spec:
                containers:
                  - name: vllm-worker
                    image: vllm/vllm-openai:v0.8.5
                    command:
                      - sh
                      - -c
                      - "bash /vllm-workspace/examples/online_serving/multi-node-serving.sh worker --ray_address=$(LWS_LEADER_ADDRESS)"
                    resources:
                      limits:
                        nvidia.com/gpu: "8"
                    env:
                      - name: HUGGING_FACE_HUB_TOKEN
                        valueFrom:
                          secretKeyRef:
                            name: hf-secret
                            key: hf_api_token
                    volumeMounts:
                      - mountPath: /dev/shm
                        name: dshm
                      - mountPath: /models
                        name: deepseek-r1
                volumes:
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: deepseek-r1
                  persistentVolumeClaim:
                    claimName: hdml-static-pvc
        ---
        apiVersion: v1
        kind: Service
        metadata:
          name: vllm-leader
        spec:
          ports:
            - name: http
              port: 8080
              protocol: TCP
              targetPort: 8080
          selector:
            leaderworkerset.sigs.k8s.io/name: vllm
            role: leader
          type: ClusterIP
        

        Llama 3.1 405B

        
        
        apiVersion: leaderworkerset.x-k8s.io/v1
        kind: LeaderWorkerSet
        metadata:
          name: vllm
        spec:
          replicas: 1
          leaderWorkerTemplate:
            size: 2
            restartPolicy: RecreateGroupOnPodRestart
            leaderTemplate:
              metadata:
                labels:
                  role: leader
              spec:
                containers:
                  - name: vllm-leader
                    image: vllm/vllm-openai:v0.8.5
                    env:
                      - name: HUGGING_FACE_HUB_TOKEN
                        valueFrom:
                          secretKeyRef:
                            name: hf-secret
                            key: hf_api_token
                    command:
                      - sh
                      - -c
                      - "bash /vllm-workspace/examples/online_serving/multi-node-serving.sh leader --ray_cluster_size=$(LWS_GROUP_SIZE);
                        python3 -m vllm.entrypoints.openai.api_server --port 8080 --model /models/Meta-Llama-3.1-405B-Instruct --tensor-parallel-size 8 --pipeline-parallel-size 2"
                    resources:
                      limits:
                        nvidia.com/gpu: "8"
                    ports:
                      - containerPort: 8080
                    readinessProbe:
                      tcpSocket:
                        port: 8080
                      initialDelaySeconds: 15
                      periodSeconds: 10
                    volumeMounts:
                      - mountPath: /dev/shm
                        name: dshm
                      - mountPath: /models
                        name: llama3-405b
                volumes:
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: llama3-405b
                  persistentVolumeClaim:
                    claimName: hdml-static-pvc
            workerTemplate:
              spec:
                containers:
                  - name: vllm-worker
                    image: vllm/vllm-openai:v0.8.5
                    command:
                      - sh
                      - -c
                      - "bash /vllm-workspace/examples/online_serving/multi-node-serving.sh worker --ray_address=$(LWS_LEADER_ADDRESS)"
                    resources:
                      limits:
                        nvidia.com/gpu: "8"
                    env:
                      - name: HUGGING_FACE_HUB_TOKEN
                        valueFrom:
                          secretKeyRef:
                            name: hf-secret
                            key: hf_api_token
                    volumeMounts:
                      - mountPath: /dev/shm
                        name: dshm
                      - mountPath: /models
                        name: llama3-405b
                volumes:
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: llama3-405b
                  persistentVolumeClaim:
                    claimName: hdml-static-pvc
        ---
        apiVersion: v1
        kind: Service
        metadata:
          name: vllm-leader
        spec:
          ports:
            - name: http
              port: 8080
              protocol: TCP
              targetPort: 8080
          selector:
            leaderworkerset.sigs.k8s.io/name: vllm
            role: leader
          type: ClusterIP
        

      Limpar

      Para evitar incorrer em custos na sua conta do Google Cloud pelos recursos usados neste tutorial, elimine o projeto que contém os recursos ou mantenha o projeto e elimine os recursos individuais.

      Elimine os recursos implementados

      Para evitar incorrer em custos na sua Google Cloud conta pelos recursos que criou neste guia, execute o seguinte comando:

      ps -ef | grep load.sh | awk '{print $2}' | xargs -n1 kill -9
      
      gcloud container clusters delete CLUSTER_NAME \
        --location=ZONE
      

      O que se segue?