Menyajikan Qwen3-30B-A3B di GKE dengan TorchTPU vLLM di TPU v6e

Tutorial ini menunjukkan cara men-deploy dan menyajikan model mixture of experts Qwen3-30B-A3B (Qwen/Qwen3-30B-A3B-FP8) di Google Kubernetes Engine (GKE) menggunakan akselerator TPU v6e (Trillium) host tunggal dan framework penyajian TPU vLLM dengan TorchTPU (torchtpu). Anda akan menjalankan workload pada satu node ct6e-standard-4t, yang berisi empat chip TPU v6e dalam topologi 2x2, dengan paralelisme data dan paralelisme expert diaktifkan.

Untuk menjalankan alur kerja penyajian TorchTPU vLLM host tunggal yang serupa di akselerator TPU7x (Ironwood) dengan model Qwen3.5-397B yang lebih besar, lihat Menyajikan Qwen3.5-397B di GKE dengan TorchTPU vLLM di akselerator TPU7x.

Tujuan

  • Siapkan cluster GKE dan node pool TPU v6e host tunggal.
  • Men-deploy server TorchTPU vLLM host tunggal di GKE.
  • Kirim permintaan inferensi ke server TorchTPU vLLM.
  • Menjalankan workload benchmark inferensi.
  • Jalankan pembersihan.

Biaya

Dalam dokumen ini, Anda akan menggunakan komponenGoogle Cloudyang dapat ditagih berikut:

Untuk membuat perkiraan biaya berdasarkan proyeksi penggunaan Anda, gunakan kalkulator harga.

Setelah menyelesaikan tugas yang dijelaskan dalam dokumen ini, Anda dapat menghindari penagihan berkelanjutan dengan menghapus resource yang Anda buat. Untuk mengetahui informasi selengkapnya, lihat Pembersihan.

Sebelum memulai

Siapkan lingkungan Anda untuk tutorial:

Mendapatkan token akses Hugging Face

Anda memerlukan token akses Hugging Face untuk menggunakan tutorial ini. Anda dapat mendaftar untuk mendapatkan akun gratis di Hugging Face. Setelah Anda memiliki akun, buat token akses:

  1. Di halaman Welcome to Hugging Face, klik avatar akun Anda, lalu pilih Token akses.
  2. Di halaman Token akses, klik Create new token.
  3. Pilih jenis token Read dan masukkan nama untuk token Anda.
  4. Token akses Anda akan ditampilkan. Simpan token di tempat yang aman.

Peran yang diperlukan

Untuk mendapatkan izin yang Anda perlukan untuk menyelesaikan tutorial ini, minta administrator untuk memberi Anda peran IAM berikut di project Anda:

Untuk mengetahui informasi selengkapnya tentang pemberian peran, lihat Mengelola akses ke project, folder, dan organisasi.

Anda mungkin juga bisa mendapatkan izin yang diperlukan melalui peran khusus atau peran bawaan lainnya.

Menyiapkan variabel lingkungan Anda

Siapkan autentikasi Anda:

gcloud auth login
gcloud auth application-default login

Siapkan variabel lingkungan Anda:

export PROJECT_ID="YOUR_PROJECT_ID"
export REGION="YOUR_REGION"
export ZONE="YOUR_ZONE"
export CLUSTER_NAME="YOUR_CLUSTER_NAME"
export MACHINE_TYPE="tpu7x-standard-4t"
export NODE_POOL_NAME="np-0"
export RESERVATION_NAME="YOUR_RESERVATION_NAME"
export HF_TOKEN="YOUR_HF_TOKEN"
export NETWORK="YOUR_NETWORK_NAME"
export SUBNETWORK="YOUR_SUBNETWORK_NAME"
export VLLM_IMAGE="YOUR_VLLM_TPU_IMAGE"

gcloud config set project "${PROJECT_ID}"
gcloud config set billing/quota_project "${PROJECT_ID}"

