GKE で vLLM を使用して Qwen3 で推論を実行する

このチュートリアルでは、 vLLM サービング フレームワークを使用して Qwen3 大規模言語モデル(LLM)をデプロイしてサービングする方法について説明します。モデルは、Google Kubernetes Engine(GKE)上の 単一の A4 仮想マシン(VM)インスタンスにデプロイします。

このチュートリアルは、推論ワークロードの処理に Kubernetes コンテナ オーケストレーション機能を使用することを検討している ML エンジニア、プラットフォーム管理者、オペレーター、データおよび AI のスペシャリストを対象としています。

目標

  1. Hugging Face を使用して Qwen3 にアクセスする。

  2. 環境を準備する。

  3. Autopilot モードで GKE クラスタを作成する。

  4. Cloud Storage バケットを作成する。

  5. Hugging Face の認証情報用の Kubernetes Secret を作成する。

  6. Cloud Storage の Workload Identity 連携を構成する。

  7. Cloud Storage バケットに Qwen3 モデルを入力する。

  8. vLLM コンテナを GKE にデプロイする。

  9. curl を使用して Qwen3 を操作する。

  10. クリーンアップする。

費用

このチュートリアルでは、以下を含む、 Google Cloudの課金対象となるコンポーネントを使用します:

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。

始める前に

  1. アカウントに Google Cloud ログインしてください。 Google Cloudを初めて使用する場合は、 アカウントを作成して、実際のシナリオで Google プロダクトのパフォーマンスを評価してください。新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $300 分を差し上げます。
  2. Google Cloud CLI をインストールします。

  3. 外部 ID プロバイダ(IdP)を使用している場合は、まず連携 ID を使用して gcloud CLI にログインする必要があります。

  4. gcloud CLI を初期化するには、次のコマンドを実行します:

    gcloud init
  5. プロジェクトを作成または選択します Google Cloud

    プロジェクトを選択または作成するために必要なロール

    • プロジェクトを選択する: プロジェクトの選択に特定の IAM ロールは必要ありません。ロールが付与されているプロジェクトを選択できます。
    • プロジェクトを作成する: プロジェクトを作成するには、プロジェクト作成者ロール (roles/resourcemanager.projectCreator)が必要です。これには resourcemanager.projects.create 権限が含まれています。詳しくは、ロールを付与する方法をご覧ください。
    • プロジェクトを作成する Google Cloud :

      gcloud projects create PROJECT_ID

      PROJECT_ID は、作成する Google Cloud プロジェクトの名前に置き換えます。

    • 作成した Google Cloud プロジェクトを選択します。

      gcloud config set project PROJECT_ID

      PROJECT_ID は、 Google Cloud プロジェクトの名前に置き換えます。

  6. プロジェクトに対して課金が有効になっていることを確認します Google Cloud

  7. 必要な API を有効にします。

    API を有効にするために必要なロール

    API を有効にするには、serviceusage.services.enable 権限が必要です。プロジェクトを作成した場合、オーナーロール(roles/owner)を通じてこの権限が付与されている可能性があります。それ以外の場合は、Service Usage 管理者ロール(roles/serviceusage.serviceUsageAdmin)を通じてこの権限を取得できます。ロールを付与する方法をご覧ください

    gcloud services enable container.googleapis.com
  8. Google Cloud CLI をインストールします。

  9. 外部 ID プロバイダ(IdP)を使用している場合は、まず連携 ID を使用して gcloud CLI にログインする必要があります。

  10. gcloud CLI を初期化するには、次のコマンドを実行します:

    gcloud init
  11. プロジェクトを作成または選択します Google Cloud

    プロジェクトを選択または作成するために必要なロール

    • プロジェクトを選択する: プロジェクトの選択に特定の IAM ロールは必要ありません。ロールが付与されているプロジェクトを選択できます。
    • プロジェクトを作成する: プロジェクトを作成するには、プロジェクト作成者ロール (roles/resourcemanager.projectCreator)が必要です。これには resourcemanager.projects.create 権限が含まれています。詳しくは、ロールを付与する方法をご覧ください。
    • プロジェクトを作成する Google Cloud :

      gcloud projects create PROJECT_ID

      PROJECT_ID は、作成する Google Cloud プロジェクトの名前に置き換えます。

    • 作成した Google Cloud プロジェクトを選択します。

      gcloud config set project PROJECT_ID

      PROJECT_ID は、 Google Cloud プロジェクトの名前に置き換えます。

  12. プロジェクトに対して課金が有効になっていることを確認します Google Cloud

  13. 必要な API を有効にします。

    API を有効にするために必要なロール

    API を有効にするには、serviceusage.services.enable 権限が必要です。プロジェクトを作成した場合、オーナーロール(roles/owner)を通じてこの権限が付与されている可能性があります。それ以外の場合は、Service Usage 管理者ロール(roles/serviceusage.serviceUsageAdmin)を通じてこの権限を取得できます。ロールを付与する方法をご覧ください

    gcloud services enable container.googleapis.com
  14. ユーザー アカウントにロールを付与します。次の IAM ロールごとに次のコマンドを 1 回実行します。roles/container.admin

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

    次のように置き換えます。

    • PROJECT_ID: プロジェクト ID。
    • USER_IDENTIFIER: ユーザー アカウントの識別子。例: myemail@example.com
    • ROLE: ユーザー アカウントに付与する IAM ロール。
  15. Hugging Face アカウントにログインするか、Hugging Face アカウントを作成します 。

