Utilizzare vLLM su GKE per eseguire l'inferenza con Qwen3

Questo tutorial mostra come eseguire il deployment e pubblicare un modello linguistico di grandi dimensioni (LLM) Qwen3 con il framework di pubblicazione vLLM. Esegui il deployment del modello su una singola istanza di macchina virtuale A4 (VM) su Google Kubernetes Engine (GKE).

Questo tutorial è rivolto a machine learning (ML) engineer, amministratori e operatori di piattaforme e specialisti di dati e AI interessati a utilizzare le funzionalità di orchestrazione dei container Kubernetes per gestire i carichi di lavoro di inferenza.

Obiettivi

  1. Accedi a Qwen3 utilizzando Hugging Face.

  2. Prepara l'ambiente.

  3. Creare un cluster GKE in modalità Autopilot.

  4. Creare un bucket Cloud Storage.

  5. Crea un secret Kubernetes per le credenziali di Hugging Face.

  6. Configura la federazione delle identità per i workload per Cloud Storage.

  7. Riempi il bucket Cloud Storage con il modello Qwen3.

  8. Esegui il deployment di un container vLLM in GKE.

  9. Interagisci con Qwen3 utilizzando curl.

  10. Eseguire la pulizia.

Costi

Questo tutorial utilizza componenti fatturabili di Google Cloud, tra cui:

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il Calcolatore prezzi.

Prima di iniziare

  1. Accedi al tuo account Google Cloud . Se non conosci Google Cloud, crea un account per valutare le prestazioni dei nostri prodotti in scenari reali. I nuovi clienti ricevono anche 300 $di crediti senza costi per l'esecuzione, il test e il deployment dei carichi di lavoro.
  2. Installa Google Cloud CLI.

  3. Se utilizzi un provider di identità (IdP) esterno, devi prima accedere a gcloud CLI con la tua identità federata.

  4. Per inizializzare gcloud CLI, esegui questo comando:

    gcloud init
  5. Crea o seleziona un Google Cloud progetto.

    Ruoli richiesti per selezionare o creare un progetto

    • Seleziona un progetto: la selezione di un progetto non richiede un ruolo IAM specifico. Puoi selezionare qualsiasi progetto per il quale ti è stato concesso un ruolo.
    • Crea un progetto: per creare un progetto, devi disporre del ruolo Autore progetto (roles/resourcemanager.projectCreator), che contiene l'autorizzazione resourcemanager.projects.create. Scopri come concedere i ruoli.
    • Creare un progetto Google Cloud :

      gcloud projects create PROJECT_ID

      Sostituisci PROJECT_ID con un nome per il progetto Google Cloud che stai creando.

    • Seleziona il progetto Google Cloud che hai creato:

      gcloud config set project PROJECT_ID

      Sostituisci PROJECT_ID con il nome del progetto Google Cloud .

  6. Verifica che la fatturazione sia attivata per il tuo progetto Google Cloud .

  7. Abilita l'API richiesta:

    Ruoli richiesti per abilitare le API

    Per abilitare le API, devi disporre dell'autorizzazione serviceusage.services.enable. Se hai creato il progetto, probabilmente disponi già di questa autorizzazione tramite il ruolo Proprietario (roles/owner). In caso contrario, puoi ottenere questa autorizzazione tramite il ruolo Amministratore utilizzo dei servizi (roles/serviceusage.serviceUsageAdmin). Scopri come concedere i ruoli.

    gcloud services enable container.googleapis.com
  8. Installa Google Cloud CLI.

  9. Se utilizzi un provider di identità (IdP) esterno, devi prima accedere a gcloud CLI con la tua identità federata.

  10. Per inizializzare gcloud CLI, esegui questo comando:

    gcloud init
  11. Crea o seleziona un Google Cloud progetto.

    Ruoli richiesti per selezionare o creare un progetto

    • Seleziona un progetto: la selezione di un progetto non richiede un ruolo IAM specifico. Puoi selezionare qualsiasi progetto per il quale ti è stato concesso un ruolo.
    • Crea un progetto: per creare un progetto, devi disporre del ruolo Autore progetto (roles/resourcemanager.projectCreator), che contiene l'autorizzazione resourcemanager.projects.create. Scopri come concedere i ruoli.
    • Creare un progetto Google Cloud :

      gcloud projects create PROJECT_ID

      Sostituisci PROJECT_ID con un nome per il progetto Google Cloud che stai creando.

    • Seleziona il progetto Google Cloud che hai creato:

      gcloud config set project PROJECT_ID

      Sostituisci PROJECT_ID con il nome del progetto Google Cloud .

  12. Verifica che la fatturazione sia attivata per il tuo progetto Google Cloud .

  13. Abilita l'API richiesta:

    Ruoli richiesti per abilitare le API

    Per abilitare le API, devi disporre dell'autorizzazione serviceusage.services.enable. Se hai creato il progetto, probabilmente disponi già di questa autorizzazione tramite il ruolo Proprietario (roles/owner). In caso contrario, puoi ottenere questa autorizzazione tramite il ruolo Amministratore utilizzo dei servizi (roles/serviceusage.serviceUsageAdmin). Scopri come concedere i ruoli.

    gcloud services enable container.googleapis.com
  14. Concedi ruoli al tuo account utente. Esegui il seguente comando una volta per ciascuno dei seguenti ruoli IAM: roles/container.admin

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE

    Sostituisci quanto segue:

    • PROJECT_ID: il tuo ID progetto.
    • USER_IDENTIFIER: l'identificatore del tuo account utente . Ad esempio: myemail@example.com.
    • ROLE: il ruolo IAM che concedi al tuo account utente.
  15. Accedi o crea un account Hugging Face.