Ganti kode berikut:

  • YOUR_PROJECT_ID: ID project Google Cloud Anda.
  • YOUR_REGION: region tempat Anda ingin men-deploy cluster, seperti us-central1.
  • YOUR_ZONE: zona tempat Anda ingin men-deploy node pool TPU v6e, seperti us-central1-c.
  • YOUR_CLUSTER_NAME: nama cluster GKE Anda, seperti tpu-v6e-tutorial-cluster.
  • YOUR_RESERVATION_NAME: jika Anda menggunakan pemesanan, nama pemesanan TPU v6e Anda.
  • YOUR_HF_TOKEN: token akses Hugging Face Anda.
  • YOUR_NETWORK_NAME: nama jaringanGoogle Cloud Anda. Jika Anda membuat jaringan kustom, tentukan jaringan tersebut. Jika tidak, tentukan default.
  • YOUR_SUBNETWORK_NAME: nama subnetworkGoogle Cloud Anda. Jika Anda membuat subnetwork kustom, tentukan subnetwork tersebut. Jika tidak, tentukan default.
  • YOUR_VLLM_TPU_IMAGE: image TorchTPU vLLM yang akan digunakan. Untuk image publik, lihat repositori vLLM TorchTPU.

Membuat cluster GKE

Untuk membuat cluster GKE dalam mode Standard dan memasang node pool TPU v6e host tunggal, selesaikan langkah-langkah berikut:

  1. Buat cluster GKE regional:

    gcloud container clusters create "${CLUSTER_NAME}" \
        --project="${PROJECT_ID}" \
        --location="${REGION}" \
        --node-locations="${ZONE}" \
        --network="${NETWORK}" \
        --subnetwork="${SUBNETWORK}"

    Jenis mesin default untuk cluster GKE (e2-medium) tidak memiliki kapasitas CPU yang memadai untuk pengontrol workload, sehingga perintah ini menentukan e2-standard-4.

    Outputnya mirip dengan hal berikut ini:

    NAME                      LOCATION     MASTER_VERSION      MASTER_IP      MACHINE_TYPE   NODE_VERSION        NUM_NODES  STATUS
    tpu-v6e-tutorial-cluster  us-central1  1.35.7-gke.1027000  34.63.222.246  e2-standard-4  1.35.7-gke.1027000  3          RUNNING
    
  2. Buat node pool TPU v6e host tunggal dengan satu node ct6e-standard-4t (empat chip TPU v6e dalam topologi 2x2) menggunakan pemesanan Anda:

    gcloud container node-pools create "${NODE_POOL_NAME}" \
        --cluster="${CLUSTER_NAME}" \
        --machine-type="${MACHINE_TYPE}" \
        --location="${REGION}" \
        --node-locations="${ZONE}" \
        --project="${PROJECT_ID}" \
        --num-nodes=1 \
        --reservation-affinity=specific \
        --reservation="${RESERVATION_NAME}"

    Alih-alih menggunakan pemesanan tertentu, Anda juga dapat membuat node pool menggunakan kapasitas Spot atau VM Flex-start dengan meneruskan flag berikut:

    • Spot VM: ganti flag --reservation-affinity dan --reservation dengan --spot untuk menggunakan kapasitas Spot. Instance yang menggunakan kapasitas Spot mungkin memerlukan waktu untuk dibuat setelah node pool dibuat, dan mungkin di-preempt selama workload berjalan. Jika Pod Anda memerlukan waktu untuk dibuat, atau workload berhenti di tengah proses, hal ini mungkin menjadi penyebabnya.
    • Flex-start VM: untuk menyediakan node pool menggunakan opsi konsumsi Flex-start, teruskan flag --flex-start. Untuk mengetahui informasi selengkapnya, lihat Menjalankan workload batch kecil dengan TPU dan Flex-start VM.

    Outputnya mirip dengan hal berikut ini:

    NAME  MACHINE_TYPE      DISK_SIZE_GB  NODE_VERSION
    np-0  ct6e-standard-4t  100           1.35.7-gke.1027000
    
  3. Konfigurasi kredensial kubectl untuk berkomunikasi dengan cluster Anda:

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

