Pubblica LLM come DeepSeek-R1 671B o Llama 3.1 405B su GKE


Panoramica

Questa guida mostra come pubblicare modelli linguistici di grandi dimensioni (LLM) all'avanguardia come DeepSeek-R1 671B o Llama 3.1 405B su Google Kubernetes Engine (GKE) utilizzando unità di elaborazione grafica (GPU) su più nodi.

Questa guida mostra come utilizzare tecnologie open source portatili, ovvero Kubernetes, vLLM e l'API LeaderWorkerSet (LWS), per eseguire il deployment e il servizio di carichi di lavoro di IA/ML su GKE, sfruttando il controllo granulare, la scalabilità, la resilienza, la portabilità e il rapporto costo/efficacia di GKE.

Prima di leggere questa pagina, assicurati di conoscere quanto segue:

Sfondo

Questa sezione descrive le tecnologie chiave utilizzate in questa guida, inclusi i due modelli LLM utilizzati come esempi in questa guida: DeepSeek-R1 e Llama 3.1 405B.

DeepSeek-R1

DeepSeek-R1, un modello linguistico di grandi dimensioni (LLM) di DeepSeek con 671 miliardi di parametri, è progettato per l'inferenza logica, il ragionamento matematico e la risoluzione di problemi in tempo reale in varie attività basate su testo. GKE gestisce le richieste di calcolo di DeepSeek-R1, supportandone le funzionalità con risorse scalabili, calcolo distribuito e reti efficienti.

Per scoprire di più, consulta la documentazione di DeepSeek.

Llama 3.1 405B

Llama 3.1 405B è un modello linguistico di grandi dimensioni di Meta progettato per un'ampia gamma di attività di elaborazione del linguaggio naturale, tra cui generazione di testo, traduzione e risposta a domande. GKE offre l'infrastruttura solida necessaria per supportare le esigenze di addestramento e pubblicazione distribuite dei modelli di questa portata.

Per scoprire di più, consulta la documentazione di Llama.

Servizio Kubernetes gestito GKE

Google Cloud offre una vasta gamma di servizi, tra cui GKE, che è adatto per il deployment e la gestione dei carichi di lavoro di AI/ML. GKE è un servizio Kubernetes gestito che semplifica il deployment, la scalabilità e la gestione delle applicazioni containerizzate. GKE fornisce l'infrastruttura necessaria, tra cui risorse scalabili, calcolo distribuito e reti efficienti, per gestire le richieste di calcolo degli LLM.

Per saperne di più sui concetti chiave di Kubernetes, consulta Inizia a conoscere Kubernetes. Per scoprire di più su GKE e su come ti aiuta a scalare, automatizzare e gestire Kubernetes, consulta la panoramica di GKE.

GPU

Le GPU (unità di elaborazione grafica) ti consentono di accelerare carichi di lavoro specifici come il machine learning e l'elaborazione di dati. GKE offre nodi dotati di queste potenti GPU, che ti consentono di configurare il cluster per ottenere prestazioni ottimali nelle attività di machine learning e di elaborazione dei dati. GKE offre una gamma di opzioni di tipo di macchina per la configurazione dei nodi, inclusi i tipi di macchina con GPU NVIDIA H100, L4 e A100.

Per scoprire di più, consulta Informazioni sulle GPU in GKE.

LeaderWorkerSet (LWS)

LeaderWorkerSet (LWS) è un'API di deployment Kubernetes che gestisce i pattern di deployment comuni dei workload di inferenza multi-nodo AI/ML. La pubblicazione su più nodi sfrutta più Pod, ciascuno potenzialmente in esecuzione su un nodo diverso, per gestire il carico di lavoro di inferenza distribuita. LWS consente di trattare più pod come un gruppo, semplificando la gestione della pubblicazione di modelli distribuiti.

vLLM e pubblicazione su più host

Quando servi LLM ad intensità di calcolo elevata, consigliamo di utilizzare vLLM ed eseguire i carichi di lavoro su GPU.

vLLM è un framework di pubblicazione di modelli LLM open source altamente ottimizzato che può aumentare il throughput di pubblicazione sulle GPU, con funzionalità come le seguenti:

  • Implementazione ottimizzata del transformer con PagedAttention
  • Raggruppamento continuo per migliorare il throughput complessivo della pubblicazione
  • Pubblicazione distribuita su più GPU