Hugging Face を使用して Qwen3 にアクセスする

Hugging Face を使用して Qwen3 にアクセスする手順は次のとおりです。

  1. Hugging Face にログインします。
  2. Hugging Face read アクセス トークンを作成しますYour Profile > Settings > Access Tokens > +Create new token をクリックします。
  3. トークンの任意の名前を指定し、ロールを選択します。このチュートリアルで選択できる最小のロール権限レベルは Read です。
  4. [Create token] を選択します。
  5. 生成されたトークンをコピーしてクリップボードに保存します。このチュートリアルで後ほど使用します。

環境を準備する

環境を準備するには、デフォルトの環境変数を設定します。

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

次のように置き換えます。

  • YOUR_PROJECT_ID: GKE クラスタを作成する Google Cloud プロジェクト の ID。

  • YOUR_RESERVATION_NAME: GKE クラスタの作成に使用する予約の名前。予約が存在するプロジェクトに基づいて、次のいずれかの値を指定します。

    • 予約がプロジェクトに存在する場合: RESERVATION_NAME

    • 予約が別のプロジェクトに存在し、プロジェクトで予約を使用できる場合: 予約を使用できます: projects/RESERVATION_PROJECT_ID/reservations/RESERVATION_NAME

  • YOUR_REGION: GKE クラスタを作成するリージョン。クラスタは、予約が存在するリージョンにのみ作成できます。

  • YOUR_CLUSTER_NAME: 作成する GKE クラスタの名前。

  • YOUR_BUCKET_NAME: 作成するリージョン Cloud Storage バケットの名前。

  • YOUR_HF_TOKEN: 前のセクションで作成した Hugging Face アクセス トークン。

  • YOUR_NETWORK_NAME: GKE クラスタが使用するネットワーク。次のいずれかの値を指定します。

    • カスタム ネットワークを作成した場合は、ネットワークの名前を指定します。

    • それ以外の場合は、default を指定します。

  • YOUR_SUBNETWORK_NAME: GKE クラスタが使用するサブネットワーク。次のいずれかの値を指定します。

    • カスタム サブネットワークを作成した場合は、サブネットワークの名前を指定します。予約と同じリージョンに存在するサブネットワークのみを指定できます。

    • それ以外の場合は、default を指定します。

Autopilot モードで GKE クラスタを作成する

Autopilot モードで GKE クラスタを作成するには、次のコマンドを実行します。

gcloud container clusters create-auto "$CLUSTER_NAME" \
    --project="$PROJECT_ID" \
    --region="$REGION" \
    --release-channel=rapid \
    --network="$NETWORK" \
    --subnetwork="$SUBNETWORK"
