LLMs wie DeepSeek-R1 671B oder Llama 3.1 405B in GKE bereitstellen


Übersicht

In diesem Leitfaden erfahren Sie, wie Sie moderne Large Language Models (LLMs) wie DeepSeek-R1 671B oder Llama 3.1 405B in Google Kubernetes Engine (GKE) mit GPUs auf mehreren Knoten bereitstellen.

In diesem Leitfaden wird gezeigt, wie Sie portable Open-Source-Technologien – Kubernetes, vLLM und die LeaderWorkerSet (LWS)-API – verwenden, um KI-/ML-Arbeitslasten in GKE bereitzustellen und bereitzustellen. Dabei profitieren Sie von der detaillierten Steuerung, Skalierbarkeit, Robustheit, Portabilität und Kosteneffizienz von GKE.

Machen Sie sich vor dem Lesen dieser Seite mit den folgenden Themen vertraut:

Hintergrund

In diesem Abschnitt werden die in diesem Leitfaden verwendeten Schlüsseltechnologien beschrieben, einschließlich der beiden LLMs, die in diesem Leitfaden als Beispiele verwendet werden: DeepSeek-R1 und Llama 3.1 405B.

DeepSeek-R1

DeepSeek-R1 ist ein Large Language Model mit 671 Milliarden Parametern von DeepSeek, das für logische Schlussfolgerungen, mathematische Argumentation und die Lösung von Problemen in Echtzeit bei verschiedenen textbasierten Aufgaben entwickelt wurde. GKE bewältigt die Rechenanforderungen von DeepSeek-R1 und unterstützt die Funktionen mit skalierbaren Ressourcen, verteiltem Computing und effizienten Netzwerken.

Weitere Informationen finden Sie in der DeepSeek-Dokumentation.

Llama 3.1 405B

Llama 3.1 405B ist ein Large Language Model von Meta, das für eine Vielzahl von Natural Language Processing-Aufgaben entwickelt wurde, darunter Textgenerierung, Übersetzung und Fragenbeantwortung. GKE bietet die robuste Infrastruktur, die für das verteilte Training und die Bereitstellung von Modellen dieser Größenordnung erforderlich ist.

Weitere Informationen finden Sie in der Llama-Dokumentation.

Verwalteter Kubernetes-Dienst von GKE

Google Cloud bietet eine Vielzahl von Diensten, darunter GKE, der sich gut für die Bereitstellung und Verwaltung von KI-/ML-Arbeitslasten eignet. GKE ist ein verwalteter Kubernetes-Dienst, der die Bereitstellung, Skalierung und Verwaltung von Containeranwendungen vereinfacht. GKE bietet die erforderliche Infrastruktur, einschließlich skalierbarer Ressourcen, verteiltes Computing und effiziente Netzwerke, um die Rechenanforderungen von LLMs zu bewältigen.

Weitere Informationen zu wichtigen Kubernetes-Konzepten finden Sie unter Informationen zu Kubernetes. Weitere Informationen zu GKE und dazu, wie Sie damit Kubernetes skalieren, automatisieren und verwalten können, finden Sie in der GKE-Übersicht.

GPUs

Mit Grafikprozessoren (GPUs) können Sie bestimmte Arbeitslasten wie maschinelles Lernen und Datenverarbeitung beschleunigen. GKE bietet Knoten, die mit diesen leistungsstarken GPUs ausgestattet sind. So können Sie Ihren Cluster für optimale Leistung bei Aufgaben für maschinelles Lernen und Datenverarbeitung konfigurieren. GKE bietet eine Reihe von Maschinentypoptionen für die Knotenkonfiguration, einschließlich Maschinentypen mit NVIDIA H100-, L4- und A100-GPUs.

Weitere Informationen finden Sie unter GPUs in GKE.

LeaderWorkerSet (LWS)

LeaderWorkerSet (LWS) ist eine Kubernetes-Bereitstellungs-API, die auf gängige Bereitstellungsmuster von KI/ML-Inferenzarbeitslasten mit mehreren Knoten zugeschnitten ist. Bei der Bereitstellung mit mehreren Knoten werden mehrere Pods verwendet, die jeweils auf einem anderen Knoten ausgeführt werden können, um die verteilte Inferenzarbeitslast zu verarbeiten. Mit LWS können mehrere Pods als Gruppe behandelt werden, was die Verwaltung von verteiltem Model Serving vereinfacht.