Accedere a Qwen3 utilizzando Hugging Face

Per utilizzare Hugging Face per accedere a Qwen3, segui questi passaggi:

  1. Accedere a Hugging Face
  2. Crea un token di accesso read di Hugging Face. Fai clic su Il tuo profilo > Impostazioni > Token di accesso > +Crea nuovo token.
  3. Specifica un nome a tua scelta per il token, quindi seleziona un ruolo. Il livello di autorizzazione del ruolo minimo che puoi selezionare per questo tutorial è Lettura.
  4. Seleziona Crea token.
  5. Copia e salva il token generato negli appunti. Lo utilizzerai più avanti in questo tutorial.

prepara l'ambiente

Per preparare l'ambiente, imposta le variabili di ambiente predefinite:

export PROJECT_ID="YOUR_PROJECT_ID"
export RESERVATION_NAME="YOUR_RESERVATION_NAME"
export REGION="YOUR_REGION"
export CLUSTER_NAME="YOUR_CLUSTER_NAME"
export GCS_BUCKET_NAME="YOUR_GCS_BUCKET"
export HUGGING_FACE_TOKEN="YOUR_HF_TOKEN"
export NETWORK="YOUR_NETWORK_NAME"
export SUBNETWORK="YOUR_SUBNETWORK_NAME"

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

Sostituisci quanto segue:

  • YOUR_PROJECT_ID: l'ID del progetto Google Cloud in cui vuoi creare il cluster GKE.

  • YOUR_RESERVATION_NAME: il nome della prenotazione che vuoi utilizzare per creare il cluster GKE. In base al progetto in cui esiste la prenotazione, specifica uno dei seguenti valori:

    • La prenotazione esiste nel tuo progetto: RESERVATION_NAME

    • La prenotazione esiste in un progetto diverso e il tuo progetto può utilizzarla: projects/RESERVATION_PROJECT_ID/reservations/RESERVATION_NAME

  • YOUR_REGION: la regione in cui vuoi creare il cluster GKE. Puoi creare il cluster solo nella regione in cui esiste la prenotazione.

  • YOUR_CLUSTER_NAME: il nome del cluster GKE da creare.

  • YOUR_BUCKET_NAME: il nome del bucket Cloud Storage regionale da creare.

  • YOUR_HF_TOKEN: il token di accesso Hugging Face che hai creato nella sezione precedente.

  • YOUR_NETWORK_NAME: la rete utilizzata dal cluster GKE. Specifica uno dei seguenti valori:

    • Se hai creato una rete personalizzata, specifica il nome della rete.

    • In caso contrario, specifica default.

  • YOUR_SUBNETWORK_NAME: la subnet utilizzata dal cluster GKE. Specifica uno dei seguenti valori:

    • Se hai creato una subnet personalizzata, specifica il nome della subnet. Puoi specificare solo una subnet che si trova nella stessa regione della prenotazione.

    • In caso contrario, specifica default.

