Usar o vLLM no GKE para executar inferência com o Qwen3

Neste tutorial, mostramos como implantar e disponibilizar um modelo de linguagem grande (LLM) Qwen3 com o framework de disponibilização vLLM. Você implanta o modelo em uma única instância de máquina virtual A4 (VM) no Google Kubernetes Engine (GKE).

Este tutorial é destinado a engenheiros de machine learning (ML), administradores e operadores de plataforma e especialistas em dados e IA interessados em usar os recursos de orquestração de contêineres do Kubernetes para processar cargas de trabalho de inferência.

Objetivos

  1. Acesse o Qwen3 usando o Hugging Face.

  2. Prepare seu ambiente.

  3. Criar um cluster do GKE no modo Autopilot.

  4. Criar um bucket do Cloud Storage.

  5. Crie um secret do Kubernetes para as credenciais do Hugging Face.

  6. Configure a federação de identidade da carga de trabalho para o Cloud Storage.

  7. Preencha o bucket do Cloud Storage com o modelo Qwen3.

  8. Implante um contêiner vLLM no GKE.

  9. Interaja com o Qwen3 usando curl.

  10. Fazer a limpeza.

Custos

Neste tutorial, usamos componentes faturáveis do Google Cloud, incluindo:

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços.

Antes de começar

  1. Faça login na sua conta do Google Cloud . Se você começou a usar o Google Cloudagora, crie uma conta para avaliar o desempenho dos nossos produtos em situações reais. Clientes novos também recebem US $300 em créditos para executar, testar e implantar cargas de trabalho.
  2. Instale a CLI do Google Cloud.

  3. Ao usar um provedor de identidade (IdP) externo, primeiro faça login na CLI gcloud com sua identidade federada.

  4. Para inicializar a CLI gcloud, execute o seguinte comando:

    gcloud init
  5. Crie ou selecione um Google Cloud projeto.

    Funções necessárias para selecionar ou criar um projeto

    • Selecionar um projeto: não é necessário um papel específico do IAM para selecionar um projeto. Você pode escolher qualquer projeto em que tenha recebido um papel.
    • Criar um projeto: para criar um projeto, é necessário ter o papel de Criador de projetos (roles/resourcemanager.projectCreator), que contém a permissão resourcemanager.projects.create. Saiba como conceder papéis.
    • Crie um projeto do Google Cloud :

      gcloud projects create PROJECT_ID

      Substitua PROJECT_ID por um nome para o projeto do Google Cloud que você está criando.

    • Selecione o projeto Google Cloud que você criou:

      gcloud config set project PROJECT_ID

      Substitua PROJECT_ID pelo nome do projeto do Google Cloud .

  6. Verifique se o faturamento está ativado para o projeto do Google Cloud .

  7. Ative a API necessária, se ela ainda não estiver ativada:

    Funções necessárias para ativar APIs

    Para ativar APIs, você precisa da permissão serviceusage.services.enable. Se você criou o projeto, provavelmente já tem essa permissão pelo papel de Proprietário (roles/owner). Caso contrário, é possível receber essa permissão pelo papel de Administrador do Service Usage (roles/serviceusage.serviceUsageAdmin). Saiba como conceder papéis.

    gcloud services enable container.googleapis.com
  8. Instale a CLI do Google Cloud.

  9. Ao usar um provedor de identidade (IdP) externo, primeiro faça login na CLI gcloud com sua identidade federada.

  10. Para inicializar a CLI gcloud, execute o seguinte comando:

    gcloud init
  11. Crie ou selecione um Google Cloud projeto.

    Funções necessárias para selecionar ou criar um projeto

    • Selecionar um projeto: não é necessário um papel específico do IAM para selecionar um projeto. Você pode escolher qualquer projeto em que tenha recebido um papel.
    • Criar um projeto: para criar um projeto, é necessário ter o papel de Criador de projetos (roles/resourcemanager.projectCreator), que contém a permissão resourcemanager.projects.create. Saiba como conceder papéis.
    • Crie um projeto do Google Cloud :

      gcloud projects create PROJECT_ID

      Substitua PROJECT_ID por um nome para o projeto do Google Cloud que você está criando.

    • Selecione o projeto Google Cloud que você criou:

      gcloud config set project PROJECT_ID

      Substitua PROJECT_ID pelo nome do projeto do Google Cloud .

  12. Verifique se o faturamento está ativado para o projeto do Google Cloud .

  13. Ative a API necessária, se ela ainda não estiver ativada:

    Funções necessárias para ativar APIs

    Para ativar APIs, você precisa da permissão serviceusage.services.enable. Se você criou o projeto, provavelmente já tem essa permissão pelo papel de Proprietário (roles/owner). Caso contrário, é possível receber essa permissão pelo papel de Administrador do Service Usage (roles/serviceusage.serviceUsageAdmin). Saiba como conceder papéis.

    gcloud services enable container.googleapis.com
  14. Conceda papéis à sua conta de usuário. Execute uma vez o seguinte comando para cada um dos seguintes papéis do IAM: roles/container.admin

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

    Substitua:

    • PROJECT_ID: o ID do projeto.
    • USER_IDENTIFIER: o identificador da sua conta de usuário . Por exemplo, myemail@example.com.
    • ROLE: o papel do IAM que você concede à sua conta de usuário.
  15. Faça login ou crie uma conta do Hugging Face.

