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

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

  • Verify 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.
      • Sehen Sie sich die verfügbaren GPU-Modelle und Maschinentypen an, um herauszufinden, welcher Maschinentyp und welche Region Ihren Anforderungen entsprechen.
      • 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 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