Qwen3-Coder-480B in der GKE mit Multi-Host-SGLang-TorchTPU auf TPU7x-Beschleunigern bereitstellen

In dieser Anleitung erfahren Sie, wie Sie Qwen3-Coder-480B (Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8), ein Mixture-of-Experts-Codierungsmodell, in der Google Kubernetes Engine (GKE) bereitstellen und verwenden. Für die Bereitstellung werden Multi-Host-TPU7x-Beschleuniger (Ironwood) und das SGLang-Bereitstellungs-Framework mit TorchTPU (torchtpu) und Prefill-Decode-Disaggregation (PD) verwendet.

In der in dieser Anleitung beschriebenen Bereitstellungskonfiguration stellen Sie zwei tpu7x-standard-4t-Knotenpools mit mehreren Hosts bereit, die jeweils in einer 2x2x2-Topologie angeordnet sind (acht TPU7x-Chips auf zwei Knoten pro Knotenpool, also insgesamt 16 TPU7x-Chips). Mit der Kubernetes LeaderWorkerSet API können Sie Folgendes tun:

  • Führen Sie disaggregierte Prefill- und Decodierungsserver mit mehreren Hosts auf separaten TPU7x-Slices mit aktivierter Tensor- und Expertenparallelität aus.
  • OpenAI-kompatible Anfragen über einen SGLang-Disaggregationsrouter weiterleiten.

Ziele

  • Richten Sie Ihren GKE-Cluster und die TPU7x-Knotenpools mit mehreren Hosts ein.
  • Anmeldedaten konfigurieren und den LeaderWorkerSet-Controller installieren.
  • Stellen Sie die SGLang-Arbeitslasten für Prefill, Decode und Router auf mehreren Hosts bereit.
  • Senden Sie eine Inferenzanfrage an den SGLang-Routerdienst.
  • Führen Sie eine Benchmark-Arbeitslast für die Bereitstellung aus.
  • bereinigen.

Kosten

In diesem Dokument verwenden Sie die folgenden kostenpflichtigen Komponenten vonGoogle Cloud:

Mit dem Preisrechner können Sie eine Kostenschätzung für Ihre voraussichtliche Nutzung vornehmen.

Nach Abschluss der in diesem Dokument beschriebenen Aufgaben können Sie weitere Kosten vermeiden, indem Sie die erstellten Ressourcen löschen. Weitere Informationen finden Sie unter Bereinigen.

Hinweis

  • Für diese Anleitung benötigen Sie ein Hugging Face-Zugriffstoken. Sie können sich bei Hugging Face für ein kostenloses Konto registrieren. Nachdem Sie ein Konto erstellt haben, generieren Sie ein Zugriffstoken:

    1. Klicken Sie auf der Seite Willkommen bei Hugging Face auf Ihren Konto-Avatar und wählen Sie Zugriffstokens aus.
    2. Klicken Sie auf der Seite Zugriffstokens auf Neues Token erstellen.
    3. Wählen Sie den Tokentyp Lesen aus und geben Sie einen Namen für das Token ein.
    4. Ihr Zugriffstoken wird angezeigt. Speichern Sie das Token an einem sicheren Ort.

  • Aktivieren Sie die Kubernetes Engine API, die Compute Engine API, die Cloud TPU API und die Artifact Registry API in Ihrem Google Cloud -Projekt:

    APIs aktivieren

  • Prüfen Sie, ob Ihr Projekt in der Region, in der sich Ihre TPU-Kapazität befindet, über ein ausreichendes Laufwerkskontingent und Kontingent für externe IP-Adressen verfügt:

    1. Rufen Sie in der Google Cloud Console die Seite Kontingente und Systemlimits auf.

      Zur Seite „Kontingente und Systemlimits“

    2. Prüfen Sie, ob Sie mindestens 2.800 GiB verfügbares Google Cloud Hyperdisk Balanced-Kontingent für die vier sitzungsspezifischen 700-GiB-Volumes haben, die von den Prefill- und Decode-Pods für das Modell-Caching verwendet werden.

    3. Filtern Sie nach In Verwendung befindliche regionale externe IPv4-Adressen und prüfen Sie, ob Sie in Ihrer Zielregion ein ausreichendes IP-Adresskontingent haben.

