Usa vLLM en GKE para ejecutar la inferencia con Qwen3

En este instructivo, se muestra cómo implementar y entregar un modelo de lenguaje grande (LLM) Qwen3 con el framework de entrega vLLM. Implementas el modelo en una sola instancia de máquina virtual (VM) A4 en Google Kubernetes Engine (GKE).

Este instructivo está dirigido a ingenieros de aprendizaje automático (AA), administradores y operadores de plataformas, y especialistas en datos y en IA que estén interesados en usar las capacidades de organización de contenedores de Kubernetes para controlar las cargas de trabajo de inferencia.

Objetivos

  1. Accede a Qwen3 con Hugging Face.

  2. Prepara tu entorno.

  3. Crear un clúster de GKE en modo Autopilot

  4. Crear un bucket de Cloud Storage

  5. Crea un secreto de Kubernetes para las credenciales de Hugging Face.

  6. Configura la federación de identidades para cargas de trabajo para Cloud Storage.

  7. Propaga el bucket de Cloud Storage con el modelo Qwen3.

  8. Implementar un contenedor de vLLM en tu clúster de GKE

  9. Interactúa con Qwen3 usando curl.

  10. Realizar una limpieza

Costos

En este instructivo, se usan los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios.

Antes de comenzar

  1. Accede a tu cuenta de Google Cloud . Si eres nuevo en Google Cloud, crea una cuenta para evaluar el rendimiento de nuestros productos en situaciones reales. Los clientes nuevos también obtienen $300 en créditos gratuitos para ejecutar, probar y, además, implementar cargas de trabajo.
  2. Instala Google Cloud CLI.

  3. Si usas un proveedor de identidad externo (IdP), primero debes acceder a la gcloud CLI con tu identidad federada.

  4. Para inicializar gcloud CLI, ejecuta el siguiente comando:

    gcloud init
  5. Crea o selecciona un Google Cloud proyecto.

    Roles necesarios para seleccionar o crear un proyecto

    • Selecciona un proyecto: Para seleccionar un proyecto, no se requiere un rol de IAM específico. Puedes seleccionar cualquier proyecto en el que se te haya otorgado un rol.
    • Crear un proyecto: Para crear un proyecto, necesitas el rol de Creador de proyectos (roles/resourcemanager.projectCreator), que contiene el permiso resourcemanager.projects.create. Obtén más información para otorgar roles.
    • Crea un proyecto de Google Cloud :

      gcloud projects create PROJECT_ID

      Reemplaza PROJECT_ID por un nombre para el proyecto Google Cloud que estás creando.

    • Selecciona el proyecto Google Cloud que creaste:

      gcloud config set project PROJECT_ID

      Reemplaza PROJECT_ID por el nombre de tu proyecto de Google Cloud .

  6. Verifica que la facturación esté habilitada para tu proyecto de Google Cloud .

  7. Habilita la API necesaria:

    Roles necesarios para habilitar las APIs

    Para habilitar APIs, necesitas el permiso serviceusage.services.enable. Si creaste el proyecto, es probable que ya tengas este permiso a través del rol de propietario (roles/owner). De lo contrario, puedes obtener este permiso a través del rol de administrador de Service Usage (roles/serviceusage.serviceUsageAdmin). Obtén más información para otorgar roles.

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

  9. Si usas un proveedor de identidad externo (IdP), primero debes acceder a la gcloud CLI con tu identidad federada.

  10. Para inicializar gcloud CLI, ejecuta el siguiente comando:

    gcloud init
  11. Crea o selecciona un Google Cloud proyecto.

    Roles necesarios para seleccionar o crear un proyecto

    • Selecciona un proyecto: Para seleccionar un proyecto, no se requiere un rol de IAM específico. Puedes seleccionar cualquier proyecto en el que se te haya otorgado un rol.
    • Crear un proyecto: Para crear un proyecto, necesitas el rol de Creador de proyectos (roles/resourcemanager.projectCreator), que contiene el permiso resourcemanager.projects.create. Obtén más información para otorgar roles.
    • Crea un proyecto de Google Cloud :

      gcloud projects create PROJECT_ID

      Reemplaza PROJECT_ID por un nombre para el proyecto Google Cloud que estás creando.

    • Selecciona el proyecto Google Cloud que creaste:

      gcloud config set project PROJECT_ID

      Reemplaza PROJECT_ID por el nombre de tu proyecto de Google Cloud .

  12. Verifica que la facturación esté habilitada para tu proyecto de Google Cloud .

  13. Habilita la API necesaria:

    Roles necesarios para habilitar las APIs

    Para habilitar APIs, necesitas el permiso serviceusage.services.enable. Si creaste el proyecto, es probable que ya tengas este permiso a través del rol de propietario (roles/owner). De lo contrario, puedes obtener este permiso a través del rol de administrador de Service Usage (roles/serviceusage.serviceUsageAdmin). Obtén más información para otorgar roles.

    gcloud services enable container.googleapis.com
  14. Otorga roles a tu cuenta de usuario. Ejecuta el siguiente comando una vez para cada uno de los siguientes roles de IAM: roles/container.admin

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

    Reemplaza lo siguiente:

    • PROJECT_ID: ID del proyecto
    • USER_IDENTIFIER: Es el identificador de tu cuenta de usuario de . Por ejemplo, myemail@example.com. Cuenta de
    • ROLE: Es el rol de IAM que otorgas a tu cuenta de usuario.
  15. Accede a tu cuenta de Hugging Face o crea una.