Con LLM particolarmente impegnativi dal punto di vista computazionale che non possono essere inseriti in un singolo node GPU, puoi utilizzare più node GPU per eseguire il servizio del modello. vLLM supporta l'esecuzione di carichi di lavoro su più GPU con due strategie:

  • Il parallismo tensoriale suddivide le moltiplicazioni di matrici nel livello del trasformatore su più GPU. Tuttavia, questa strategia richiede una rete veloce a causa della comunicazione necessaria tra le GPU, rendendola meno adatta per l'esecuzione di carichi di lavoro su più nodi.

  • Il parallelismo della pipeline suddivide il modello per livello o in verticale. Questa strategia non richiede una comunicazione costante tra le GPU, il che la rende un'opzione migliore per l'esecuzione di modelli su più nodi.

Puoi utilizzare entrambe le strategie nella pubblicazione su più nodi. Ad esempio, se utilizzi due nodi con otto GPU H100 ciascuno, puoi utilizzare entrambe le strategie:

  • Parallelismo della pipeline bidirezionale per suddividere il modello nei due nodi
  • Parallelismo tensoriale a otto vie per suddividere il modello tra le otto GPU su ogni nodo

Per scoprire di più, consulta la documentazione vLLM.

Obiettivi

  1. Prepara l'ambiente con un cluster GKE in modalità Autopilot o Standard.
  2. Esegui il deployment di vLLM su più nodi del cluster.
  3. Utilizza vLLM per pubblicare il modello tramite curl.

Prima di iniziare

  • 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.

    Go to project selector

  • Make sure that billing is enabled for your Google Cloud project.

  • Enable the required API.

    Enable the API

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

    Go to project selector

  • Make sure that billing is enabled for your Google Cloud project.

  • Enable the required API.

    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.

      Vai a IAM
    2. Seleziona il progetto.
    3. Fai clic su Concedi accesso.
    4. Nel campo Nuovi principali, inserisci il tuo identificatore utente. In genere si tratta dell'indirizzo email di un Account Google.

    5. Nell'elenco Seleziona un ruolo, seleziona un ruolo.
    6. Per concedere altri ruoli, fai clic su Aggiungi un altro ruolo e aggiungi ogni ruolo aggiuntivo.
    7. Fai clic su Salva.

Ottieni l'accesso al modello

Puoi utilizzare i modelli Llama 3.1 405B o DeepSeek-R1.

DeepSeek-R1

Genera un token di accesso

Se non ne hai già uno, genera un nuovo token Hugging Face:

  1. Fai clic su Il tuo profilo > Impostazioni > Token di accesso.
  2. Seleziona Nuovo token.
  3. Specifica un nome a tua scelta e un ruolo di almeno Read.
  4. Seleziona Genera un token.

Llama 3.1 405B

Genera un token di accesso

Se non ne hai già uno, genera un nuovo token di Hugging Face:

  1. Fai clic su Il tuo profilo > Impostazioni > Token di accesso.
  2. Seleziona Nuovo token.
  3. Specifica un nome a tua scelta e un ruolo di almeno Read.
  4. Seleziona Genera un token.

Prepara l'ambiente

In questo tutorial utilizzerai Cloud Shell per gestire le risorse ospitate su Google Cloud. Cloud Shell include il software di cui avrai bisogno per questo tutorial, tra cui kubectl e gcloud CLI.

Per configurare l'ambiente con Cloud Shell:

  1. Nella console Google Cloud, avvia una sessione Cloud Shell facendo clic su Icona di attivazione di Cloud Shell Attiva Cloud Shell nella console Google Cloud. Viene avviata una sessione nel riquadro inferiore della console Google Cloud.

  2. Imposta le variabili di ambiente predefinite:

    gcloud config set project PROJECT_ID
    export PROJECT_ID=$(gcloud config get project)
    export CLUSTER_NAME=CLUSTER_NAME
    export ZONE=ZONE
    export HF_TOKEN=HUGGING_FACE_TOKEN
    export IMAGE_NAME=REGION_NAME-docker.pkg.dev/PROJECT_ID/vllm-multihost/vllm-multihost:latest
    

    Sostituisci i seguenti valori:

    • PROJECT_ID: il tuo Google Cloud ID progetto.
    • CLUSTER_NAME: il nome del tuo cluster GKE.
    • ZONE: una zona che supporta le GPU NVIDIA H100 Tensor Core.
    • IMAGE_NAME: l'immagine vLLM che include lo script Ray.