vLLM und Bereitstellung mit mehreren Hosts

Wenn Sie rechenintensive LLMs bereitstellen, empfehlen wir die Verwendung von vLLM und die Ausführung der Arbeitslasten auf mehreren GPUs.

vLLM ist ein hoch optimiertes Open-Source-LLM-Bereitstellungs-Framework, das den Bereitstellungsdurchsatz auf GPUs über Funktionen wie die Folgenden beschleunigen kann:

  • Optimierte Transformer-Implementierung mit PagedAttention
  • Kontinuierliche Batchverarbeitung zur Verbesserung des allgemeinen Bereitstellungsdurchsatzes
  • Verteilte Bereitstellung auf mehreren GPUs

Bei rechenintensiven LLMs, die nicht auf einen einzelnen GPU-Knoten passen, können Sie das Modell auf mehreren GPU-Knoten bereitstellen. vLLM unterstützt das Ausführen von Arbeitslasten auf mehreren GPUs mit zwei Strategien:

  • Bei der Tensor-Parallelität werden die Matrixmultiplikationen in der Transformer-Schicht auf mehrere GPUs aufgeteilt. Diese Strategie erfordert jedoch ein schnelles Netzwerk aufgrund der erforderlichen Kommunikation zwischen den GPUs. Daher ist sie weniger geeignet für die Ausführung von Arbeitslasten auf mehreren Knoten.

  • Bei der Pipeline-Parallelität wird das Modell nach Schicht oder vertikal aufgeteilt. Für diese Strategie ist keine ständige Kommunikation zwischen GPUs erforderlich. Sie ist daher eine bessere Option, wenn Modelle auf mehreren Knoten ausgeführt werden.

Sie können beide Strategien für die Bereitstellung mit mehreren Knoten verwenden. Wenn Sie beispielsweise zwei Knoten mit jeweils acht H100-GPUs verwenden, können Sie beide Strategien nutzen:

  • Bidirektionale Pipeline-Parallelität zum Sharden des Modells auf die beiden Knoten
  • Achtfache Tensor-Parallelität zum Sharden des Modells auf die acht GPUs auf jedem Knoten

Weitere Informationen finden Sie in der vLLM-Dokumentation.

Lernziele

  1. Bereiten Sie Ihre Umgebung mit einem GKE-Cluster im Autopilot- oder Standardmodus vor.
  2. Stellen Sie vLLM auf mehreren Knoten in Ihrem Cluster bereit.
  3. Verwenden Sie vLLM, um das Modell über curl bereitzustellen.

Hinweise

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

      Zu IAM
    2. Wählen Sie das Projekt aus.
    3. Klicken Sie auf Zugriff erlauben.
    4. Geben Sie im Feld Neue Hauptkonten Ihre Nutzer-ID ein. Dies ist in der Regel die E-Mail-Adresse eines Google-Kontos.

    5. Wählen Sie in der Liste Rolle auswählen eine Rolle aus.
    6. Wenn Sie weitere Rollen hinzufügen möchten, klicken Sie auf Weitere Rolle hinzufügen und fügen Sie weitere Rollen hinzu.
    7. Klicken Sie auf Speichern.
  • Erstellen Sie ein Hugging Face-Konto, falls Sie noch keines haben.
  • Prüfen Sie, ob Ihr Projekt ein ausreichendes Kontingent für NVIDIA_H100_MEGA hat. In dieser Anleitung wird der Maschinentyp a3-highgpu-8g verwendet, der mit 8 NVIDIA H100 80GB GPUs ausgestattet ist. Weitere Informationen zu GPUs und zur Verwaltung von Kontingenten finden Sie unter GPUs und Zuteilungskontingente.

Zugriff auf das Modell erhalten

Sie können die Modelle Llama 3.1 405B oder DeepSeek-R1 verwenden.

DeepSeek-R1

Zugriffstoken erstellen

Falls noch nicht geschehen, generieren Sie ein neues Hugging Face-Token:

  1. Klicken Sie auf Profil > Einstellungen > Zugriffstokens.
  2. Wählen Sie Neues Token aus.
  3. Geben Sie einen Namen Ihrer Wahl und eine Rolle von mindestens Read an.
  4. Wählen Sie Token generieren aus.

Llama 3.1 405B

Zugriffstoken erstellen

