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 der Google Kubernetes Engine (GKE) mithilfe von GPUs auf mehreren Knoten bereitstellen.

In diesem Leitfaden erfahren Sie, wie Sie mithilfe portabler Open-Source-Technologien wie Kubernetes, vLLM und der LeaderWorkerSet-API (LWS) KI/ML-Arbeitslasten in GKE bereitstellen und ausführen. Dabei werden die detaillierte Kontrolle, Skalierbarkeit, Ausfallsicherheit, Übertragbarkeit und Kosteneffizienz von GKE genutzt.

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 von DeepSeek mit 671 Milliarden Parametern. Es wurde für logische Schlussfolgerungen, mathematisches Denken und die Lösung von Problemen in Echtzeit bei verschiedenen textbasierten Aufgaben entwickelt. GKE erfüllt die Rechenanforderungen von DeepSeek-R1 und unterstützt seine Funktionen mit skalierbaren Ressourcen, verteiltem Computing und effizientem Networking.

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 Aufgaben im Bereich Natural Language Processing entwickelt wurde, darunter Textgenerierung, Übersetzung und Fragebeantwortung. 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 breite Palette von Diensten, darunter GKE, das sich gut für die Bereitstellung und Verwaltung von KI-/ML-Arbeitslasten eignet. GKE ist ein verwalteter Kubernetes-Dienst, der das Bereitstellen, Skalieren und Verwalten von containerisierten Anwendungen vereinfacht. GKE bietet die erforderliche Infrastruktur, einschließlich skalierbarer Ressourcen, verteiltem Computing und effizientem Networking, um die Rechenanforderungen von LLMs zu erfüllen.

Weitere Informationen zu den wichtigsten Kubernetes-Konzepten finden Sie unter Einstieg in Kubernetes. Weitere Informationen zur 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 mit diesen leistungsstarken GPUs, sodass Sie Ihren Cluster für eine optimale Leistung bei Aufgaben für maschinelles Lernen und Datenverarbeitung konfigurieren können. 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 gängige Bereitstellungsmuster von KI/ML-Inferenzarbeitslasten mit mehreren Knoten anspricht. 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 der verteilten Modellbereitstellung vereinfacht.

vLLM und Mehrfachhostbereitstellung

Wenn Sie LLMs mit hoher Rechenleistung bereitstellen, empfehlen wir die Verwendung von vLLM und die Ausführung der Arbeitslasten auf 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 besonders rechenintensiven LLMs, die nicht auf einem einzelnen GPU-Knoten passen, können Sie mehrere GPU-Knoten verwenden, um das Modell bereitzustellen. vLLM unterstützt das Ausführen von Arbeitslasten auf GPUs mit zwei Strategien:

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

  • Bei der Pipeline-Parallelität wird das Modell nach Ebene oder vertikal aufgeteilt. Diese Strategie erfordert keine ständige Kommunikation zwischen GPUs. Daher ist sie eine bessere Option, wenn Modelle auf mehreren Knoten ausgeführt werden.

Sie können beide Strategien beim Ausliefern über mehrere Knoten verwenden. Wenn Sie beispielsweise zwei Knoten mit jeweils acht H100-GPUs verwenden, können Sie beide Strategien verwenden:

  • Zwei-Wege-Pipeline-Parallelität, um das Modell auf die beiden Knoten aufzuteilen
  • Achtfache Tensorparallelität, um das Modell auf die acht GPUs auf jedem Knoten aufzuteilen

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.

      IAM aufrufen
    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 H100-GPUs hat. Weitere Informationen 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

verwenden zu können.

Zugriffstoken erstellen

Generieren Sie ein neues Hugging Face-Token, falls Sie noch keines haben:

  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

verwenden zu können.

Zugriffstoken erstellen

Generieren Sie ein neues Hugging Face-Token, falls Sie noch keines haben:

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

    Ersetzen Sie die folgenden Werte:

    • PROJECT_ID: Ihre Google Cloud Projekt-ID.
    • CLUSTER_NAME: der Name Ihres GKE-Clusters.
    • ZONE: Eine Zone, die NVIDIA H100 Tensor Core-GPUs unterstützt.
    • IMAGE_NAME: das vLLM-Image mit dem Ray-Script.

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} \
    --region=${REGION} \
    --cluster-version=${CLUSTER_VERSION}

Standard

  1. GKE-Standardcluster mit zwei CPU-Knoten erstellen:

    gcloud container clusters create CLUSTER_NAME \
        --project=PROJECT_ID \
        --num-nodes=2 \
        --location=ZONE \
        --machine-type=e2-standard-16
    
  2. Erstellen Sie einen A3-Knotenpool mit zwei Knoten, die jeweils acht H100s enthalten:

    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
    

kubectl für die Kommunikation mit Ihrem Cluster konfigurieren

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

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

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 -

Eigenes vLLM-Image mit mehreren Knoten erstellen

Um die Knotenübergreifende Kommunikation für vLLM zu erleichtern, können Sie Ray verwenden. Das LeaderWorkerSet-Repository enthält ein Dockerfile mit einem Bash-Script zum Konfigurieren von Ray mit vLLM.

