Ray LLM を備えた GKE で TPU を使用して Gemma オープンモデルを提供する

このチュートリアルでは、Ray Serve LLM を使用してマルチホスト TPU 推論サービスをデプロイする方法について説明します。Ray のネイティブ TPU サポートを利用して、複雑なアクセラレータ トポロジ全体に分散エンジン ワーカーをアトミックに共同スケジューリングすることで、推論のためにマルチホスト TPU スライスに大規模なモデルをデプロイできます。

このチュートリアルは、分散マルチホスト TPU スライスで AI/ML ワークロードをサービングするために Kubernetes コンテナ オーケストレーション機能を使用することに関心のある ML エンジニア、プラットフォーム管理者、オペレーター、データおよび AI スペシャリストを対象としています。 のコンテンツで使用されている一般的なロールとタスクの例の詳細については、一般的な GKE ユーザーロールとタスクをご覧ください。 Google Cloud

このページを読む前に、次のことをよく理解しておいてください。

背景

このセクションでは、このガイドで使用されている重要なテクノロジーについて説明します。

TPU

Tensor Processing Unit(TPU)を使用すると、ノードで実行される特定のワークロード(ML やデータ処理など)を高速化できます。TPU の主な利点は、パフォーマンス拡張です。このチュートリアルでは、第 6 世代の Cloud TPU である TPU Trillium を使用します。マルチホスト TPU スライスは、高速チップ間相互接続(ICI)を使用して通信する複数の物理ノードで構成されており、高スループットと低レイテンシのサービングに適しています。

Ray 上の vLLM

vLLM は、高スループットでメモリ効率の高い LLM サービング エンジンです。Ray Serve と統合することで、vLLM は複数のホストにスケーリングし、物理ハードウェア トポロジにネイティブにアクセスできます。このチュートリアルでは、Ray Serve の LLMConfig Deployment と LLMServer Deployment を使用して、マルチホスト スライス全体で vLLM 推論をオーケストレートする方法を示します。これにより、フレームワークがトポロジの分散とプレースメント グループの分散を自動的に処理できます。

目標

このチュートリアルでは、マルチホスト TPU を使用するマネージド Kubernetes 環境における推論用 LLM の実用的なデプロイに関する基礎を学ぶことができます。

  1. Autopilot または Standard の GKE クラスタで環境を準備する。
  2. 依存関係が組み込まれたカスタム コンテナ イメージをビルドする。
  3. Ray LLM Python スクリプトをクラスタにデプロイして、TPU スライス上の vLLM 推論をオーケストレートする。
  4. Ray LLM を使用して、curl とオプションのウェブチャット インターフェースを介して Gemma 4 モデルをサービングする。

始める前に

作業を始める前に、次のタスクが完了していることを確認してください。

  • Google Kubernetes Engine API を有効にする。
  • Google Kubernetes Engine API の有効化
  • このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化する。gcloud CLI をインストール済みの場合は、gcloud components update コマンドを実行して最新のバージョンを取得します。以前のバージョンの gcloud CLI では、このドキュメントのコマンドを実行できない場合があります。
  • 選択したリージョンに TPU Trillium(v6e)の容量が十分にあることを確認します。詳細については、Cloud TPU の割り当てをご覧ください。
  • GKE クラスタで GKE Dataplane V2 が使用され、DRANET のバージョン要件(Standard と Autopilot の両方で 1.35.2-gke.1842000 以降 )を満たしていることを確認します。
  • 次の IAM ロールがあることを確認してください。
    • roles/container.admin
    • roles/iam.serviceAccountAdmin

環境を準備する

このチュートリアルでは、Cloud Shell を使用して Google Cloudでホストされているリソースを管理します。Cloud Shell には、このチュートリアルに必要な kubectlgcloud CLI などのソフトウェアがプリインストールされています。