Acessar o Qwen3 usando o Hugging Face

Para usar o Hugging Face e acessar o Qwen3, siga estas etapas:

  1. Fazer login no Hugging Face
  2. Crie um token de acesso read do Hugging Face. Clique em Seu perfil > Configurações > Tokens de acesso > +Criar novo token.
  3. Especifique um nome para o token e selecione uma função. O nível mínimo de permissão de função que você pode selecionar para este tutorial é Leitura.
  4. Selecione Criar token.
  5. Copie e salve o token gerado na área de transferência. Você vai usá-lo mais tarde neste tutorial.

Preparar o ambiente

Para preparar seu ambiente, defina as variáveis de ambiente padrão:

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

Substitua:

  • YOUR_PROJECT_ID: o ID do Google Cloud projeto em que você quer criar o cluster do GKE.

  • YOUR_RESERVATION_NAME: o nome da reserva que você quer usar para criar o cluster do GKE. Com base no projeto em que a reserva existe, especifique um dos seguintes valores:

    • A reserva existe no seu projeto: RESERVATION_NAME

    • A reserva existe em um projeto diferente, e seu projeto pode usar a reserva: projects/RESERVATION_PROJECT_ID/reservations/RESERVATION_NAME

  • YOUR_REGION: a região em que você quer criar o cluster do GKE. Só é possível criar o cluster na região em que a reserva está.

  • YOUR_CLUSTER_NAME: o nome do cluster do GKE a ser criado.

  • YOUR_BUCKET_NAME: o nome do bucket do Cloud Storage regional a ser criado.

  • YOUR_HF_TOKEN: o token de acesso do Hugging Face que você criou na seção anterior.

  • YOUR_NETWORK_NAME: a rede usada pelo cluster do GKE. Especifique um dos seguintes valores:

    • Se você criou uma rede personalizada, especifique o nome dela.

    • Caso contrário, especifique default.

  • YOUR_SUBNETWORK_NAME: a sub-rede que o cluster do GKE usa. Especifique um dos seguintes valores:

    • Se você criou uma sub-rede personalizada, especifique o nome dela. Só é possível especificar uma sub-rede que esteja na mesma região da reserva.

    • Caso contrário, especifique default.

Criar um cluster do GKE no modo Autopilot

Para criar um cluster do GKE no modo Autopilot, execute o seguinte comando:

gcloud container clusters create-auto "$CLUSTER_NAME" \
    --project="$PROJECT_ID" \
    --region="$REGION" \
    --release-channel=rapid \
    --network="$NETWORK" \
    --subnetwork="$SUBNETWORK"
A criação do cluster do GKE pode levar algum tempo. Para verificar se o Google Cloud concluiu a criação do cluster, acesse Clusters do Kubernetes no console Google Cloud .