Bitten Sie Ihren Administrator, Ihnen die folgenden IAM-Rollen für Ihr Projekt zuzuweisen, um die Berechtigungen zu erhalten, die Sie zum Ausführen dieser Anleitung benötigen:

Weitere Informationen zum Zuweisen von Rollen finden Sie unter Zugriff auf Projekte, Ordner und Organisationen verwalten.

Sie können die erforderlichen Berechtigungen auch über benutzerdefinierte Rollen oder andere vordefinierte Rollen erhalten.

Achten Sie darauf, dass Ihr Compute Engine-Standarddienstkonto die folgenden IAM-Rollen (Identity and Access Management) für Ihr Projekt hat:

Umgebungsvariablen einrichten

Exportieren Sie die Umgebungsvariablen, die Sie in dieser Anleitung verwenden:

export CLUSTER_NAME="YOUR_CLUSTER_NAME"
export PROJECT_ID="YOUR_PROJECT_ID"
export REGION="YOUR_REGION"
export ZONE="YOUR_ZONE"
export RESERVATION="YOUR_RESERVATION_NAME"
export HF_TOKEN="YOUR_HF_TOKEN"
export SGLANG_IMAGE="lmsysorg/sglang:v0.1.0-tpu"

Ersetzen Sie Folgendes:

  • YOUR_CLUSTER_NAME: Name Ihres GKE-Clusters.
  • YOUR_PROJECT_ID: die ID Ihres Google Cloud-Projekts.
  • YOUR_REGION: die Region, in der Sie Ihren Cluster bereitstellen möchten, z. B. us-central1.
  • YOUR_ZONE: Die Zone, in der Sie Ihre TPU7x-Knotenpools bereitstellen möchten, z. B. us-central1-c.
  • YOUR_RESERVATION_NAME: Wenn Sie eine Reservierung verwenden, der Name Ihrer TPU7x-Reservierung.
  • YOUR_HF_TOKEN: Ihr Hugging Face-Zugriffstoken.
  • YOUR_SGLANG_TPU_IMAGE: Wenn Sie ein benutzerdefiniertes SGLang TorchTPU-Container-Image verwenden, der URI Ihres Images; andernfalls das Standard-SGLang TorchTPU-Image.

GKE-Cluster erstellen