Cloud Shell を使用して環境を設定するには、次の操作を行います。

  1. コンソールで、[Activate Cloud Shell] Shell をアクティブにするボタン をクリックして、Cloud Shell セッションを起動します。 Google Cloud これにより、コンソールの下部ペインでセッションが起動します。 Google Cloud

  2. Python 仮想環境を作成してアクティブにします。

    python3 -m venv ray-env
    source ray-env/bin/activate
    
  3. Ray CLI をインストールします。

    pip install "ray"
    
  4. デフォルトの環境変数を設定します。

    export PROJECT_ID=$(gcloud config get project)
    export CLUSTER_NAME=ray-llm-cluster
    export REGION=REGION
    export ZONE=ZONE
    export NAMESPACE=default
    export KSA_NAME=ray-ksa
    export GSA_NAME=tpu-reader-sa
    export NETWORK_NAME=${CLUSTER_NAME}-net
    export GS_BUCKET=BUCKET_NAME
    export REPO_NAME=ray-repo
    export CUSTOM_IMAGE_URI=REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/vllm-tpu-ray:vllm-tpu
    

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

    • PROJECT_ID: 実際の Google Cloud プロジェクト ID。
    • CLUSTER_NAME: クラスタの名前。
    • REGION: TPU Trillium の容量が使用可能なリージョン。
    • ZONE: TPU Trillium の容量が使用可能なゾーン。詳細については、GKE での TPU の可用性をご覧ください。
    • REPOSITORY: Artifact Registry リポジトリの名前
    • BUCKET_NAME: ストレージ バケットの名前。

リソースを作成して構成する Google Cloud

次の手順で、必要なリソースを作成します。

GKE クラスタとノードプールを作成する

GKE Autopilot クラスタまたは GKE Standard クラスタの TPU で Gemma をサービングできます。GKE マネージド DRANET は、分散 Pod の高性能ネットワーキング リソースを動的にリクエストして管理します。これにより、GKE は、手動で VPC を設定しなくても、アクセラレータ間の通信用にセカンダリ高速ネットワークを自動的にプロビジョニングできます。

Autopilot

  1. Cloud Shell で、Autopilot クラスタを作成します。

    gcloud container clusters create-auto ${CLUSTER_NAME} \
        --project=${PROJECT_ID} \
        --enable-ray-operator \
        --location=${REGION}
    
  2. クラスタと通信を行うように kubectl を構成します。

    gcloud container clusters get-credentials ${CLUSTER_NAME} \
        --location=${REGION}
    
  3. Autopilot モードで GKE マネージド DRANET を使用するには、リポジトリに用意されているカスタム ComputeClass リソースをデプロイして、動的ネットワーキングをオプトインします。

    apiVersion: cloud.google.com/v1
    kind: ComputeClass
    metadata:
      name: dranet-compute-class
    spec:
      nodePoolAutoCreation:
        enabled: true
      nodePoolConfig:
        dra:
          networking:
            enabled: true
      priorities:
      - machineType: ct6e-standard-4t
        acceleratorNetworkProfile: auto
  4. マニフェストをクラスタに適用します。

    kubectl apply -f ai-ml/gke-ray/rayserve/llm/tpu/networking/dranet-compute-class.yaml
    

標準

  1. Cloud Shell で、Ray オペレーターを有効にして GKE Dataplane V2 を使用する Standard クラスタを作成します。

    gcloud container clusters create ${CLUSTER_NAME} \
        --project=${PROJECT_ID} \
        --addons=RayOperator,GcsFuseCsiDriver \
        --machine-type=n2-standard-8 \
        --enable-dataplane-v2 \
        --workload-pool=${PROJECT_ID}.svc.id.goog \
        --location=${ZONE}
    
  2. DRANET ドライバを有効にして、マルチホスト TPU スライス ノードプールを作成します。

    gcloud container node-pools create v6e-16 \
        --location=${ZONE} \
        --cluster=${CLUSTER_NAME} \
        --machine-type=ct6e-standard-4t \
        --tpu-topology=4x4 \
        --num-nodes=4 \
        --enable-gvnic \
        --scopes=https://www.googleapis.com/auth/cloud-platform \
        --accelerator-network-profile=auto \
        --node-labels=cloud.google.com/gke-networking-dra-driver=true
    

ストレージと認証を構成する