Criar um bucket do Cloud Storage

Para criar um bucket regional do Cloud Storage e armazenar seu modelo, execute o seguinte comando:

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

Criar um secret do Kubernetes para as credenciais do Hugging Face

Para criar um secret do Kubernetes para as credenciais do Hugging Face, siga estas etapas:

  1. Configure kubectl para se comunicar com o cluster do GKE:

    gcloud container clusters get-credentials "$CLUSTER_NAME" \
        --location="$REGION" \
        --project="$PROJECT_ID"
  2. Crie um secret do Kubernetes para armazenar seu token do Hugging Face:

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

Configurar a federação de identidade da carga de trabalho para o Cloud Storage

Para permitir que o GKE acesse o bucket do Cloud Storage com segurança, configure a federação de identidade da carga de trabalho do 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"

Preencha o bucket do Cloud Storage com os pesos do modelo Qwen3

Para preencher seu bucket do Cloud Storage com os pesos do modelo Qwen3, execute um job do Kubernetes que use o driver CSI do Cloud Storage FUSE para montar o bucket como um volume. O job faz o download do modelo do Hugging Face se ele ainda não existir no bucket.

  1. Crie um arquivo chamado qwen3-model-loader.yaml com o conteúdo a seguir:

    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. Aplique o manifesto qwen3-model-loader.yaml para inicializar o job de download:

    envsubst < qwen3-model-loader.yaml | kubectl apply -f -
  3. Para verificar se o job está em execução, transmita os registros dele:

    kubectl logs -f job/qwen3-model-loader -c downloader
    
  4. Aguarde a conclusão do job de download do modelo:

    kubectl wait \
        --for=condition=Complete \
        --timeout=1800s job/qwen3-model-loader
  5. Para excluir o job, execute o seguinte comando:

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

Implantar um contêiner vLLM no cluster do GKE

Para implantar o contêiner vLLM para disponibilizar o modelo Qwen3 usando implantações do Kubernetes, faça o seguinte:

  1. Crie um arquivo qwen3-235b-deploy.yaml com a implantação do vLLM escolhida:

    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. Aplique o arquivo qwen3-235b-deploy.yaml ao cluster do GKE:

    envsubst < qwen3-235b-deploy.yaml | kubectl apply -f -
    Como o contêiner usa o Run:ai Model Streamer para transmitir pesos de modelos diretamente do Cloud Storage, o tempo de inicialização é significativamente acelerado.

  3. Para conferir o status da conclusão, execute o seguinte comando:

    kubectl wait \
        --for=condition=Available \
        --timeout=1800s deployment/vllm-qwen3-deployment
    A flag --timeout=600s permite que o comando monitore a implantação por até 10 minutos.

Interagir com o Qwen3 usando curl

Para verificar o modelo Qwen3 implantado, faça o seguinte:

  1. Configure o encaminhamento de portas para o Qwen3:

    kubectl port-forward service/qwen3-service 8000:8000
  2. Abra uma nova janela do terminal. Em seguida, converse com o 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. O resultado será o seguinte:

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

Observar a performance do modelo

Se quiser observar a performance do modelo, use a integração do painel do vLLM no Cloud Monitoring. Esse painel ajuda você a conferir métricas de desempenho críticas para seu modelo, como capacidade de processamento de tokens, latência de rede e taxas de erro. Para mais informações, consulte vLLM na documentação do Monitoring.

Limpar

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados no tutorial, exclua o projeto que os contém ou mantenha o projeto e exclua os recursos individuais.

Para evitar cobranças na sua conta do Cloud Billing pelos recursos usados neste tutorial, exclua o projeto que os contém ou mantenha o projeto e exclua os recursos individuais.

Excluir os recursos

Para excluir os recursos do tutorial, execute os seguintes 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

Excluir o cluster do GKE

Para excluir o cluster do GKE, execute o seguinte comando:

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

Excluir o projeto

Excluir um projeto do Google Cloud :

gcloud projects delete PROJECT_ID

A seguir