Wenn Sie Ihr eigenes vLLM-Multi-Node-Image erstellen möchten, müssen Sie das LeaderWorkerSet-Repository klonen, ein Docker-Image mit dem bereitgestellten Dockerfile erstellen (das Ray für die netzwerkübergreifende Kommunikation konfiguriert) und dieses Image dann zur Bereitstellung in GKE in Artifact Registry hochladen.

Container erstellen

So erstellen Sie den Container:

  1. Klonen Sie das LeaderWorkerSet-Repository:

    git clone https://github.com/kubernetes-sigs/lws.git
    
  2. Image erstellen

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

Übertragen Sie das Image per Push in Artifact Registry:

Damit Ihr Kubernetes-Deployment auf das Image zugreifen kann, müssen Sie es in der Artifact Registry in Ihrem Google Cloud Projekt speichern.

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

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 in etwa so aus:

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

vLLM-Modellserver bereitstellen

So stellen Sie den vLLM-Modellserver bereit:

  1. Wenden Sie das Manifest je nach dem zu implementierenden LLM an.

    DeepSeek-R1

    1. Prüfen Sie das vllm-deepseek-r1-A3.yaml-Manifest.

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

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

    Llama 3.1 405B

    1. Prüfen Sie das vllm-llama3-405b-A3.yaml-Manifest.

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

      kubectl apply -f vllm-llama3-405b-A3.yaml
      
  2. Rufen Sie die Protokolle des laufenden Modellservers mit dem folgenden Befehl auf:

    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 die Portweiterleitung zum Modell mit dem folgenden Befehl 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/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}}

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 standardmäßig auf dem GKE-Cluster 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 Auslastung auf dem vLLM-Server, um zu testen, wie GKE mit einem benutzerdefinierten vLLM-Messwert automatisch skaliert.

  1. Richten Sie die Portweiterleitung zum Modell ein:

    kubectl port-forward svc/vllm-leader 8080:8080
    
  2. Führen Sie ein Bash-Script (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/Meta-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-Script aus:

    nohup ./load.sh &
    

Prüfen, ob die Messwerte in Google Cloud Managed Service for Prometheus aufgenommen werden

Nachdem Google Cloud Managed Service for Prometheus die Messwerte gescrapt hat und Sie dem vLLM-Endpunkt eine Last hinzufügen, können Sie die Messwerte in Cloud Monitoring aufrufen.

  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 die 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 Ladescripts. In diesem Diagramm ist zu sehen, dass Google Cloud Managed Service for Prometheus die Traffic-Messwerte als Reaktion auf die dem vLLM-Endpunkt hinzugefügte Last aufnimmt:

Für den vLLM-Server erfasste Traffic-Messwerte

Konfiguration für horizontales Pod-Autoscaling bereitstellen

Bei der Entscheidung, anhand welcher Messwerte das Autoscaling erfolgen soll, empfehlen wir für vLLM die folgenden Messwerte:

  • num_requests_waiting: Dieser Messwert bezieht sich auf die Anzahl der Anfragen, die in der Warteschlange des Modellservers warten. Diese Zahl steigt merklich an, wenn der kv-Cache voll ist.

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

Wir empfehlen num_requests_waiting, wenn Sie den Durchsatz und die Kosten optimieren und Ihre Latenzziele mit dem maximalen Durchsatz Ihres Modellservers erreichbar sind.

Wir empfehlen die Verwendung von gpu_cache_usage_perc, wenn Sie latenzempfindliche Arbeitslasten haben, 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 festlegen, anhand welchem Messwert das Autoscaling getestet werden soll. Weitere Ideen zur Optimierung Ihrer Tests finden Sie im Blogpost GPUs sparen: Intelligenteres Autoscaling für Ihre GKE-Inferenzanwendungen. Der in diesem Blogpost verwendete Profilgenerator 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 vllm:metric_name-Format.

    Best Practice:

    Verwenden Sie num_requests_waiting, um den Durchsatz zu skalieren. Verwenden Sie gpu_cache_usage_perc für latenzempfindliche GPU-Anwendungsfälle.

  2. Konfigurieren Sie das horizontale Pod-Autoscaling:

    kubectl apply -f vllm-hpa.yaml
    

    GKE plant die Bereitstellung eines weiteren Pods, wodurch der Knotenpool-Autoscaler einen zweiten Knoten hinzufügt, bevor das zweite vLLM-Replikat bereitgestellt wird.

  3. Beobachten Sie den Fortschritt des Pod-Autoscalings:

    kubectl get hpa --watch
    

    Die Ausgabe sieht in 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 sehr lange dauern, bis vLLM auf jedem neuen Replikat heruntergeladen, geladen und warmgestellt wird. Mit 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 in ein Hyperdisk-ML-Volume herunterladen und dieses Volume auf jedem Pod bereitstellen. In dieser Anleitung wird für diesen Vorgang 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 die Modellladezeiten:

  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-Datenladevorgang mit Hyperdisk ML beschleunigen und verwenden Sie dabei 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 die vLLM-GPU-Serverbereitstellung mit mehreren Knoten bereit, für die das neu erstellte Hyperdisk ML-Volume für Modelldaten verwendet wird.

    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
    

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

Führen Sie den folgenden Befehl aus, damit Ihrem Google Cloud -Konto die in dieser Anleitung erstellten Ressourcen nicht 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