Crea un cluster GKE in modalità Autopilot

Per creare un cluster GKE in modalità Autopilot, esegui questo comando:

gcloud container clusters create-auto "$CLUSTER_NAME" \
    --project="$PROJECT_ID" \
    --region="$REGION" \
    --release-channel=rapid \
    --network="$NETWORK" \
    --subnetwork="$SUBNETWORK"
La creazione del cluster GKE potrebbe richiedere un po' di tempo. Per verificare che Google Cloud abbia terminato la creazione del cluster, vai a Cluster Kubernetes nella console Google Cloud .

Crea un bucket Cloud Storage

Per creare un bucket Cloud Storage regionale in cui archiviare il modello, esegui questo comando:

gcloud storage buckets create gs://$GCS_BUCKET_NAME \
    --project=$PROJECT_ID \
    --location=$REGION

Crea un secret Kubernetes per le credenziali di Hugging Face

Per creare un secret Kubernetes per le credenziali di Hugging Face:

  1. Configura kubectl per comunicare con il cluster GKE:

    gcloud container clusters get-credentials "$CLUSTER_NAME" \
        --location="$REGION" \
        --project="$PROJECT_ID"
  2. Crea un secret di Kubernetes per archiviare il token Hugging Face:

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

Configura la federazione delle identità per i workload per Cloud Storage

Per consentire a GKE di accedere in modo sicuro al bucket Cloud Storage, configura la federazione delle identità per i workload per GKE:

gcloud iam service-accounts create qwen-gcs-sa \
    --project=$PROJECT_ID

gcloud storage buckets add-iam-policy-binding gs://$GCS_BUCKET_NAME \
    --member="serviceAccount:qwen-gcs-sa@$PROJECT_ID.iam.gserviceaccount.com" \
    --role="roles/storage.objectAdmin"

kubectl create serviceaccount qwen-ksa \
    --namespace=default

gcloud iam service-accounts add-iam-policy-binding qwen-gcs-sa@$PROJECT_ID.iam.gserviceaccount.com \
    --project=$PROJECT_ID \
    --role=roles/iam.workloadIdentityUser \
    --member="serviceAccount:$PROJECT_ID.svc.id.goog[default/qwen-ksa]"

kubectl annotate serviceaccount qwen-ksa \
    --namespace=default \
    iam.gke.io/gcp-service-account="qwen-gcs-sa@$PROJECT_ID.iam.gserviceaccount.com"

Popola il bucket Cloud Storage con i pesi del modello Qwen3