Falls noch nicht geschehen, generieren Sie ein neues Hugging Face-Token:

  1. Klicken Sie auf Profil > Einstellungen > Zugriffstokens.
  2. Wählen Sie Neues Token aus.
  3. Geben Sie einen Namen Ihrer Wahl und eine Rolle von mindestens Read an.
  4. Wählen Sie Token generieren aus.

Umgebung vorbereiten

In dieser Anleitung verwenden Sie Cloud Shell zum Verwalten von Ressourcen, die inGoogle Cloudgehostet werden. Die Software, die Sie für diese Anleitung benötigen, ist in Cloud Shell vorinstalliert, einschließlich kubectl und gcloud CLI.

So richten Sie Ihre Umgebung mit Cloud Shell ein:

  1. Starten Sie in der Google Cloud Console eine Cloud Shell-Sitzung. Klicken Sie dazu in der Google Cloud Console auf Symbol für die Cloud Shell-Aktivierung Cloud Shell aktivieren. Dadurch wird im unteren Bereich der Google Cloud console eine Sitzung gestartet.

  2. Legen Sie die Standardumgebungsvariablen fest:

    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
    

    Ersetzen Sie die folgenden Werte:

    • PROJECT_ID: Ihre Google Cloud Projekt-ID.
    • CLUSTER_NAME: der Name Ihres GKE-Clusters.
    • REGION: die Region Ihres GKE-Cluster.
    • ZONE: Eine Zone, die NVIDIA H100 Tensor Core-GPUs unterstützt.

GKE-Cluster erstellen

Sie können Modelle mit vLLM auf mehreren GPU-Knoten in einem GKE-Cluster im Autopilot- oder Standardmodus bereitstellen. Für eine vollständig verwaltete Kubernetes-Umgebung empfehlen wir die Verwendung eines Autopilot-Clusters. Informationen zum Auswählen des GKE-Betriebsmodus, der für Ihre Arbeitslasten am besten geeignet ist, finden Sie unter GKE-Betriebsmodus auswählen.

Autopilot

Führen Sie in Cloud Shell den folgenden Befehl aus:

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

Standard

  1. Erstellen Sie einen GKE-Standardcluster mit zwei CPU-Knoten:

    gcloud container clusters create CLUSTER_NAME \
        --project=PROJECT_ID \
        --num-nodes=2 \
        --location=REGION \
        --machine-type=e2-standard-16
    
  2. Erstellen Sie einen A3-Knotenpool mit zwei Knoten und jeweils acht 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}
    

kubectl für die Kommunikation mit Ihrem Cluster konfigurieren

Konfigurieren Sie kubectl für die Kommunikation mit Ihrem Cluster mit dem folgenden Befehl:

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

Kubernetes-Secret für Hugging Face-Anmeldedaten erstellen

Erstellen Sie mit dem folgenden Befehl ein Kubernetes-Secret, das das Hugging Face-Token enthält:

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

LeaderWorkerSet installieren

Führen Sie den folgenden Befehl aus, um LWS zu installieren:

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

Prüfen Sie mit dem folgenden Befehl, ob der LeaderWorkerSet-Controller im Namespace lws-system ausgeführt wird:

kubectl get pod -n lws-system

Die Ausgabe sieht etwa so aus:

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

vLLM Model Server bereitstellen

So stellen Sie den vLLM-Modellserver bereit:

  1. Wenden Sie das Manifest je nach dem LLM an, das Sie bereitstellen möchten.

    DeepSeek-R1

    1. Sehen Sie sich das vllm-deepseek-r1-A3.yaml-Manifest an.

      
      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. Wenden Sie das Manifest mit dem folgenden Befehl an:

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

    Llama 3.1 405B

    1. Sehen Sie sich das vllm-llama3-405b-A3.yaml-Manifest an.

      
      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. Wenden Sie das Manifest mit dem folgenden Befehl an:

      kubectl apply -f vllm-llama3-405b-A3.yaml
      
  2. Warten Sie, bis der Download des Modell-Checkpoints abgeschlossen ist. Dieser Vorgang kann einige Minuten dauern.

  3. Sehen Sie sich die Logs des ausgeführten Modellservers mit dem folgenden Befehl an:

    kubectl logs vllm-0 -c vllm-leader
    

    Die Ausgabe sollte in etwa so aussehen:

    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)
    