Mengonfigurasi kredensial

Buat Secret Kubernetes bernama hf-secret untuk menyimpan token akses Hugging Face Anda:

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

Men-deploy server TorchTPU vLLM

Manifes workload (qwen3_5_server.yaml) menentukan resource berikut:

  • StorageClass (hyperdisk-balanced-qwen3) dan PersistentVolumeClaim (hd-claim-qwen3) 500 GiB yang didukung oleh penyimpanan Google Cloud Hyperdisk Balanced untuk menyimpan bobot model yang didownload, cache kompilasi XLA, dan cache kompilasi PyTorch.

  • Deployment (vllm-qwen3) yang dijadwalkan pada satu node TPU v6e dengan topologi 2x2 (google.com/tpu: '4'). Container menjalankan vllm serve untuk Qwen/Qwen3-30B-A3B-FP8 dengan flag berikut:

    • --data-parallel-size=4
    • --tensor-parallel-size=1
    • --enable-expert-parallel
    • --kv-cache-dtype=fp8
    • --max-model-len=9236
    • --max-num-seqs=64.
  • Layanan ClusterIP (vllm-qwen3-service) yang mengekspos port 8000.

Untuk men-deploy dan memantau workload, selesaikan langkah-langkah berikut:

  1. Ambil manifes server:

    curl -O https://raw.githubusercontent.com/GoogleCloudSamples/AIHypercomputerSamples/refs/heads/main/tpu/inference/qwen3-5-397b/qwen3_5_server.yaml

    Atau, Anda dapat memilih untuk membuat file bernama qwen3_5_server.yaml dengan konten berikut:

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: hyperdisk-balanced-qwen3-5
    provisioner: pd.csi.storage.gke.io
    parameters:
      type: hyperdisk-balanced
    reclaimPolicy: Delete
    volumeBindingMode: WaitForFirstConsumer
    allowVolumeExpansion: true
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: hd-claim-qwen3-5
      namespace: default
    spec:
      storageClassName: hyperdisk-balanced-qwen3-5
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 1500Gi
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: vllm-qwen3-5
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: vllm-qwen3-5
      template:
        metadata:
          labels:
            app: vllm-qwen3-5
        spec:
          nodeSelector:
            cloud.google.com/gke-tpu-accelerator: tpu7x
            cloud.google.com/gke-tpu-topology: 2x2x1
          tolerations:
          - key: "cloud.google.com/gke-spot"
            operator: "Equal"
            value: "true"
            effect: "NoSchedule"
          containers:
          - name: vllm-tpu
            image: $VLLM_IMAGE
            command: ["vllm", "serve"]
            args:
            - --host=0.0.0.0
            - --port=8000
            - --model=Qwen/Qwen3.5-397B-A17B-FP8
            - --tokenizer=Qwen/Qwen3.5-397B-A17B-FP8
            - --max-model-len=9236
            - --max-num-batched-tokens=1024
            - --max-num-seqs=64
            - --no-enable-prefix-caching
            - --gpu-memory-utilization=0.9
            - --data-parallel-size=8
            - --tensor-parallel-size=1
            - --async-scheduling
            - --language-model-only
            - --enable-auto-tool-choice
            - --tool-call-parser=qwen3_coder
            - --reasoning-parser=qwen3
            - '--limit-mm-per-prompt={"image": 0, "video": 0}'
            - --kv-cache-dtype=fp8
            - --enable-expert-parallel
            - --download-dir=/data
            - --block-size=128
            env:
            - name: MODEL_IMPL_TYPE
              value: "vllm"
            - name: DP_SCHED_ENABLED
              value: "1"
            - name: ONEHOT_MOE_PERMUTE_THRESHOLD
              value: "32768"
            - name: VLLM_ENGINE_READY_TIMEOUT_S
              value: "9600"
            - name: VLLM_ENGINE_ITERATION_TIMEOUT_S
              value: "1800"
            - name: USE_MOE_SPARSE_CORE
              value: "1"
            - name: TPU_MOE_SKIP_PADDED_TOKENS
              value: "1"
            - name: VLLM_CACHE_ROOT
              value: "/data/vllm_cache"
            - name: VLLM_TORCH_COMPILE_CACHE_DIR
              value: "/data/torch_compile_cache"
            - name: XLA_CACHE_DIR
              value: "/data/xla_cache"
            - name: HF_HOME
              value: /data
            - name: HF_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_api_token
            ports:
            - containerPort: 8000
            resources:
              limits:
                google.com/tpu: '4'
              requests:
                google.com/tpu: '4'
            readinessProbe:
              tcpSocket:
                port: 8000
              initialDelaySeconds: 15
              periodSeconds: 10
            volumeMounts:
            - mountPath: "/data"
              name: data-volume
            - mountPath: /dev/shm
              name: dshm
          volumes:
          - emptyDir:
              medium: Memory
            name: dshm
          - name: data-volume
            persistentVolumeClaim:
              claimName: hd-claim-qwen3-5
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: vllm-qwen3-5-service
      namespace: default
    spec:
      selector:
        app: vllm-qwen3-5
      type: ClusterIP
      ports:
      - name: http
        protocol: TCP
        port: 8000
        targetPort: 8000
  2. Terapkan manifes server vLLM TorchTPU ke cluster Anda:

    envsubst '$VLLM_IMAGE' < "qwen3_5_server.yaml" | kubectl apply -f -
  3. Pantau log deployment server hingga startup aplikasi selesai:

    kubectl wait --for=jsonpath='{.status.phase}'=Running pod -l app=vllm-qwen3-5 --timeout=900s
    kubectl logs deployment/vllm-qwen3-5 -c vllm-tpu -f

    Startup layanan awal mungkin memerlukan waktu sekitar 15 hingga 30 menit saat Pod mendownload bobot model dan mengompilasi model.

    Jika Anda menggunakan kapasitas preemptive seperti Spot atau Flex-start, mungkin perlu waktu lebih lama setelah pembuatan node pool untuk membuat node slice TPU, dan node tersebut dapat di-preempt selama eksekusi workload. Jika Pod Anda memerlukan waktu lebih lama dari yang diperkirakan untuk memulai, atau workload Anda berhenti di tengah jalan, hal ini bisa menjadi penyebabnya. Untuk mengetahui informasi selengkapnya, baca Preemption Spot VM. Untuk memeriksa apakah node slice TPU Anda telah dibuat, lihat Memeriksa status dan kondisi node.

    Tunggu hingga log melaporkan Application startup complete sebelum Anda mengirim traffic:

    (APIServer pid=1) INFO:     Started server process [1]
    (APIServer pid=1) INFO:     Waiting for application startup.
    (APIServer pid=1) INFO:     Application startup complete.
    
  4. Buka sesi terminal kedua.

  5. Di sesi terminal kedua, teruskan port lokal 8000 ke vllm-qwen3-service:

    kubectl port-forward service/vllm-qwen3-5-service 8000:8000

    Biarkan penerusan port berjalan di sesi terminal ini.