Cloud Storage バケットを作成し、Rapid Cache インスタンスを初期化してモデルの読み込みを高速化します。次に、Hugging Face の認証を構成します。

  1. TPU ゾーンで、ストレージ バケットを作成し、Rapid Cache インスタンスを初期化します。

    gcloud storage buckets create gs://${GS_BUCKET} --project=${PROJECT_ID} --default-storage-class=STANDARD --location=${REGION}
    
    gcloud storage buckets anywhere-caches create gs://${GS_BUCKET} ${ZONE} \
        --ttl=1d \
        --admission-policy=ADMIT_ON_FIRST_MISS
    
  2. ID リンクを構成して、重みバケットを GKE Pod に安全にマウントできるようにします。まず、専用の IAM サービス アカウントを作成し、バケットの読み取り権限を付与します。

    gcloud iam service-accounts create ${GSA_NAME}
    
    gcloud storage buckets add-iam-policy-binding gs://${GS_BUCKET} \
        --member="serviceAccount:${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
        --role="roles/storage.objectAdmin"
    
  3. Workload Identity Federation for GKE バインディングを作成し、Kubernetes ServiceAccount オブジェクトにアノテーションを付けます。

    gcloud iam service-accounts add-iam-policy-binding ${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \
        --role="roles/iam.workloadIdentityUser" \
        --member="serviceAccount:${PROJECT_ID}.svc.id.goog[${NAMESPACE}/${KSA_NAME}]"
    
    kubectl create serviceaccount ${KSA_NAME} --namespace ${NAMESPACE}
    kubectl annotate serviceaccount ${KSA_NAME} --namespace ${NAMESPACE} iam.gke.io/gcp-service-account=${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com
    
  4. Gemma 4 モデルの重みをダウンロードするには、Hugging Face で Google のライセンス契約に同意する必要があります。Hugging Face の Gemma 4 モデルのページに移動します

  5. [Agree and access repository] をクリックして、ライセンス条項に同意します。

  6. Hugging Face アカウントの設定に移動し、アクセス トークンRead ロールで生成します。

  7. Hugging Face トークンをエクスポートし、Ray がモデルの重みを pull できるように Kubernetes Secret を作成します。

    export HF_TOKEN=YOUR_HUGGING_FACE_TOKEN
    
    kubectl create secret generic hf-secret \
      --from-literal=hf_api_token=${HF_TOKEN}
    

カスタム コンテナ イメージをビルドする

マルチホスト環境に必要な依存関係がすべて含まれていることを確認するには、vLLM の TPU イメージに基づいてカスタム イメージをビルドし、サービング スクリプトをコピーします。

  1. Artifact Registry リポジトリを作成します。

    gcloud artifacts repositories create ${REPO_NAME} \
        --repository-format=docker \
        --location=${REGION}
    
  2. プロジェクトに対して Docker を認証します。

    gcloud auth configure-docker ${REGION}-docker.pkg.dev
    
  3. サンプル リポジトリの Dockerfile を確認します。

    FROM vllm/vllm-tpu:v0.21.0
    
    ENV VLLM_TARGET_DEVICE=tpu
    ENV VLLM_XLA_CACHE_PATH=/data
    
    USER root
    
    RUN pip install --no-cache-dir -U \
        "https://s3-us-west-2.amazonaws.com/ray-wheels/master/75b85027a859439fae5634e49aa6443f6fbecfeb/ray-3.0.0.dev0-cp312-cp312-manylinux2014_x86_64.whl" && \
        pip install --no-cache-dir --no-deps "ray[llm]"
    
    COPY serve_tpu_multihost.py /home/ray/serve_tpu_multihost.py
  4. イメージをビルドして Artifact Registry に push します。

    docker build -t ${CUSTOM_IMAGE_URI} .
    docker push ${CUSTOM_IMAGE_URI}
    

モデルの重みを Cloud Storage に事前ステージングする

RayCluster をデプロイする前に、スタンドアロン Kubernetes Job を使用してモデルの重みを Cloud Storage バケットに直接事前ステージングすることで、モデルの読み込みパフォーマンスを最適化し、分散 TPU スライス全体で高可用性を確保します。この分離されたアプローチにより、協調的な並列ストリーミングが可能になり、クラスタの起動時間が短縮されます。

  1. ダウンローダー ジョブのマニフェストは、リポジトリにあります。マニフェスト構成を確認します。

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: model-downloader
    spec:
      ttlSecondsAfterFinished: 60
      template:
        metadata:
          annotations:
            gke-gcsfuse/volumes: "true"
            gke-gcsfuse/memory-limit: "0"
        spec:
          serviceAccountName: ${KSA_NAME}
          restartPolicy: OnFailure
          containers:
          - name: downloader
            image: python:3.10-slim
            command: ["/bin/sh", "-c"]
            args:
            - |
              pip install -U huggingface_hub filelock
    
              python -c '
              import filelock
    
              class DummyLock:
                  def __init__(self, *args, **kwargs): pass
                  def __enter__(self): return self
                  def __exit__(self, *args): pass
                  def acquire(self, *args, **kwargs): pass
                  def release(self, *args, **kwargs): pass
    
              filelock.FileLock = DummyLock
    
              from huggingface_hub import snapshot_download
              snapshot_download(
                  repo_id="google/gemma-4-31B-it", 
                  local_dir="/data/google/gemma-4-31B-it"
              )
              '
            env:
            - name: HF_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_api_token
            volumeMounts:
            - name: gcs-fuse-csi-ephemeral
              mountPath: /data
          volumes:
          - name: gcs-fuse-csi-ephemeral
            csi:
              driver: gcsfuse.csi.storage.gke.io
              volumeAttributes:
                bucketName: ${GS_BUCKET}
                mountOptions: "implicit-dirs"
  2. リポジトリ内のファイルを適用して、ダウンローダー ジョブを作成します。

    envsubst < ai-ml/gke-ray/rayserve/llm/tpu/components/model-downloader-job.yaml | kubectl apply -f -
    
  3. ダウンロード ストリームが成功を報告するまでジョブをモニタリングします。

    kubectl logs -f job/model-downloader
    

推論スクリプトを作成する

次の Python スクリプトは、Ray Serve の高レベルの LLMConfig ラッパーを搭載した Ray Serve アプリケーションを定義します。

  1. サンプル リポジトリの serve_tpu_multihost.py スクリプトを確認します。

    import os
    import ray
    from ray import serve
    from ray.serve.llm import LLMConfig, ModelLoadingConfig, LLMServingArgs, build_openai_app
    
    # Read configurations from environment variables
    MODEL_ID = os.environ.get("MODEL_ID", "google/gemma-4-31B-it")
    MODEL_SOURCE = os.environ.get("MODEL_SOURCE", "/data/google/gemma-4-31B-it")
    
    # TPU hardware options (i.e. TPU-V6E, TPU-V7X etc.)
    ACCELERATOR_TYPE = os.environ.get("ACCELERATOR_TYPE", "TPU-V6E")
    TPU_TOPOLOGY = os.environ.get("TPU_TOPOLOGY", "4x4")
    
    # vLLM engine parameters
    TENSOR_PARALLEL_SIZE = int(os.environ.get("TENSOR_PARALLEL_SIZE", "16"))
    MAX_MODEL_LEN = int(os.environ.get("MAX_MODEL_LEN", "8192"))
    MAX_NUM_BATCHED_TOKENS = int(os.environ.get("MAX_NUM_BATCHED_TOKENS", "4096"))
    
    # Define the multi-host TPU LLM config
    llm_config = LLMConfig(
        model_loading_config=dict(
            model_id=MODEL_ID,
            model_source=MODEL_SOURCE
        ),
        accelerator_type=ACCELERATOR_TYPE,
        accelerator_config={"kind": "tpu", "topology": TPU_TOPOLOGY},
        engine_kwargs={
            "tensor_parallel_size": TENSOR_PARALLEL_SIZE,
            "max_model_len": MAX_MODEL_LEN,
            "max_num_batched_tokens": MAX_NUM_BATCHED_TOKENS,
            "distributed_executor_backend": "ray",
        }
    )
    
    deployment = build_openai_app(
        LLMServingArgs(
            llm_configs=[llm_config]
        )
    )

Ray LLM API について

このスクリプトは、Ray Serve のネイティブ ray.serve.llm ライブラリを利用して、マルチホスト TPU オーケストレーションの複雑さを抽象化します。vLLM エンジンをラップすることで、Ray Serve LLM は、本番環境での高度に分散された推論ワークロード向けに特別に設計された、高性能でスケーラブルなフレームワークを提供します。

Ray LLM API を使用すると、次のような重要なメリットがあります。

  • マルチノード デプロイ: Ray Serve LLM を使用すると、複数の分散ホスト(TPU マルチホスト スライスなど)にまたがる大規模なモデルを、ネイティブに自動プレースメント、調整、トポロジ分散でサービングできます。
  • vLLM の互換性: Ray Serve LLM は、vLLM のサーバーと連携する OpenAI 互換の API を提供します。また、Kubernetes クラスタ全体でワークロードをスケーリングしながら、vLLM の高度な機能セット(構造化出力、マルチモーダル機能、推論モデルなど)にアクセスすることもできます。
  • 本番環境に対応した機能: Ray Serve LLM には、組み込みの自動スケーリング、キャッシュ ヒットを最大化するためのカスタム リクエスト ルーティング、指標とオブザーバビリティの組み込み統合など、エンタープライズ グレードの機能が含まれています。

提供されている推論スクリプトでは、デプロイは次の 2 つの主要コンポーネントで定義されます。

  • LLMConfig: このオブジェクトは、サービング構成を定義します。モデルソース、vLLM のエンジン パラメータ、accelerator_config を指定します。{"kind": "tpu", "topology": "4x4"} を設定すると、Ray Serve LLM は、物理 16 チップ TPU v6e スライスに正確にマッピングされる分散プレースメント グループを自動的にプロビジョニングします。
  • build_openai_app: この API は、構成された vLLM エンジンを OpenAI 互換の FastAPI サーバーに自動的にラップします。これにより、カスタム サーバーコードを記述しなくても、業界標準の REST API(/v1/chat/completions など)をすぐに使用できます。

RayService をデプロイする

動的リソース割り当て(DRA)ネットワーキング構成と RayService サービング マニフェストをデプロイします。

  1. リポジトリに用意されている ResourceClaimTemplate をデプロイして、各ノードで使用可能なすべての NetDevice インターフェースをリクエストします。

    apiVersion: resource.k8s.io/v1
    kind: ResourceClaimTemplate
    metadata:
      name: all-netdev
    spec:
      spec:
        devices:
          requests:
          - name: req-netdev
            exactly:
              deviceClassName: netdev.google.com
              allocationMode: All
  2. テンプレート マニフェストをクラスタに適用します。

    kubectl apply -f ai-ml/gke-ray/rayserve/llm/tpu/networking/all-netdev-template.yaml
    
  3. RayService サービング マニフェストは、リポジトリにあります。マニフェスト構成を確認します。

    apiVersion: ray.io/v1
    kind: RayService
    metadata:
      name: vllm-tpu-multihost
      labels:
        ai.gke.io/model: "gemma-4-31B-it"
        ai.gke.io/inference-server: "vllm"
    spec:
      serveConfigV2: |
        http_options:
          host: 0.0.0.0
          port: 8000
        applications:
          - name: llm
            import_path: ai-ml.gke-ray.rayserve.llm.tpu.serve_tpu_multihost:deployment
            runtime_env:
              working_dir: "https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/archive/main.zip"
              env_vars:
                # Use local disk to prevent multi-host GCSFuse race conditions
                VLLM_XLA_CACHE_PATH: "/tmp/vllm_xla_cache"
      rayClusterConfig:
        headGroupSpec:
          rayStartParams: {}
          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: $KSA_NAME
              containers:
              - name: ray-head
                image: $CUSTOM_IMAGE_URI
                imagePullPolicy: Always
                ports:
                - containerPort: 6379
                  name: gcs
                - containerPort: 8265
                  name: dashboard
                - containerPort: 10001
                  name: client
                - containerPort: 8000
                  name: serve
                resources:
                  limits:
                    cpu: "2"
                    memory: 16Gi
                  requests:
                    cpu: "2"
                    memory: 16Gi
                volumeMounts:
                - name: dshm
                  mountPath: /dev/shm
                - name: gcs-fuse-csi-ephemeral
                  mountPath: /data
              volumes:
              - name: dshm
                emptyDir:
                  medium: Memory
              - name: gke-gcsfuse-cache
                emptyDir:
                  medium: Memory
              - name: gcs-fuse-csi-ephemeral
                csi:
                  driver: gcsfuse.csi.storage.gke.io
                  volumeAttributes:
                    bucketName: $GS_BUCKET
                    mountOptions: "implicit-dirs"
        workerGroupSpecs:
        - groupName: tpu-group
          replicas: 1
          minReplicas: 1
          maxReplicas: 1
          numOfHosts: 4
          rayStartParams: {}
          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: $KSA_NAME
              containers:
                - name: ray-worker
                  image: $CUSTOM_IMAGE_URI
                  imagePullPolicy: Always
                  resources:
                    limits:
                      cpu: "20"
                      google.com/tpu: "4"
                      memory: 200Gi
                    requests:
                      cpu: "20"
                      google.com/tpu: "4"
                      memory: 200Gi
                    claims:
                    - name: netdev
                  env:
                    - name: HF_HOME
                      value: "/data/huggingface"
                    - name: HF_TOKEN
                      valueFrom:
                        secretKeyRef:
                          name: hf-secret
                          key: hf_api_token
                    - name: JAX_PLATFORMS
                      value: "tpu,cpu"
                    - name: NODE_IP
                      valueFrom:
                        fieldRef:
                          fieldPath: status.hostIP
                    - name: VBAR_CONTROL_SERVICE_URL
                      value: $(NODE_IP):8353
                    - name: TPU_MULTIHOST_BACKEND
                      value: "ray"
                    - name: TPU_BACKEND_TYPE
                      value: "jax"
                    - name: ENABLE_PJRT_COMPATIBILITY
                      value: "true"
                  volumeMounts:
                  - name: dshm
                    mountPath: /dev/shm
                  - name: gcs-fuse-csi-ephemeral
                    mountPath: /data
              volumes:
              - name: dshm
                emptyDir:
                  medium: Memory
              - name: gke-gcsfuse-cache
                emptyDir:
                  medium: Memory
              - name: gcs-fuse-csi-ephemeral
                csi:
                  driver: gcsfuse.csi.storage.gke.io
                  volumeAttributes:
                    bucketName: $GS_BUCKET
                    mountOptions: "implicit-dirs"
              resourceClaims:
                - name: netdev
                  resourceClaimTemplateName: all-netdev
              nodeSelector:
                cloud.google.com/gke-tpu-accelerator: tpu-v6e-slice
                cloud.google.com/gke-tpu-topology: 4x4
  4. マニフェストを使用してサービスをデプロイします。

    Autopilot

    1. Autopilot クラスタにサービスをデプロイするには、まずマニフェストをダウンロードし、ローカルで編集して、オプトイン ComputeClass nodeSelector を追加する必要があります。これは、Autopilot での DRANET ネットワーキングに必要です。

      curl -O https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/main/ai-ml/gke-ray/rayserve/llm/tpu/ray-service.tpu-v6e-multihost.yaml
      
    2. nodeSelector フィールドにラベルを追加して、次のようになります。

      nodeSelector:
        cloud.google.com/gke-tpu-accelerator: tpu-v6e-slice
        cloud.google.com/gke-tpu-topology: 4x4
        cloud.google.com/compute-class: dranet-compute-class
      
    3. 次に、変更したローカル マニフェストを使用してサービスをデプロイします。

      envsubst < ray-service.tpu-v6e-multihost.yaml | kubectl apply -f -
      

    標準

    Standard クラスタにサービスをデプロイするには、リポジトリからマニフェストを直接デプロイします。

    envsubst < ai-ml/gke-ray/rayserve/llm/tpu/ray-service.tpu-v6e-multihost.yaml | kubectl apply -f -
    

検証

  1. RayService が利用可能になるまで待ちます。

    kubectl wait --for=condition=Ready --timeout=1800s rayservice/vllm-tpu-multihost
    
  2. モデルが正常に読み込まれたことを確認するには、Ray ヘッド Pod のログを表示します。

    kubectl logs -f -l ray.io/node-type=head -c ray-head
    

モデルをサービングする

このセクションでは、モデルを操作します。モデルが完全にダウンロードされたことを確認してから、次の手順に進んでください。

ポート転送をセットアップする

次のコマンドを実行して、モデルへのポート転送を設定します。

kubectl port-forward svc/vllm-tpu-multihost-head-svc 8000:8000 2>&1 >/dev/null &

curl を使用してモデルを操作する

このセクションでは、基本的なスモークテストを実行して、デプロイされた Gemma 4 モデルを確認する方法について説明します。

新しいターミナル セッションで、curl を使用してモデルとチャットします。

curl -X POST http://127.0.0.1:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "google/gemma-4-31B-it",
        "messages": [
            {
              "role": "user",
              "content": "Why is GKE managed DRANET preferred for multi-host TPU networking?"
            }
        ],
        "max_tokens": 256
    }'

出力は次のようになります。

{
  "id": "chatcmpl-392692d3-5325-4832-a3a3-0b084c1045b0",
  "object": "chat.completion",
  "created": 1779883255,
  "model": "google/gemma-4-31B-it",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "To understand why GKE-managed **DRANET** (Distributed RANET) is preferred for multi-host TPU networking, it is first necessary to understand the fundamental challenge of TPU pods: **the need for massive, low-latency, all-to-all communication.**\n\nWhen you scale a model across multiple TPU hosts (multi-host), the hosts must synchronize gradients and weights constantly. Standard TCP/IP networking introduces too much overhead (latency and CPU jitter) for these operations.\n\nHere is the detailed breakdown of why GKE-managed DRANET is the preferred architecture:\n\n### 1. Bypassing the Kernel (Zero-Copy Networking)\nStandard networking requires the operating system kernel to handle packets, moving data from the network card to kernel space and then to user space.\n*   **The DRANET Advantage:** DRANET implements a specialized networking stack that allows for **Kernel Bypass**. It enables the TPU hardware/drivers to write data directly into the memory of the destination host. This reduces latency and eliminates the CPU overhead associated with processing network interrupts.\n\n### 2. High-Bandwidth, Low-Latency Interconnect\nMulti-host TPU training relies on a specialized topology (like a 2D or 3D"
      },
      "finish_reason": "length"
    }
  ]
}