Crea un cluster GKE

Puoi pubblicare modelli utilizzando vLLM su più nodi GPU in un cluster GKE Autopilot o Standard. Ti consigliamo di utilizzare un cluster Autopilot per un'esperienza Kubernetes completamente gestita. Per scegliere la modalità operativa di GKE più adatta ai tuoi carichi di lavoro, consulta Scegliere una modalità operativa GKE.

Autopilot

In Cloud Shell, esegui questo comando:

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

Standard

  1. Crea un cluster GKE Standard con due nodi CPU:

    gcloud container clusters create CLUSTER_NAME \
        --project=PROJECT_ID \
        --num-nodes=2 \
        --location=ZONE \
        --machine-type=e2-standard-16
    
  2. Crea un node pool A3 con due nodi, ciascuno con otto H100:

    gcloud container node-pools create gpu-nodepool \
        --location=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
    

Configura kubectl per comunicare con il cluster

Configura kubectl per comunicare con il tuo cluster con il seguente comando:

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

Crea un secret di Kubernetes per le credenziali di Hugging Face

Crea un secret Kubernetes contenente il token di Hugging Face utilizzando il seguente comando:

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

Creare un'immagine vLLM multi-nodo

Per facilitare la comunicazione tra i nodi per vLLM, puoi utilizzare Ray. Il repository LeaderWorkerSet fornisce un Dockerfile, che include uno script bash per la configurazione di Ray con vLLM.

Per creare la tua immagine multi-nodo vLLM, devi eseguire il cloning del repository LeaderWorkerSet, creare un'immagine Docker utilizzando il Dockerfile fornito (che configura Ray per la comunicazione tra nodi) e poi eseguire il push dell'immagine in Artifact Registry per il deployment su GKE.

Crea il container

Per compilare il contenitore:

  1. Clona il repository LeaderWorkerSet:

    git clone https://github.com/kubernetes-sigs/lws.git
    
  2. Crea l'immagine.

    cd lws/docs/examples/vllm/build/ && docker build -f Dockerfile.GPU . -t vllm-multihost
    

Esegui il push dell'immagine in Artifact Registry

Per assicurarti che il deployment Kubernetes possa accedere all'immagine, archiviala in Artifact Registry all'interno del tuo Google Cloud progetto.

gcloud artifacts repositories create vllm-multihost --repository-format=docker --location=REGION_NAME && \
gcloud auth configure-docker REGION_NAME-docker.pkg.dev && \
docker image tag vllm-multihost REGION_NAME-docker.pkg.dev/PROJECT_ID/vllm-multihost/vllm-multihost:latest && \
docker push REGION_NAME-docker.pkg.dev/PROJECT_ID/vllm-multihost/vllm-multihost:latest

Installa LeaderWorkerSet

Per installare LWS, esegui il seguente comando:

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

Verifica che il controller LeaderWorkerSet sia in esecuzione nello spazio dei nomi lws-system utilizzando il seguente comando:

kubectl get pod -n lws-system

L'output è simile al seguente:

NAME                                      READY   STATUS    RESTARTS   AGE
lws-controller-manager-5c4ff67cbd-9jsfc   2/2     Running   0          6d23h

Esegui il deployment del server di modelli vLLM

Per eseguire il deployment del server di modelli vLLM:

  1. Applica il manifest, a seconda del modello LLM che vuoi implementare.

    DeepSeek-R1

    1. Controlla il file manifest 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: IMAGE_NAME
                  env:
                    - name: HUGGING_FACE_HUB_TOKEN
                      valueFrom:
                        secretKeyRef:
                          name: hf-secret
                          key: hf_api_token
                  command:
                    - sh
                    - -c
                    - "/vllm-workspace/ray_init.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: IMAGE_NAME
                  command:
                    - sh
                    - -c
                    - "/vllm-workspace/ray_init.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. Applica il manifest eseguendo il seguente comando:

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

    Llama 3.1 405B

    1. Controlla il file manifest 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: IMAGE_NAME
                  env:
                    - name: HUGGING_FACE_HUB_TOKEN
                      valueFrom:
                        secretKeyRef:
                          name: hf-secret
                          key: hf_api_token
                  command:
                    - sh
                    - -c
                    - "/vllm-workspace/ray_init.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: IMAGE_NAME
                  command:
                    - sh
                    - -c
                    - "/vllm-workspace/ray_init.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. Applica il manifest eseguendo il seguente comando:

      kubectl apply -f vllm-llama3-405b-A3.yaml
      
  2. Visualizza i log del server di modelli in esecuzione con il seguente comando:

    kubectl logs vllm-0 -c vllm-leader
    

    L'output dovrebbe essere simile al seguente:

    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)
    