Modell bereitstellen

Richten Sie mit dem folgenden Befehl die Portweiterleitung zum Modell ein:

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

Mithilfe von curl mit dem Modell interagieren

So interagieren Sie mit dem Modell mithilfe von curl:

DeepSeek-R1

Senden Sie in einem neuen Terminal eine Anfrage an den 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
}'

Die Ausgabe sollte in etwa so aussehen:

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

Senden Sie in einem neuen Terminal eine Anfrage an den 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
}'

Die Ausgabe sollte in etwa so aussehen:

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

Benutzerdefiniertes Autoscaling einrichten

In diesem Abschnitt richten Sie das horizontale Pod-Autoscaling so ein, dass benutzerdefinierte Prometheus-Messwerte verwendet werden. Sie verwenden die Google Cloud Managed Service for Prometheus-Messwerte vom vLLM-Server.

Weitere Informationen finden Sie unter Google Cloud Managed Service for Prometheus. Diese Option sollte im GKE-Cluster standardmäßig aktiviert sein.

  1. Richten Sie den Stackdriver-Adapter für benutzerdefinierte Messwerte in Ihrem Cluster ein:

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml
    
  2. Fügen Sie dem Dienstkonto, das vom Stackdriver-Adapter für benutzerdefinierte Messwerte verwendet wird, die Rolle „Monitoring-Betrachter“ hinzu:

    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. Speichern Sie das folgende Manifest als 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. Wenden Sie das Manifest auf den Cluster an:

    kubectl apply -f vllm_pod_monitor.yaml
    

Last auf dem vLLM-Endpunkt erzeugen

Erstellen Sie eine Last auf dem vLLM-Server, um zu testen, wie GKE mit einem benutzerdefinierten vLLM-Messwert skaliert wird.

  1. Richten Sie die Portweiterleitung zum Modell ein:

    kubectl port-forward svc/vllm-leader 8080:8080
    
  2. Führen Sie ein Bash-Skript (load.sh) aus, um N parallele Anfragen an den vLLM-Endpunkt zu senden:

    #!/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/Llama-3.1-70B", "prompt": "Write a story about san francisco", "max_tokens": 100, "temperature": 0}'
      done &  # Run in the background
    done
    wait
    

    Ersetzen Sie PARALLEL_PROCESSES durch die Anzahl der parallelen Prozesse, die Sie ausführen möchten.

  3. Führen Sie das Bash-Skript aus:

    nohup ./load.sh &
    

Prüfen, ob Google Cloud Managed Service for Prometheus die Messwerte aufnimmt

Nachdem Google Cloud Managed Service for Prometheus die Messwerte erfasst hat und Sie den vLLM-Endpunkt belasten, können Sie die Messwerte in Cloud Monitoring ansehen.

  1. Rufen Sie in der Google Cloud Console die Seite Metrics Explorer auf.

    Zu Metrics Explorer

  2. Klicken Sie auf < > PromQL.

  3. Geben Sie die folgende Abfrage ein, um Traffic-Messwerte zu beobachten:

    vllm:gpu_cache_usage_perc{cluster='CLUSTER_NAME'}
    

Das folgende Bild zeigt ein Beispiel für ein Diagramm nach der Ausführung des Lastskripts. Dieses Diagramm zeigt, dass Google Cloud Managed Service for Prometheus die Traffic-Messwerte als Reaktion auf die Last aufnimmt, die dem vLLM-Endpunkt hinzugefügt wurde:

Traffic-Messwerte für den vLLM-Server

Konfiguration für horizontales Pod-Autoscaling bereitstellen

Wenn Sie entscheiden, auf welchen Messwerten das Autoscaling basieren soll, empfehlen wir die folgenden Messwerte für vLLM:

  • num_requests_waiting: Dieser Messwert bezieht sich auf die Anzahl der Anfragen, die in der Warteschlange des Modellservers warten. Diese Zahl beginnt merklich zu steigen, wenn der KV-Cache voll ist.

  • gpu_cache_usage_perc: Dieser Messwert bezieht sich auf die Nutzung des KV-Cache, die direkt mit der Anzahl der Anfragen korreliert, die für einen bestimmten Inferenzzyklus auf dem Modellserver verarbeitet werden.