(省略可)Gradio のチャット インターフェースでモデルを操作する

このセクションでは、指示用にチューニングされたモデルを操作できるウェブチャット アプリケーションを作成します。

Gradio は、chatbot のユーザー インターフェースを作成する ChatInterface ラッパーを含む Python ライブラリです。

チャット インターフェースをデプロイする

チャット インターフェースのマニフェストは、リポジトリにあります。マニフェスト構成を確認します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gradio
  labels:
    app: gradio
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gradio
  template:
    metadata:
      labels:
        app: gradio
    spec:
      containers:
      - name: gradio
        image: us-docker.pkg.dev/google-samples/containers/gke/gradio-app:v1.0.7
        resources:
          requests:
            cpu: "250m"
            memory: "512Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
        env:
        - name: CONTEXT_PATH
          value: "/v1/chat/completions"
        - name: HOST
          value: "http://vllm-tpu-multihost-serve-svc:8000"
        - name: LLM_ENGINE
          value: "openai-chat"
        - name: MODEL_ID
          value: "google/gemma-4-31B-it"
        - name: DISABLE_SYSTEM_MESSAGE
          value: "true"
        ports:
        - containerPort: 7860
---
apiVersion: v1
kind: Service
metadata:
  name: gradio
spec:
  selector:
    app: gradio
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 7860
  type: ClusterIP