Pubblica il modello

Configura il port forwarding al modello eseguendo il seguente comando:

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

Interagire con il modello utilizzando curl

Per interagire con il modello utilizzando curl:

DeepSeek-R1

In un nuovo terminale, invia una richiesta al server:

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
}'

L'output dovrebbe essere simile al seguente:

{
"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

In un nuovo terminale, invia una richiesta al server:

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
}'

L'output dovrebbe essere simile al seguente:

{"id":"cmpl-0a2310f30ac3454aa7f2c5bb6a292e6c",
"object":"text_completion","created":1723238375,"model":"meta-llama/Meta-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}}

Configurare l'autoscalatore personalizzato

In questa sezione, configuri la scalabilità automatica orizzontale dei pod per utilizzare le metriche Prometheus personalizzate. Utilizzi le metriche di Google Cloud Managed Service per Prometheus dal server vLLM.

Per saperne di più, consulta Google Cloud Managed Service per Prometheus. Questa opzione dovrebbe essere attiva per impostazione predefinita nel cluster GKE.

  1. Configura l'adattatore Stackdriver delle metriche personalizzate nel tuo cluster:

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml
    
  2. Aggiungi il ruolo Visualizzatore di monitoraggio all'account di servizio utilizzato dall'adattatore Stackdriver per le metriche personalizzate:

    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. Salva il seguente manifest come 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. Applica il manifest al cluster:

    kubectl apply -f vllm_pod_monitor.yaml
    

Creare un carico sull'endpoint vLLM

Crea un carico sul server vLLM per testare la scalabilità automatica di GKE con una metrica vLLM personalizzata.

  1. Configura il port forwarding per il modello:

    kubectl port-forward svc/vllm-leader 8080:8080
    
  2. Esegui uno script bash (load.sh) per inviare N richieste parallele all'endpoint vLLM:

    #!/bin/bash
    N=PARALLEL_PROCESSES
    export vllm_service=$(kubectl get service vllm-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    for i in $(seq 1 $N); do
      while true; do
        curl http://$vllm_service:8000/v1/completions -H "Content-Type: application/json" -d '{"model": "meta-llama/Meta-Llama-3.1-70B", "prompt": "Write a story about san francisco", "max_tokens": 100, "temperature": 0}'
      done &  # Run in the background
    done
    wait
    

    Sostituisci PARALLEL_PROCESSES con il numero di procedimenti paralleli che vuoi eseguire.

  3. Esegui lo script bash:

    nohup ./load.sh &
    

Verifica che Google Cloud Managed Service per Prometheus importi le metriche

Dopo che Google Cloud Managed Service per Prometheus ha estratto le metriche e hai aggiunto il carico all'endpoint vLLM, puoi visualizzare le metriche in Cloud Monitoring.

  1. Nella console Google Cloud, vai alla pagina Esplora metriche.

    Vai a Esplora metriche

  2. Fai clic su < > PromQL.

  3. Inserisci la seguente query per osservare le metriche sul traffico:

    vllm:gpu_cache_usage_perc{cluster='CLUSTER_NAME'}
    

L'immagine seguente è un esempio di grafico dopo l'esecuzione dello script di caricamento. Questo grafico mostra che Google Cloud Managed Service per Prometheus sta acquisendo le metriche sul traffico in risposta al carico aggiunto all'endpoint vLLM:

Metriche sul traffico acquisite per il server vLLM

Esegui il deployment della configurazione di Horizontal Pod Autoscaler

Quando decidi su quale metrica eseguire il ridimensionamento automatico, ti consigliamo le seguenti metriche per vLLM:

  • num_requests_waiting: questa metrica si riferisce al numero di richieste in attesa nella coda del server del modello. Questo numero inizia a crescere notevolmente quando la cache KV è piena.

  • gpu_cache_usage_perc: questa metrica si riferisce all'utilizzo della cache KV, correlata direttamente al numero di richieste elaborate per un determinato ciclo di inferenza sul server del modello.

Ti consigliamo di utilizzare num_requests_waiting quando esegui l'ottimizzazione in base a throughput e costo e quando i tuoi target di latenza sono raggiungibili con il throughput massimo del server del modello.

Ti consigliamo di utilizzare gpu_cache_usage_perc quando hai carichi di lavoro sensibili alla latenza in cui la scalabilità basata su coda non è abbastanza veloce per soddisfare i tuoi requisiti.

Per ulteriori spiegazioni, consulta Best practice per la scalabilità automatica dei carichi di lavoro di inferenza dei modelli linguistici di grandi dimensioni (LLM) con GPU.

Quando selezioni un target averageValue per la configurazione dell'HPA, devi determinare sperimentalmente su quale metrica eseguire l'autoscaling. Per altre idee su come ottimizzare gli esperimenti, consulta il post del blog Risparmiare sulle GPU: scalabilità automatica più intelligente per i carichi di lavoro di inferenza GKE. profile-generator utilizzato in questo post del blog funziona anche per vLLM.

Per eseguire il deployment della configurazione di Horizontal Pod Autoscaler utilizzando num_requests_waiting, segui questi passaggi:

  1. Salva il seguente manifest come 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
    

    Le metriche vLLM in Google Cloud Managed Service per Prometheus seguono il formato vllm:metric_name.

    Best practice:

    Utilizza num_requests_waiting per scalare la velocità in bit. Utilizza gpu_cache_usage_perc per i casi d'uso GPU sensibili alla latenza.

  2. Esegui il deployment della configurazione di Horizontal Pod Autoscaler:

    kubectl apply -f vllm-hpa.yaml
    

    GKE pianifica il deployment di un altro pod, che attiva il gestore della scalabilità automatica del node pool per aggiungere un secondo nodo prima di eseguire il deployment della seconda replica vLLM.

  3. Monitora l'avanzamento della scalabilità automatica dei pod:

    kubectl get hpa --watch
    

    L'output è simile al seguente:

    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
    

Accelera i tempi di caricamento dei modelli con Hyperdisk ML

Con questi tipi di LLM, il vLLM può richiedere molto tempo per il download, il caricamento e l'inizializzazione su ogni nuova replica. Ad esempio, questa operazione può richiedere circa 90 minuti con Llama 3.1 405B. Puoi ridurre questo tempo (a 20 minuti con Llama 3.1 405B) scaricando il modello direttamente in un volume ML Hyperdisk e montando questo volume su ogni pod. Per completare questa operazione, questo tutorial utilizza un volume ML Hyperdisk e un job Kubernetes. Un controller Job in Kubernetes crea uno o più pod e si assicura che vengano eseguiti correttamente un'attività specifica.

Per velocizzare i tempi di caricamento del modello, segui questi passaggi:

  1. Salva il seguente manifest di esempio come producer-pvc.yaml:

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: producer-pvc
    spec:
      storageClassName: hyperdisk-ml
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 800Gi
    
  2. Salva il seguente manifest di esempio come 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. Segui le istruzioni riportate in Accelerare il caricamento dei dati AI/ML con Hyperdisk ML, utilizzando i due file creati nei passaggi precedenti.

    Al termine di questo passaggio, avrai creato e compilato il volume Hyperdisk ML con i dati del modello.

  4. Esegui il deployment del server GPU multi-nodo vLLM, che utilizzerà il volume ML Hyperdisk appena creato per i dati del modello.

    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: IMAGE_NAME
                env:
                  - name: HUGGING_FACE_HUB_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                command:
                  - sh
                  - -c
                  - "/vllm-workspace/ray_init.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: IMAGE_NAME
                command:
                  - sh
                  - -c
                  - "/vllm-workspace/ray_init.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: IMAGE_NAME
                env:
                  - name: HUGGING_FACE_HUB_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                command:
                  - sh
                  - -c
                  - "/vllm-workspace/ray_init.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: IMAGE_NAME
                command:
                  - sh
                  - -c
                  - "/vllm-workspace/ray_init.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
    

Esegui la pulizia

Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.

Elimina le risorse di cui è stato eseguito il deployment

Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse che hai creato in questa guida, esegui il seguente comando:

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

Passaggi successivi