Accede a Qwen3 con Hugging Face

Para usar Hugging Face y acceder a Qwen3, sigue estos pasos:

  1. Accede a Hugging Face
  2. Crea un token de acceso de Hugging Face read. Haz clic en Tu perfil > Configuración > Tokens de acceso > +Crear token nuevo.
  3. Especifica el nombre que desees para el token y, luego, selecciona un rol. El nivel de permiso de rol mínimo que puedes seleccionar para este instructivo es Lectura.
  4. Selecciona Crear token.
  5. Copia y guarda el token generado en el portapapeles. La usarás más adelante en este instructivo.

Prepara el entorno

Para preparar tu entorno, establece las variables de entorno predeterminadas:

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

Reemplaza lo siguiente:

  • YOUR_PROJECT_ID: Es el ID del Google Cloud proyecto en el que deseas crear el clúster de GKE.

  • YOUR_RESERVATION_NAME: Es el nombre de la reserva que deseas usar para crear tu clúster de GKE. Según el proyecto en el que existe la reserva, especifica uno de los siguientes valores:

    • La reserva existe en tu proyecto: RESERVATION_NAME

    • La reserva existe en otro proyecto y tu proyecto puede usarla: projects/RESERVATION_PROJECT_ID/reservations/RESERVATION_NAME

  • YOUR_REGION: Es la región en la que deseas crear tu clúster de GKE. Solo puedes crear el clúster en la región en la que existe tu reserva.

  • YOUR_CLUSTER_NAME: Es el nombre del clúster de GKE que se creará.

  • YOUR_BUCKET_NAME: Es el nombre del bucket de Cloud Storage regional que se creará.

  • YOUR_HF_TOKEN: El token de acceso de Hugging Face que creaste en la sección anterior.

  • YOUR_NETWORK_NAME: Es la red que usa el clúster de GKE. Especifica uno de los siguientes valores:

    • Si creaste una red personalizada, especifica su nombre.

    • De lo contrario, especifica default.

  • YOUR_SUBNETWORK_NAME: Es la subred que usa el clúster de GKE. Especifica uno de los siguientes valores:

    • Si creaste una subred personalizada, especifica su nombre. Solo puedes especificar una subred que exista en la misma región que la reserva.

    • De lo contrario, especifica default.

Crea un clúster de GKE en modo Autopilot

Para crear un clúster de GKE en modo Autopilot, ejecuta el siguiente comando:

gcloud container clusters create-auto "$CLUSTER_NAME" \
    --project="$PROJECT_ID" \
    --region="$REGION" \
    --release-channel=rapid \
    --network="$NETWORK" \
    --subnetwork="$SUBNETWORK"
La creación del clúster de GKE puede tardar un tiempo en completarse. Para verificar que Google Cloud haya terminado de crear tu clúster, ve aClústeres de Kubernetesen la consola de Google Cloud .

Cree un bucket de Cloud Storage