次のようにマニフェストを適用します。

kubectl apply -f ai-ml/gke-ray/rayserve/llm/tpu/components/gradio.yaml

Deployment が利用可能になるまで待ちます。

kubectl wait --for=condition=Available --timeout=900s deployment/gradio

チャット インターフェースを使用する

Cloud Shell で、次のコマンドを実行します。

kubectl port-forward service/gradio 8080:8080

これにより、Cloud Shell から Gradio サービスへのポート転送が作成されます。

Cloud Shell タスクバーの右上にある [ウェブでプレビュー] アイコン [ウェブでプレビュー] ボタン をクリックします。[ポート 8080 でプレビュー] をクリックします。ブラウザで新しいタブが開きます。

Gradio のチャット インターフェースを使用して Gemma を操作します。プロンプトを追加して [送信] をクリックします。

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

KubeRay で実行されているモデルのオブザーバビリティ指標のダッシュボードを表示するには、GKE 専用の Ray ダッシュボードを使用します。

クラスタを構成してオブザーバビリティ ダッシュボードにアクセスする手順については、Google Kubernetes Engine(GKE)上の RayCluster のログと指標を収集して表示するをご覧ください。

Ray ダッシュボードにアクセスする

Ray アクターのステータスを確認し、詳細なアプリケーション ログを表示して、Ray でノードレベルの使用率をネイティブにモニタリングするには、Ray ダッシュボードにアクセスします。

  1. Ray ヘッドノード サービスをローカルマシンにポート転送します。

    kubectl port-forward svc/vllm-tpu-multihost-head-svc 8265:8265
    
  2. ブラウザを開いて http://localhost:8265 に移動します。 Cloud Shell を使用している場合は、[ウェブでプレビュー] ボタンをクリックし、[ポート 8265 でプレビュー] を選択します。

  3. vLLM デプロイ、モデル レプリカのヘルス、クエリ レイテンシを表示するには、[Serve] タブをクリックします。

クリーンアップ

このチュートリアルで使用したリソースについて Google Cloud アカウントに課金されないようにするには、リソースを削除します。

  1. RayService を削除します。

    kubectl delete rayservice vllm-tpu-multihost
    
  2. GKE クラスタを削除します。

    gcloud container clusters delete ${CLUSTER_NAME} --zone=${ZONE}
    

次のステップ