Mengirim permintaan inferensi

Kembali ke sesi terminal pertama Anda dan kirim permintaan penyelesaian chat ke endpoint /v1/chat/completions:

curl http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "Qwen/Qwen3.5-397B-A17B-FP8",
        "messages": [
            {"role": "user", "content": "Hello! Tell me a joke."}
        ],
        "max_tokens": 512,
        "temperature": 0.7
    }' | jq .

Menjalankan workload benchmark

Untuk melakukan tolok ukur model Qwen3-30B-A3B yang di-deploy menggunakan workload input 8.192 token dan output 1.024 token (8k/1k) dengan InferenceX benchmark suite, selesaikan langkah-langkah berikut:

  1. Ambil manifes benchmark:

    curl -O https://raw.githubusercontent.com/GoogleCloudSamples/AIHypercomputerSamples/refs/heads/main/tpu/inference/qwen3-5-397b/qwen3_5-benchmark-8k1k.yaml

    Atau, buat file bernama qwen3_5-benchmark-8k1k.yaml dengan konten berikut:

    apiVersion: v1
    kind: Pod
    metadata:
      name: qwen3-5-bench-8k1k
      namespace: default
    spec:
      restartPolicy: OnFailure
      terminationGracePeriodSeconds: 60
      containers:
      - name: vllm-bench
        image: $VLLM_IMAGE
        command: ["/bin/bash", "-c"]
        args:
        - |
          while ! curl http://vllm-qwen3-5-service:8000/ping; do sleep 30 && echo 'Waiting for server...'; done
          apt-get update && apt-get install -y git && \
          git clone https://github.com/SemiAnalysisAI/InferenceX.git /ubench/inferencex && \
          cd /ubench/inferencex && \
          git checkout 89ce6098ef2bc4576a735c43f39c7d972b091cfc && \
          python3 /ubench/inferencex/utils/bench_serving/benchmark_serving.py \
            --backend=vllm \
            --percentile-metrics='ttft,tpot,itl,e2el' \
            --host=vllm-qwen3-5-service \
            --port=8000 \
            --model=Qwen/Qwen3.5-397B-A17B-FP8 \
            --tokenizer=Qwen/Qwen3.5-397B-A17B-FP8 \
            --dataset-name=random \
            --random-input-len=8192 \
            --random-output-len=1024 \
            --random-range-ratio=1.0 \
            --num-prompts=2560 \
            --num-warmups=512 \
            --max-concurrency=256 \
            --ignore-eos
        env:
        - name: HUGGING_FACE_HUB_TOKEN
          valueFrom:
            secretKeyRef:
              key: hf_api_token
              name: hf-secret
  2. Terapkan manifes Pod benchmark:

    envsubst '$VLLM_IMAGE' < "qwen3_5-benchmark-8k1k.yaml" | kubectl apply -f -
  3. Pantau log tolok ukur:

    kubectl wait --for=jsonpath='{.status.phase}'=Running pod --field-selector=metadata.name=qwen3-5-bench-8k1k --timeout=600s
    kubectl logs -f qwen3-5-bench-8k1k

    Benchmark memerlukan waktu sekitar 25 hingga 30 menit untuk diselesaikan.

  4. Setelah benchmark selesai, cari output yang berisi metrik seperti berikut:

    • Output token throughput
    • Total token throughput
    • TTFT
    • TPOT

Pembersihan

Agar tidak menimbulkan biaya berkelanjutan tambahan pada akun Google Cloud Anda untuk resource yang digunakan dalam tutorial ini, hapus workload Kubernetes, TPU node pool, dan cluster GKE:

  1. Hapus Deployment, Service, PersistentVolumeClaim, dan Secret Hugging Face server vLLM TorchTPU:

    kubectl delete -f qwen3_5_server.yaml --ignore-not-found || true
    kubectl delete secret hf-secret --ignore-not-found || true
  2. Hapus node pool TPU v6e dan cluster GKE:

    gcloud container node-pools delete "${NODE_POOL_NAME}" \
        --cluster="${CLUSTER_NAME}" \
        --location="${REGION}" \
        --project="${PROJECT_ID}" \
        --quiet || true
    
    gcloud container clusters delete "${CLUSTER_NAME}" \
        --location="${REGION}" \
        --project="${PROJECT_ID}" \
        --quiet || true

Langkah berikutnya