Führen Sie die folgenden Schritte aus, um einen GKE-Cluster im Standardmodus zu erstellen und zwei Multi-Host-TPU7x-Knotenpools für die Disaggregation von Prefill und Decodierung anzuhängen:

  1. Erstellen Sie einen regionalen GKE-Cluster, der e2-standard-4-Knoten für den Standardknotenpool verwendet. Dieser bietet ausreichend CPU- und Arbeitsspeicherressourcen für den LeaderWorkerSet-Controller und den SGLang-Disaggregationsrouter:

    gcloud container clusters create $CLUSTER_NAME \
      --project=$PROJECT_ID \
      --location=$REGION \
      --machine-type=e2-standard-4
  2. Erstellen Sie eine Richtlinie für die Platzierung von Arbeitslasten mit hohem Durchsatz und einer 2x2x2-Beschleunigertopologie, die für TPU7x-Knotenpools mit mehreren Hosts erforderlich ist:

    gcloud compute resource-policies create workload-policy tpu7x-2x2x2-workload-policy \
        --type=HIGH_THROUGHPUT \
        --accelerator-topology=2x2x2 \
        --project=${PROJECT_ID} \
        --region=${REGION}
  3. Erstellen Sie zwei TPU7x-Knotenpools mit mehreren Hosts (tpu7x-pool-0 und tpu7x-pool-1), die jeweils zwei tpu7x-standard-4t-Knoten enthalten (acht TPU7x-Chips in einer 2x2x2-Topologie pro Knotenpool, insgesamt 16 TPU7x-Chips):

    gcloud container node-pools create tpu7x-pool-0 \
        --cluster=$CLUSTER_NAME \
        --location=$REGION \
        --node-locations=$ZONE \
        --machine-type=tpu7x-standard-4t \
        --num-nodes=2 \
        --placement-policy=tpu7x-2x2x2-workload-policy \
        --reservation-affinity=specific \
        --reservation=$RESERVATION \
        --project=$PROJECT_ID
    
    gcloud container node-pools create tpu7x-pool-1 \
        --cluster=$CLUSTER_NAME \
        --location=$REGION \
        --node-locations=$ZONE \
        --machine-type=tpu7x-standard-4t \
        --num-nodes=2 \
        --placement-policy=tpu7x-2x2x2-workload-policy \
        --reservation-affinity=specific \
        --reservation=$RESERVATION \
        --project=$PROJECT_ID

    Anstatt eine bestimmte Reservierung zu verwenden, können Sie die Knotenpools auch mit Spot-Kapazität oder Flex-Start-VMs erstellen. Übergeben Sie dazu die folgenden Flags:

    • Spot-VMs: Ersetzen Sie --reservation-affinity=specific und --reservation=${RESERVATION} durch --spot, um Spot-Kapazität zu verwenden. Es kann einige Zeit dauern, bis Instanzen, die Spot-Kapazität verwenden, nach dem Erstellen des Knotenpools erstellt werden. Außerdem können sie während der Ausführung von Arbeitslasten vorzeitig beendet werden.
    • Flex-Start-VMs: Ersetzen Sie --num-nodes=2, --reservation-affinity=specific und --reservation=${RESERVATION} durch --flex-start, --enable-autoscaling, --num-nodes=0, --min-nodes=0 und --max-nodes=2, um den Knotenpool mit der Verbrauchsoption Flex-Start bereitzustellen. Weitere Informationen finden Sie unter Kleine Batcharbeitslast mit TPUs und Flex-Start-VMs ausführen.
  4. Konfigurieren Sie kubectl-Anmeldedaten für die Kommunikation mit Ihrem Cluster:

    gcloud container clusters get-credentials $CLUSTER_NAME --location=${REGION} --project=${PROJECT_ID}

Anmeldedaten konfigurieren und LeaderWorkerSet installieren

Führen Sie die folgenden Schritte aus, um Ihren Cluster für die SGLang-Bereitstellung mit mehreren Hosts vorzubereiten:

  1. Erstellen Sie ein Kubernetes-Secret mit dem Namen hf-secret, um Ihr Hugging Face-Zugriffstoken zu speichern:

    kubectl create secret generic hf-secret \
        --from-literal=hf_api_token=${HF_TOKEN}
  2. Installieren Sie die LeaderWorkerSet-CustomResourceDefinition und den Controller in Ihrem Cluster:

    kubectl apply --server-side -k github.com/kubernetes-sigs/lws/config/default?ref=main
    echo "Waiting for LWS controller to be ready..."
    kubectl wait --for=condition=Available --timeout=300s deployment/lws-controller-manager -n lws-system

SGLang-Server mit mehreren Hosts bereitstellen