Per popolare il bucket Cloud Storage con i pesi del modello Qwen3, esegui un job Kubernetes che utilizza il driver CSI di Cloud Storage FUSE per montare il bucket come volume. Il job scarica il modello da Hugging Face se non esiste già nel bucket.

  1. Crea un file denominato qwen3-model-loader.yaml con i seguenti contenuti:

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: qwen3-model-loader
    spec:
      template:
        metadata:
          annotations:
            gke-gcsfuse/volumes: "true"
            gke-gcsfuse/cpu-limit: "0"
            gke-gcsfuse/memory-limit: "0"
            gke-gcsfuse/ephemeral-storage-limit: "0"
        spec:
          serviceAccountName: qwen-ksa
          restartPolicy: OnFailure
          containers:
          - name: downloader
            image: python:3.11-slim
            resources:
              requests:
                cpu: "4"
                memory: "16Gi"
                ephemeral-storage: "100Gi"
              limits:
                cpu: "4"
                memory: "16Gi"
                ephemeral-storage: "100Gi"
            command: ["/bin/sh", "-c"]
            args:
            - |
              pip install huggingface_hub
              python3 -c '
              import os
              from huggingface_hub import snapshot_download
              model_id = "Qwen/Qwen3-235B-A22B-Instruct-2507"
              local_dir = "/data/Qwen/Qwen3-235B-A22B-Instruct-2507"
              config_path = os.path.join(local_dir, "config.json")
              if os.path.exists(config_path):
                  print(f"Model already exists at {local_dir}. Skipping download.")
              else:
                  print(f"Downloading model {model_id} to {local_dir}...")
                  snapshot_download(
                      repo_id=model_id,
                      local_dir=local_dir,
                      local_dir_use_symlinks=False,
                      token=os.environ.get("HUGGING_FACE_HUB_TOKEN")
                  )
                  print("Download completed successfully!")
              '
            env:
            - name: HUGGING_FACE_HUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_token
            volumeMounts:
            - name: gcs-fuse-volume
              mountPath: /data
          volumes:
          - name: gcs-fuse-volume
            csi:
              driver: gcsfuse.csi.storage.gke.io
              volumeAttributes:
                bucketName: $GCS_BUCKET_NAME
                mountOptions: "implicit-dirs"
  2. Applica il manifest qwen3-model-loader.yaml per inizializzare il job di download:

    envsubst < qwen3-model-loader.yaml | kubectl apply -f -
  3. Per verificare che il job sia in esecuzione, trasmetti in streaming i log del job di download:

    kubectl logs -f job/qwen3-model-loader -c downloader
    
  4. Attendi il completamento del job di download del modello:

    kubectl wait \
        --for=condition=Complete \
        --timeout=1800s job/qwen3-model-loader
  5. Per eliminare il job, esegui questo comando:

    kubectl delete job qwen3-model-loader --ignore-not-found

Esegui il deployment di un container vLLM nel cluster GKE

Per eseguire il deployment del container vLLM per pubblicare il modello Qwen3 utilizzando i deployment Kubernetes, segui questi passaggi:

  1. Crea un file qwen3-235b-deploy.yaml con il deployment vLLM che hai scelto:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: vllm-qwen3-deployment
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: qwen3-server
      template:
        metadata:
          labels:
            app: qwen3-server
            ai.gke.io/model: Qwen3-235B-A22B-Instruct-2507
            ai.gke.io/inference-server: vllm
            examples.ai.gke.io/source: user-guide
        spec:
          serviceAccountName: qwen-ksa
          containers:
          - name: qwen-inference-server
            image: us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:20250801_0916_RC01
            resources:
              requests:
                cpu: "10"
                memory: "1000Gi"
                ephemeral-storage: "500Gi"
                nvidia.com/gpu: "8"
              limits:
                cpu: "10"
                memory: "1000Gi"
                ephemeral-storage: "500Gi"
                nvidia.com/gpu: "8"
            command: ["python3", "-m", "vllm.entrypoints.openai.api_server"]
            args:
            - --model=$(MODEL_ID)
            - --load-format=runai_streamer
            - --model-loader-extra-config={"distributed":true}
            - --tensor-parallel-size=8
            - --host=0.0.0.0
            - --port=8000
            - --max-model-len=8192
            - --max-num-seqs=4
            - --dtype=bfloat16
            env:
            - name: MODEL_ID
              value: "gs://$GCS_BUCKET_NAME/Qwen/Qwen3-235B-A22B-Instruct-2507"
            - name: HUGGING_FACE_HUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_token
            volumeMounts:
            - mountPath: /dev/shm
              name: dshm
            livenessProbe:
              httpGet:
                path: /health
                port: 8000
              initialDelaySeconds: 200
              periodSeconds: 10
            readinessProbe:
              httpGet:
                path: /health
                port: 8000
              initialDelaySeconds: 200
              periodSeconds: 5
          volumes:
          - name: dshm
            emptyDir:
              medium: Memory
          nodeSelector:
            cloud.google.com/gke-accelerator: nvidia-b200
            cloud.google.com/reservation-name: $RESERVATION_NAME
            cloud.google.com/reservation-affinity: "specific"
            cloud.google.com/gke-gpu-driver-version: latest
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: qwen3-service
    spec:
      selector:
        app: qwen3-server
      type: ClusterIP
      ports:
        - protocol: TCP
          port: 8000
          targetPort: 8000
    ---
    apiVersion: monitoring.googleapis.com/v1
    kind: PodMonitoring
    metadata:
      name: vllm-qwen3-monitoring
    spec:
      selector:
        matchLabels:
          app: qwen3-server
      endpoints:
      - port: 8000
        path: /metrics
        interval: 30s
  2. Applica il file qwen3-235b-deploy.yaml al cluster GKE:

    envsubst < qwen3-235b-deploy.yaml | kubectl apply -f -
    Poiché il container utilizza Run:ai Model Streamer per trasmettere in streaming i pesi del modello direttamente da Cloud Storage, il tempo di avvio è notevolmente accelerato.

  3. Per visualizzare lo stato di completamento, esegui questo comando:

    kubectl wait \
        --for=condition=Available \
        --timeout=1800s deployment/vllm-qwen3-deployment
    Il flag --timeout=600s consente al comando di monitorare il deployment per un massimo di 10 minuti.