GKE クラスタの作成が完了するまでに時間がかかることがあります。 Google Cloud がクラスタの作成を完了したことを確認するには、 Google Cloud コンソールで Kubernetes クラスタ に移動します。

Cloud Storage バケットを作成する

モデルを保存するリージョン Cloud Storage バケットを作成するには、次のコマンドを実行します。

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

Hugging Face の認証情報用の Kubernetes Secret を作成する

Hugging Face の認証情報用の Kubernetes Secret を作成する手順は次のとおりです。

  1. GKE クラスタと通信するように kubectl を構成します。

    gcloud container clusters get-credentials "$CLUSTER_NAME" \
        --location="$REGION" \
        --project="$PROJECT_ID"
  2. Hugging Face トークンを保存する Kubernetes Secret を作成します。

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

Cloud Storage の Workload Identity 連携を構成する

GKE が Cloud Storage バケットに安全にアクセスできるようにするには、GKE Workload Identity 連携を設定します。

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"

Cloud Storage バケットに Qwen3 モデルの重みを入力する

Cloud Storage バケットに Qwen3 モデルの重みを入力するには、Cloud Storage FUSE CSI ドライバを使用してバケットをボリュームとしてマウントする Kubernetes Job を実行します。バケットにモデルが存在しない場合、ジョブは Hugging Face からモデルをダウンロードします。

  1. 次の内容で qwen3-model-loader.yaml という名前のファイルを作成します。

    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. qwen3-model-loader.yaml マニフェストを適用して、ダウンロード ジョブを初期化します。

    envsubst < qwen3-model-loader.yaml | kubectl apply -f -
  3. ジョブが実行されていることを確認するには、ダウンロード ジョブのログをストリーミングします。

    kubectl logs -f job/qwen3-model-loader -c downloader
    
  4. モデルのダウンロード ジョブが完了するまで待ちます。

    kubectl wait \
        --for=condition=Complete \
        --timeout=1800s job/qwen3-model-loader
  5. ジョブを削除するには、次のコマンドを実行します。

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

vLLM コンテナを GKE クラスタにデプロイする

Kubernetes Deployment を使用して Qwen3 モデルをサービングする vLLM コンテナをデプロイするには、次の操作を行います。

  1. 選択した vLLM デプロイで qwen3-235b-deploy.yaml ファイルを作成します。

    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. qwen3-235b-deploy.yaml ファイルを GKE クラスタに適用します。

    envsubst < qwen3-235b-deploy.yaml | kubectl apply -f -
    コンテナは Run:ai Model Streamer を使用して Cloud Storage からモデルの重みを直接ストリーミングするため、起動時間が大幅に短縮されます。

  3. 完了ステータスを確認するには、次のコマンドを実行します。

    kubectl wait \
        --for=condition=Available \
        --timeout=1800s deployment/vllm-qwen3-deployment
    --timeout=600s フラグを使用すると、コマンドは最大 10 分間デプロイをモニタリングできます。

curl を使用して Qwen3 を操作する

デプロイした Qwen3 モデルを確認する手順は次のとおりです。

  1. Qwen3 へのポート転送を設定します。

    kubectl port-forward service/qwen3-service 8000:8000
  2. 新しいターミナル ウィンドウを開きます。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. 出力は次のようになります。

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

モデルのパフォーマンスをモニタリングする

モデルのパフォーマンスをモニタリングする場合は、Cloud Monitoring で vLLM ダッシュボードの統合を使用できます。このダッシュボードでは、トークンのスループット、ネットワーク レイテンシ、エラー率など、モデルの重要なパフォーマンス指標を確認できます。詳細については、 Monitoring のドキュメントのvLLMをご覧ください。

クリーンアップする。

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

このチュートリアルで使用したリソースについて、Cloud 請求先アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

リソースの削除

チュートリアルのリソースを削除するには、次のコマンドを実行します。

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

GKE クラスタを削除する

GKE クラスタを削除するには、次のコマンドを実行します。

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

プロジェクトの削除

プロジェクト Google Cloud を削除する:

gcloud projects delete PROJECT_ID

次のステップ