Wir empfehlen, num_requests_waiting zu verwenden, wenn Sie die Optimierung auf Durchsatz und Kosten ausrichten und Ihre Latenzziele mit dem maximalen Durchsatz Ihres Modellservers erreicht werden können.

Wir empfehlen die Verwendung von gpu_cache_usage_perc für latenzempfindliche Arbeitslasten, bei denen die warteschlangenbasierte Skalierung nicht schnell genug ist, um Ihre Anforderungen zu erfüllen.

Weitere Informationen finden Sie unter Best Practices für das Autoscaling von Inferenzen für LLM-Arbeitslasten (Large Language Model) mit GPUs.

Wenn Sie ein averageValue-Ziel für Ihre HPA-Konfiguration auswählen, müssen Sie experimentell ermitteln, welcher Messwert für das Autoscaling verwendet werden soll. Weitere Ideen zur Optimierung Ihrer Tests finden Sie im Blogpost Save on GPUs: Smarter autoscaling for your GKE inferencing workloads. Der in diesem Blogpost verwendete profile-generator funktioniert auch für vLLM.

So stellen Sie die Konfiguration des horizontalen Pod-Autoscalings mit num_requests_waiting bereit:

  1. Speichern Sie das folgende Manifest als 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
    

    Die vLLM-Messwerte in Google Cloud Managed Service for Prometheus folgen dem Format vllm:metric_name.

    Best Practice:

    Verwenden Sie num_requests_waiting zum Skalieren des Durchsatzes. Verwenden Sie gpu_cache_usage_perc für latenzempfindliche GPU-Anwendungsfälle.

  2. Stellen Sie die Konfiguration für das horizontale Pod-Autoscaling bereit:

    kubectl apply -f vllm-hpa.yaml
    

    GKE plant die Bereitstellung eines weiteren Pods, wodurch der Autoscaler für Knotenpools einen zweiten Knoten hinzufügt, bevor die zweite vLLM-Replica bereitgestellt wird.

  3. Beobachten Sie den Fortschritt des Pod-Autoscalings:

    kubectl get hpa --watch
    

    Die Ausgabe sieht etwa so aus:

    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
    

Modellladezeiten mit Hyperdisk ML verkürzen

Bei diesen Arten von LLMs kann es mit vLLM sehr lange dauern, bis sie auf jeder neuen Replika heruntergeladen, geladen und aufgewärmt sind. Bei Llama 3.1 405B kann dieser Vorgang beispielsweise etwa 90 Minuten dauern. Sie können diese Zeit verkürzen (auf 20 Minuten mit Llama 3.1 405B), indem Sie das Modell direkt auf ein Hyperdisk-ML-Volume herunterladen und dieses Volume in jedem Pod einbinden. Für diesen Vorgang werden in dieser Anleitung ein Hyperdisk ML-Volume und ein Kubernetes-Job verwendet. Ein Jobcontroller in Kubernetes erstellt einen oder mehrere Pods und sorgt dafür, dass sie eine bestimmte Aufgabe erfolgreich ausführen.

So beschleunigen Sie das Laden von Modellen:

  1. Speichern Sie das folgende Beispielmanifest als producer-pvc.yaml:

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: producer-pvc
    spec:
      storageClassName: hyperdisk-ml
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 800Gi
    
  2. Speichern Sie das folgende Beispielmanifest als 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. Folgen Sie der Anleitung unter KI/ML-Datenladen mit Hyperdisk ML beschleunigen und verwenden Sie die beiden Dateien, die Sie in den vorherigen Schritten erstellt haben.

    Nach diesem Schritt haben Sie das Hyperdisk ML-Volume erstellt und mit den Modelldaten gefüllt.

  4. Stellen Sie das vLLM-Deployment für GPU-Server mit mehreren Knoten bereit. Dabei wird das neu erstellte Hyperdisk ML-Volume für Modelldaten verwendet.

    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
    

Bereinigen

Damit Ihrem Google Cloud-Konto die in dieser Anleitung verwendeten Ressourcen nicht in Rechnung gestellt werden, löschen Sie entweder das Projekt, das die Ressourcen enthält, oder Sie behalten das Projekt und löschen die einzelnen Ressourcen.

Bereitgestellte Ressourcen löschen

Mit dem folgenden Befehl vermeiden Sie, dass Ihrem Google Cloud Konto die in dieser Anleitung erstellten Ressourcen in Rechnung gestellt werden:

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

Nächste Schritte