Interagisci con Qwen3 utilizzando curl

Per verificare il modello Qwen3 che hai implementato:

  1. Configura il port forwarding su Qwen3:

    kubectl port-forward service/qwen3-service 8000:8000
  2. Apri una nuova finestra del terminale. Puoi quindi chattare con il tuo modello utilizzando curl:

    curl http://127.0.0.1:8000/v1/chat/completions \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{
      "model": "Qwen/Qwen3-235B-A22B-Instruct-2507",
      "messages": [
        {
          "role": "user",
          "content": "Describe a GPU in one short sentence?"
        }
      ],
      "stream": false
    }' | jq .
  3. L'output è simile al seguente:

    {
      "id": "chatcmpl-a926ddf7ef2745ca832bda096e867764",
      "object": "chat.completion",
      "created": 1755023619,
      "model": "Qwen/Qwen3-235B-A22B-Instruct-2507",
      "choices": [
        {
          "index": 0,
          "message": {
            "role": "assistant",
            "content": "A GPU is a specialized electronic circuit designed to rapidly process and render graphics and perform parallel computations.",
            "refusal": null,
            "annotations": null,
            "audio": null,
            "function_call": null,
            "tool_calls": [],
            "reasoning_content": null
          },
          "logprobs": null,
          "finish_reason": "stop",
          "stop_reason": null
        }
      ],
      "service_tier": null,
      "system_fingerprint": null,
      "usage": {
        "prompt_tokens": 16,
        "total_tokens": 36,
        "completion_tokens": 20,
        "prompt_tokens_details": null
      },
      "prompt_logprobs": null,
      "kv_transfer_params": null
    }
    

Osserva le prestazioni del modello

Se vuoi osservare le prestazioni del tuo modello, puoi utilizzare l'integrazione della dashboard vLLM in Cloud Monitoring. Questa dashboard ti aiuta a visualizzare le metriche di rendimento critiche per il tuo modello, come la velocità effettiva dei token, la latenza di rete e i tassi di errore. Per informazioni, consulta vLLM nella documentazione di Monitoring.

Esegui la pulizia

Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.

Per evitare che al tuo account di fatturazione Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.

Elimina le risorse

Per eliminare le risorse del tutorial, esegui questi comandi:

envsubst < qwen3-235b-deploy.yaml | kubectl delete -f -
envsubst < qwen3-model-loader.yaml | kubectl delete -f -
kubectl delete secret hf-secret
kubectl delete serviceaccount qwen-ksa

gcloud iam service-accounts delete qwen-gcs-sa@$PROJECT_ID.iam.gserviceaccount.com \
    --project=$PROJECT_ID --quiet

gcloud storage rm --recursive gs://$GCS_BUCKET_NAME

Elimina il cluster GKE

Per eliminare il cluster GKE, esegui questo comando:

gcloud container clusters delete "$CLUSTER_NAME" \
    --region="$REGION" \
    --project="$PROJECT_ID" \
    --quiet

Elimina il progetto

Elimina un progetto Google Cloud :

gcloud projects delete PROJECT_ID

Passaggi successivi