Im Arbeitslastmanifest (qwen3-coder-480b-multihost-disagg-v7x.yaml) werden die folgenden Ressourcen definiert, um die disaggregierte Bereitstellung von Prefill und Decodierung über die beiden 2x2x2-TPU7x-Knotenpools hinweg zu koordinieren:

  • StorageClass (hyperdisk-balanced-tpu): stellt sitzungsspezifische 700-GiB-ReadWriteOnce-Volumes bereit, die von Google Cloud Hyperdisk Balanced-Speicher unterstützt werden. Jeder der vier Pods für die Vorbefüllung und Decodierung stellt ein eigenes Volume unter /data bereit, um den heruntergeladenen Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8-Prüfpunkt lokal zu speichern.
  • Prefill-Pool (sglang-prefill-service und sglang-tpu-prefill): Führt ein LeaderWorkerSet von size: 2 (ein Leader-Pod und ein Worker-Pod) aus, das ausschließlich an einen 2x2x2-TPU7x-Knotenpool (acht TPU-Chips, die 16 TensorCores bereitstellen) gebunden ist. Das LeaderWorkerSet verwendet die Annotation leaderworkerset.sigs.k8s.io/exclusive-topology, die auf "cloud.google.com/gke-nodepool" festgelegt ist. Die Pods starten sglang.launch_server mit den Flags --disaggregation-mode=prefill, --tensor-parallel-size=16 und --ep-size=16 und stellen den HTTP-Port 8000 und den Bootstrap-Port 8998 bereit.
  • Decodierungspool (sglang-decode-service und sglang-tpu-decode): Führt ein LeaderWorkerSet von size: 2 aus, das an den zweiten 2x2x2-TPU7x-Knotenpool (acht TPU-Chips, die 16 TensorCores bereitstellen) angehängt ist. Das LeaderWorkerSet startet sglang.launch_server mit den Flags --disaggregation-mode=decode, --tensor-parallel-size=16 und --ep-size=16.
  • Disaggregationsrouter (sglang-router und sglang-service): Führt ein CPU-Deployment aus, das das sglang_router.launch_router-Modul mit dem Flag --pd-disaggregation ausführt und einen ClusterIP-Dienst auf Port 8000 bereitstellt. Der Router leitet Prompts weiter und koordiniert die KV-Cache-Übertragung zwischen den Diensten sglang-prefill-service und sglang-decode-service.