Para crear un bucket regional de Cloud Storage en el que almacenar tu modelo, ejecuta el siguiente comando:

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

Crea un secreto de Kubernetes para las credenciales de Hugging Face

Para crear un secreto de Kubernetes para las credenciales de Hugging Face, sigue estos pasos:

  1. Configura kubectl para comunicarse con tu clúster de GKE:

    gcloud container clusters get-credentials "$CLUSTER_NAME" \
        --location="$REGION" \
        --project="$PROJECT_ID"
  2. Crea un Secret de Kubernetes para almacenar tu token de 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 federación de identidades para cargas de trabajo para Cloud Storage

Para permitir que GKE acceda de forma segura al bucket de Cloud Storage, configura la federación de identidades para cargas de trabajo de 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"

Propaga el bucket de Cloud Storage con las ponderaciones del modelo Qwen3

Para propagar tu bucket de Cloud Storage con los pesos del modelo Qwen3, ejecuta un trabajo de Kubernetes que use el controlador de CSI de Cloud Storage FUSE para activar tu bucket como un volumen. El trabajo descarga el modelo de Hugging Face si aún no existe en el bucket.

  1. Crea un archivo llamado qwen3-model-loader.yaml con el siguiente contenido:

    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. Aplica el manifiesto qwen3-model-loader.yaml para inicializar el trabajo de descarga:

    envsubst < qwen3-model-loader.yaml | kubectl apply -f -
  3. Para verificar que el trabajo se esté ejecutando, transmite los registros del trabajo de descarga:

    kubectl logs -f job/qwen3-model-loader -c downloader
    
  4. Espera a que se complete el trabajo de descarga del modelo:

    kubectl wait \
        --for=condition=Complete \
        --timeout=1800s job/qwen3-model-loader
  5. Para borrar el trabajo, ejecuta el siguiente comando:

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

Implementa un contenedor de vLLM en tu clúster de GKE

Para implementar el contenedor de vLLM y entregar el modelo de Qwen3 con implementaciones de Kubernetes, haz lo siguiente:

  1. Crea un archivo qwen3-235b-deploy.yaml con la implementación de vLLM que elijas:

    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. Aplica el archivo qwen3-235b-deploy.yaml a tu clúster de GKE:

    envsubst < qwen3-235b-deploy.yaml | kubectl apply -f -
    Dado que el contenedor usa Run:ai Model Streamer para transmitir los pesos del modelo directamente desde Cloud Storage, el tiempo de inicio se acelera significativamente.

  3. Para ver el estado de finalización, ejecuta el siguiente comando:

    kubectl wait \
        --for=condition=Available \
        --timeout=1800s deployment/vllm-qwen3-deployment
    La marca --timeout=600s permite que el comando supervise la implementación durante un máximo de 10 minutos.

Interactúa con Qwen3 usando curl

Para verificar el modelo Qwen3 que implementaste, haz lo siguiente:

  1. Configura la redirección de puertos a Qwen3:

    kubectl port-forward service/qwen3-service 8000:8000
  2. Abre una nueva ventana de terminal. Luego, puedes chatear con tu modelo usando 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. El resultado es similar a lo siguiente:

    {
      "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
    }
    

Observa el rendimiento del modelo

Si deseas observar el rendimiento de tu modelo, puedes usar la integración del panel de vLLM en Cloud Monitoring. Este panel te ayuda a ver las métricas de rendimiento críticas de tu modelo, como la capacidad de procesamiento de tokens, la latencia de la red y las tasas de error. Para obtener más información, consulta vLLM en la documentación de Monitoring.

Realiza una limpieza

Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos usados en este instructivo, borra el proyecto que contiene los recursos o conserva el proyecto y borra los recursos individuales.

Para evitar que se apliquen cargos a tu cuenta de facturación de Cloud por los recursos usados en este instructivo, borra el proyecto que contiene los recursos o conserva el proyecto y borra los recursos individuales.

Borra recursos

Para borrar los recursos del instructivo, ejecuta los siguientes comandos:

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

Borra tu clúster de GKE

Para borrar tu clúster de GKE, ejecuta el siguiente comando:

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

Borra tu proyecto

Borra un Google Cloud proyecto:

gcloud projects delete PROJECT_ID

¿Qué sigue?