So stellen Sie die SGLang-Server mit mehreren Hosts bereit und überwachen sie:

  1. Laden Sie das Arbeitslastmanifest herunter:

    curl -LO https://raw.githubusercontent.com/GoogleCloudSamples/AIHypercomputerSamples/main/tpu/inference/qwen3-coder/qwen3-coder-480b-multihost-disagg-v7x.yaml

    Alternativ können Sie eine Datei mit dem Namen qwen3-coder-480b-multihost-disagg-v7x.yaml und folgendem Inhalt erstellen:

    # ==============================================================================
    # Serve Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8 on GKE / Ironwood (TPU v7x)
    # using SGLang TorchTPU with Prefill/Decode Disaggregation, multi-host
    # ==============================================================================
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: hyperdisk-balanced-tpu
    provisioner: pd.csi.storage.gke.io
    volumeBindingMode: WaitForFirstConsumer
    allowVolumeExpansion: true
    parameters:
      type: hyperdisk-balanced
    ---
    # ==============================================================================
    # PREFILL POOL: Internal ClusterIP Service exposing SGLang Prefill Endpoint
    # ==============================================================================
    apiVersion: v1
    kind: Service
    metadata:
      name: sglang-prefill-service
      labels:
        app: sglang-prefill
    spec:
      type: ClusterIP
      selector:
        app: sglang-prefill
        role: leader
      ports:
        - name: http
          protocol: TCP
          port: 8000
          targetPort: 8000
        - name: bootstrap
          protocol: TCP
          port: 8998
          targetPort: 8998
    ---
    # ==============================================================================
    # PREFILL POOL: LeaderWorkerSet (TPU v7x, 1 slice = 2 nodes, 8 chips / 16 TensorCores)
    # ==============================================================================
    apiVersion: leaderworkerset.x-k8s.io/v1
    kind: LeaderWorkerSet
    metadata:
      name: sglang-tpu-prefill
      annotations:
        leaderworkerset.sigs.k8s.io/exclusive-topology: "cloud.google.com/gke-nodepool"
      labels:
        app: sglang-prefill
    spec:
      replicas: 1
      rolloutStrategy:
        type: RollingUpdate
      leaderWorkerTemplate:
        size: 2
        restartPolicy: RecreateGroupOnPodRestart
        leaderTemplate:
          metadata:
            labels:
              app: sglang-prefill
              role: leader
          spec: &prefill-pod-spec
            securityContext:
              fsGroup: 65534
            nodeSelector:
              cloud.google.com/gke-tpu-accelerator: tpu7x
              cloud.google.com/gke-tpu-topology: 2x2x2
            tolerations:
              - key: "google.com/tpu"
                operator: "Exists"
                effect: "NoSchedule"
            containers:
              - name: sglang
                image: $SGLANG_IMAGE
                command:
                  - /bin/bash
                  - -c
                  - |
                    set -ex
                    ulimit -c 0
                    LEADER_POD="${LWS_LEADER_ADDRESS%%.*}"
                    DNS_SUFFIX="${LWS_LEADER_ADDRESS#*.}"
                    HOSTS="${LWS_LEADER_ADDRESS}"
                    for ((i = 1; i < LWS_GROUP_SIZE; i++)); do
                      HOSTS="${HOSTS},${LEADER_POD}-${i}.${DNS_SUFFIX}"
                    done
                    export TPU_WORKER_HOSTNAMES="${HOSTS}"
                    export TPU_WORKER_ID="${LWS_WORKER_INDEX}"
                    export TPU_TOPOLOGY="${TPU_TOPOLOGY:-2x2x2}"
                    echo "=== [prefill rank ${LWS_WORKER_INDEX}/${LWS_GROUP_SIZE}] hosts=${TPU_WORKER_HOSTNAMES} ==="
                    exec python3 -m sglang.launch_server \
                      --device=tpu \
                      --host=0.0.0.0 \
                      --port=8000 \
                      --model-path=Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8 \
                      --tensor-parallel-size=16 \
                      --ep-size=16 \
                      --nnodes="${LWS_GROUP_SIZE}" \
                      --node-rank="${LWS_WORKER_INDEX}" \
                      --dist-init-addr="${LWS_LEADER_ADDRESS}:20000" \
                      --attention-backend=pallas_tpu_rpa_batched \
                      --mem-fraction-static=0.8 \
                      --max-running-requests=256 \
                      --chunked-prefill-size=8192 \
                      --max-total-tokens=786432 \
                      --context-length=9216 \
                      --enable-torch-compile \
                      --torch-compile-max-bs=256 \
                      --tpu-compile-tracer=direct \
                      --sampling-defaults=openai \
                      --enable-fused-qk-norm-rope \
                      --disaggregation-mode=prefill \
                      --disaggregation-transfer-backend=tpu \
                      --download-dir=/data \
                      --tpu-compile-tokens=8192 \
                      --disable-radix-cache
                env:
                  - name: HF_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                        optional: true
                resources:
                  requests:
                    cpu: "16"
                    memory: 128Gi
                    google.com/tpu: "4"
                  limits:
                    memory: 768Gi
                    google.com/tpu: "4"
                ports:
                  - containerPort: 8000
                    name: http
                  - containerPort: 8998
                    name: bootstrap
                startupProbe:
                  httpGet:
                    path: /health
                    port: 8000
                  initialDelaySeconds: 60
                  periodSeconds: 15
                  timeoutSeconds: 10
                  failureThreshold: 236
                readinessProbe:
                  httpGet:
                    path: /health
                    port: 8000
                  periodSeconds: 10
                  timeoutSeconds: 5
                  failureThreshold: 3
                volumeMounts:
                  - name: model-cache
                    mountPath: /data
                  - name: dshm
                    mountPath: /dev/shm
            volumes:
              - name: dshm
                emptyDir:
                  medium: Memory
                  sizeLimit: 32Gi
              - name: model-cache
                ephemeral:
                  volumeClaimTemplate:
                    spec:
                      accessModes: ["ReadWriteOnce"]
                      storageClassName: hyperdisk-balanced-tpu
                      resources:
                        requests:
                          storage: 700Gi
        workerTemplate:
          metadata:
            labels:
              app: sglang-prefill
              role: worker
          spec: *prefill-pod-spec
    ---
    # ==============================================================================
    # DECODE POOL: Internal ClusterIP Service exposing SGLang Decode Endpoint
    # ==============================================================================
    apiVersion: v1
    kind: Service
    metadata:
      name: sglang-decode-service
      labels:
        app: sglang-decode
    spec:
      type: ClusterIP
      selector:
        app: sglang-decode
        role: leader
      ports:
        - name: http
          protocol: TCP
          port: 8000
          targetPort: 8000
        - name: bootstrap
          protocol: TCP
          port: 8998
          targetPort: 8998
    ---
    # ==============================================================================
    # DECODE POOL: LeaderWorkerSet (TPU v7x, 1 slice = 2 nodes, 8 chips / 16 TensorCores)
    # ==============================================================================
    apiVersion: leaderworkerset.x-k8s.io/v1
    kind: LeaderWorkerSet
    metadata:
      name: sglang-tpu-decode
      annotations:
        leaderworkerset.sigs.k8s.io/exclusive-topology: "cloud.google.com/gke-nodepool"
      labels:
        app: sglang-decode
    spec:
      replicas: 1
      rolloutStrategy:
        type: RollingUpdate
      leaderWorkerTemplate:
        size: 2
        restartPolicy: RecreateGroupOnPodRestart
        leaderTemplate:
          metadata:
            labels:
              app: sglang-decode
              role: leader
          spec: &decode-pod-spec
            securityContext:
              fsGroup: 65534
            nodeSelector:
              cloud.google.com/gke-tpu-accelerator: tpu7x
              cloud.google.com/gke-tpu-topology: 2x2x2
            tolerations:
              - key: "google.com/tpu"
                operator: "Exists"
                effect: "NoSchedule"
            containers:
              - name: sglang
                image: $SGLANG_IMAGE
                command:
                  - /bin/bash
                  - -c
                  - |
                    set -ex
                    ulimit -c 0
                    LEADER_POD="${LWS_LEADER_ADDRESS%%.*}"
                    DNS_SUFFIX="${LWS_LEADER_ADDRESS#*.}"
                    HOSTS="${LWS_LEADER_ADDRESS}"
                    for ((i = 1; i < LWS_GROUP_SIZE; i++)); do
                      HOSTS="${HOSTS},${LEADER_POD}-${i}.${DNS_SUFFIX}"
                    done
                    export TPU_WORKER_HOSTNAMES="${HOSTS}"
                    export TPU_WORKER_ID="${LWS_WORKER_INDEX}"
                    export TPU_TOPOLOGY="${TPU_TOPOLOGY:-2x2x2}"
                    echo "=== [decode rank ${LWS_WORKER_INDEX}/${LWS_GROUP_SIZE}] hosts=${TPU_WORKER_HOSTNAMES} ==="
                    exec python3 -m sglang.launch_server \
                      --device=tpu \
                      --host=0.0.0.0 \
                      --port=8000 \
                      --model-path=Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8 \
                      --tensor-parallel-size=16 \
                      --ep-size=16 \
                      --nnodes="${LWS_GROUP_SIZE}" \
                      --node-rank="${LWS_WORKER_INDEX}" \
                      --dist-init-addr="${LWS_LEADER_ADDRESS}:20000" \
                      --attention-backend=pallas_tpu_rpa_batched \
                      --mem-fraction-static=0.8 \
                      --max-running-requests=256 \
                      --chunked-prefill-size=8192 \
                      --max-total-tokens=786432 \
                      --context-length=9216 \
                      --enable-torch-compile \
                      --torch-compile-max-bs=256 \
                      --tpu-compile-tracer=direct \
                      --sampling-defaults=openai \
                      --enable-fused-qk-norm-rope \
                      --disaggregation-mode=decode \
                      --disaggregation-transfer-backend=tpu \
                      --download-dir=/data
                env:
                  - name: HF_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                        optional: true
                resources:
                  requests:
                    cpu: "16"
                    memory: 128Gi
                    google.com/tpu: "4"
                  limits:
                    memory: 768Gi
                    google.com/tpu: "4"
                ports:
                  - containerPort: 8000
                    name: http
                  - containerPort: 8998
                    name: bootstrap
                startupProbe:
                  httpGet:
                    path: /health
                    port: 8000
                  initialDelaySeconds: 60
                  periodSeconds: 15
                  timeoutSeconds: 10
                  failureThreshold: 236
                readinessProbe:
                  httpGet:
                    path: /health
                    port: 8000
                  periodSeconds: 10
                  timeoutSeconds: 5
                  failureThreshold: 3
                volumeMounts:
                  - name: model-cache
                    mountPath: /data
                  - name: dshm
                    mountPath: /dev/shm
            volumes:
              - name: dshm
                emptyDir:
                  medium: Memory
                  sizeLimit: 32Gi
              - name: model-cache
                ephemeral:
                  volumeClaimTemplate:
                    spec:
                      accessModes: ["ReadWriteOnce"]
                      storageClassName: hyperdisk-balanced-tpu
                      resources:
                        requests:
                          storage: 700Gi
        workerTemplate:
          metadata:
            labels:
              app: sglang-decode
              role: worker
          spec: *decode-pod-spec
    ---
    # ==============================================================================
    # SGLANG DISAGGREGATION ROUTER / PROXY DEPLOYMENT
    # ==============================================================================
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sglang-router
      labels:
        app: sglang-router
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: sglang-router
      template:
        metadata:
          labels:
            app: sglang-router
        spec:
          containers:
            - name: router
              image: $SGLANG_IMAGE
              command:
                - python3
                - -m
                - sglang_router.launch_router
              args:
                - --pd-disaggregation
                - --prefill
                - http://sglang-prefill-service:8000
                - "8998"
                - --decode
                - http://sglang-decode-service:8000
                - --host
                - 0.0.0.0
                - --port
                - "8000"
                - --model-path
                - Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8
                - --request-timeout-secs
                - "3600"
                - --worker-startup-timeout-secs
                - "5400"
              env:
                - name: HF_TOKEN
                  valueFrom:
                    secretKeyRef:
                      name: hf-secret
                      key: hf_api_token
                      optional: true
              ports:
                - containerPort: 8000
                  name: http
              readinessProbe:
                httpGet:
                  path: /health_generate
                  port: 8000
                initialDelaySeconds: 15
                periodSeconds: 30
                timeoutSeconds: 10
                failureThreshold: 3
              resources:
                requests:
                  cpu: "1"
                  memory: 4Gi
                limits:
                  cpu: "4"
                  memory: 12Gi
    ---
    # ==============================================================================
    # SGLANG EXTERNAL SERVICE: Public / Client Endpoint for OpenAI-compatible Serving
    # ==============================================================================
    apiVersion: v1
    kind: Service
    metadata:
      name: sglang-service
      labels:
        app: sglang-router
    spec:
      type: ClusterIP
      selector:
        app: sglang-router
      ports:
        - name: http
          protocol: TCP
          port: 8000
          targetPort: 8000
  2. Wenden Sie das Arbeitslastmanifest auf Ihren Cluster an:

    envsubst '$SGLANG_IMAGE' < qwen3-coder-480b-multihost-disagg-v7x.yaml | kubectl apply -f -
  3. Prüfen Sie, ob die Router-, Prefill- und Decodierungs-Pods erstellt wurden:

    kubectl get pods

    Wenn alle Pods bereit sind, sieht die Ausgabe in etwa so aus:

    NAME                             READY   STATUS    RESTARTS   AGE
    sglang-router-6d87cb8c7d-gv4wr   1/1     Running   0          39m
    sglang-tpu-decode-0              1/1     Running   0          40m
    sglang-tpu-decode-0-1            1/1     Running   0          40m
    sglang-tpu-prefill-0             1/1     Running   0          40m
    sglang-tpu-prefill-0-1           1/1     Running   0          40m
    
  4. Überwachen Sie die Logs des Prefill- und Decode-Leader-Pods, bis der Startvorgang abgeschlossen ist:

    kubectl logs -f -l role=leader --prefix=true &
    LOG_PID=$!
    kubectl wait --for=condition=Ready --timeout=3600s pod -l role=leader
    kill "${LOG_PID}" 2>/dev/null || true

    Der erste Modelldownload, das Laden der Gewichtungen und die Kompilierung dauern beim ersten Durchlauf etwa 15 bis 30 Minuten.

    Wenn Sie Kapazität auf Abruf wie Spot-Kapazität oder Flex-Start-VMs verwenden, kann es nach dem Erstellen des Knotenpools länger dauern, bis Ihre TPU-Slice-Knoten erstellt werden. Außerdem können sie während der Ausführung von Arbeitslasten vorzeitig beendet werden. Weitere Informationen finden Sie unter VM-Instanzen auf Abruf. Informationen zum Prüfen, ob Ihre TPU-Slice-Knoten erstellt wurden, finden Sie unter Status und Bedingungen des Knotens prüfen.

    Warten Sie, bis in den Logs der Leader-Pods für Vorbefüllung und Decodierung die folgende Meldung ausgegeben wird und kubectl get pods für alle Pods 1/1 in der Spalte READY anzeigt:

    The server is fired up and ready to roll!
    
  5. Öffnen Sie eine zweite Terminalsitzung und leiten Sie den lokalen Port 8000 an sglang-service weiter:

    kubectl port-forward service/sglang-service 8000:8000

    Lassen Sie die Portweiterleitung in dieser Terminalsitzung laufen.

Inferenzanfragen senden

Kehren Sie zur ersten Terminalsitzung zurück und senden Sie eine Anfrage zur Chatvervollständigung an den vom SGLang-Router bereitgestellten Endpunkt /v1/chat/completions:

curl -s -X POST http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8",
    "messages": [
      {"role": "user", "content": "Explain quicksort in two sentences."}
    ],
    "max_tokens": 60,
    "temperature": 0.0
  }'

Benchmark-Arbeitslast ausführen

Führen Sie den folgenden Befehl aus, um das bereitgestellte Qwen3-Coder-Modell mit einer Arbeitslast von 1.024 Token Eingabe und 1.024 Token Ausgabe (1k/1k) vom Pod sglang-router zu benchmarken:

kubectl exec deployment/sglang-router -- python3 -m sglang.bench_serving \
  --backend sglang \
  --base-url http://localhost:8000 \
  --model Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8 \
  --dataset-name random \
  --random-input-len 1024 \
  --random-output-len 1024 \
  --random-range-ratio 1.0 \
  --num-prompts 256 \
  --max-concurrency 64

Bereinigen

Wenn Sie vermeiden möchten, dass Ihrem Google Cloud -Konto die in dieser Anleitung verwendeten Ressourcen in Rechnung gestellt werden, löschen Sie die folgenden Ressourcen:

  1. Löschen Sie die SGLang-Arbeitslasten für Vorbefüllung, Decodierung und Router:

    kubectl delete -f qwen3-coder-480b-multihost-disagg-v7x.yaml --ignore-not-found
  2. Löschen Sie die TPU7x-Knotenpools, die Richtlinie für die Arbeitslastplatzierung und den GKE-Cluster:

    gcloud container node-pools delete tpu7x-pool-0 \
        --cluster=${CLUSTER_NAME} \
        --location=${REGION} \
        --project=${PROJECT_ID} \
        --quiet
    
    gcloud container node-pools delete tpu7x-pool-1 \
        --cluster=${CLUSTER_NAME} \
        --location=${REGION} \
        --project=${PROJECT_ID} \
        --quiet
    
    gcloud container clusters delete ${CLUSTER_NAME} \
        --location=${REGION} \
        --project=${PROJECT_ID} \
        --quiet
    
    gcloud compute resource-policies delete tpu7x-2x2x2-workload-policy \
        --region=${REGION} \
        --project=${PROJECT_ID} \
        --quiet

Nächste Schritte