A4 VM で Dynamo と SGLang を使用して、PD 分離により GKE で Llama 3.1 405B をサービングする

このチュートリアルでは、 Google Cloudの Google Kubernetes Engine(GKE)に Llama 3.1 405B(nvidia/Llama-3.1-405B-Instruct-FP8)をデプロイして提供する方法について説明します。これは、FP8 に量子化された 4,050 億パラメータの指示調整済みモデルです。このデプロイでは、Cluster Toolkit、合計 16 個の NVIDIA B200 GPU を搭載した 2 つの A4(a4-highgpu-8g)仮想マシン(VM)インスタンス、NVIDIA Dynamo、単一ホストのプリフィル デコード(PD)分離を備えた SGLang サービング フレームワークを使用します。

このチュートリアルで説明するデプロイ構成では、Cluster Toolkit を使用して標準モードで GKE クラスタをプロビジョニングします。クラスタには、GPUDirect リモート ダイレクト メモリ アクセス(RDMA)ネットワーキングを介して接続された 2 つの a4-highgpu-8g ノードが含まれています。次に、Grove ギャング スケジューリングを使用して KAI Scheduler と NVIDIA Dynamo プラットフォームをインストールします。最後に、テンソル並列処理と FP8 KV キャッシュを使用して、2 つの単一ホスト 8 GPU ワーカーにプリフィルとデコードを分離する DynamoGraphDeployment カスタム リソースをデプロイします。

目標

  • Cluster Toolkit をインストールし、Standard モードで 2 ノードの A4 GKE クラスタをプロビジョニングします。
  • クラスタに KAI Scheduler と NVIDIA Dynamo プラットフォームを Grove ギャング スケジューリングとともにインストールします。
  • 1 つの単一ホスト A4 プリフィル ワーカーと 1 つの単一ホスト A4 デコード ワーカーを使用して、PD 分離 SGLang 推論サーバーをデプロイします。
  • Dynamo フロントエンド ルーターにチャット完了リクエストを送信します。
  • サービング ベンチマーク ワークロードを実行します。
  • デプロイしたリソースをクリーンアップします。

費用

このドキュメントでは、課金対象である次のGoogle Cloudコンポーネントを使用します。

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

始める前に

チュートリアルの環境を設定します。

  1. Google Cloud CLI をインストールして初期化し、kubectl と Helm(バージョン 3.10 以降)をインストールします。Cloud Shell を使用する場合、これらのツールはプリインストールされています。
  2. Cloud Shell ではなく Linux または macOS ワークステーションからこのチュートリアルを実行する場合は、Terraform や Git などの必要な Cluster Toolkit の依存関係をインストールします。
  3. Google Cloud プロジェクトで Kubernetes Engine API、Compute Engine API、Cloud Storage API、Identity and Access Management API、Cloud Resource Manager API、Service Usage API を有効にします。

    API の有効化

Hugging Face アクセス トークンを取得する

このチュートリアルを使用するには、Hugging Face アクセス トークンが必要です。Hugging Face で無料アカウントに登録できます。アカウントを作成したら、アクセス トークンを生成します。

  1. [Welcome to Hugging Face] ページで、アカウントのアバターをクリックし、[アクセス トークン] を選択します。
  2. [アクセス トークン] ページで、[Create new token] をクリックします。
  3. [Read] トークン タイプを選択し、トークンの名前を入力します。
  4. アクセス トークンが表示されます。トークンを安全な場所に保存します。

必要なロール

このチュートリアルを完了するために必要な権限を取得するには、プロジェクトに対する次の IAM ロールを付与するよう管理者に依頼してください。

ロールの付与については、プロジェクト、フォルダ、組織へのアクセスを管理するをご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

環境変数を設定する

このチュートリアル全体で使用する環境変数をエクスポートします。

export PROJECT_ID="YOUR_PROJECT_ID"
export REGION="YOUR_REGION"
export ZONE="YOUR_ZONE"
export CLUSTER_NAME="YOUR_CLUSTER_NAME"
export RESERVATION_NAME="YOUR_RESERVATION_NAME"
export GCS_BUCKET="YOUR_BUCKET_NAME"
export HF_TOKEN="YOUR_HF_TOKEN"
export CLUSTER_TOOLKIT_VERSION="v1.104.0"
export DYNAMO_RELEASE_VERSION="1.5.0"

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

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

  • YOUR_PROJECT_ID: 実際の Google Cloudプロジェクトの ID。
  • YOUR_REGION: A4 容量が配置され、クラスタをデプロイするリージョン(us-central1 など)。
  • YOUR_ZONE: A4 容量が配置されているゾーン(us-central1-b など)。
  • YOUR_CLUSTER_NAME: GKE クラスタと Cluster Toolkit デプロイの名前。生成されたノードプール サービス アカウント ID(YOUR_CLUSTER_NAME-gke-np-sa)が Identity and Access Management(IAM)の 30 文字の制限内に収まるように、20 文字以下の名前を使用します。
  • YOUR_RESERVATION_NAME: A4 予約の名前。
  • YOUR_BUCKET_NAME: Cluster Toolkit の Terraform 状態を保存する Cloud Storage バケットのグローバルに一意の名前。
  • YOUR_HF_TOKEN: Hugging Face アクセス トークン。

GKE クラスタを作成する

Cluster Toolkit をダウンロードし、2 つの a4-highgpu-8g ノード、GPUDirect RDMA ネットワーキング、DRA サポートを備えた標準モードの GKE クラスタをプロビジョニングします。

  1. Google Cloud CLI にログインし、Terraform のアプリケーションのデフォルト認証情報を生成します。

    gcloud auth login
    gcloud auth application-default login
  2. CLUSTER_TOOLKIT_VERSION(v1.104.0)で指定されたバージョンのビルド済み Cluster Toolkit バンドルをダウンロードして展開します。

    TAG="${CLUSTER_TOOLKIT_VERSION:-v1.104.0}"
    OS="linux"
    ARCH="amd64"
    mkdir -p cluster-toolkit && curl -L "https://github.com/GoogleCloudPlatform/cluster-toolkit/releases/download/${TAG}/gcluster_bundle_${OS}_${ARCH}.tgz" | tar -xz -C cluster-toolkit

    macOS または arm64 ワークステーションでこのコマンドを実行する場合は、プラットフォームに合わせて OS="mac" または ARCH="arm64" を設定します。

  3. Cluster Toolkit デプロイの Terraform 状態を保存するには、オブジェクト バージョニングを有効にした Cloud Storage バケットを作成します。

    gcloud storage buckets create "gs://${GCS_BUCKET}" \
        --default-storage-class=STANDARD \
        --project="${PROJECT_ID}" \
        --location="${REGION}" \
        --uniform-bucket-level-access
    gcloud storage buckets update "gs://${GCS_BUCKET}" --versioning
  4. 2 つの a4-highgpu-8g ノードの cluster-toolkit/examples/gke-a4/gke-a4-deployment.yaml デプロイ構成ファイルを作成します。

    cat <<EOF > cluster-toolkit/examples/gke-a4/gke-a4-deployment.yaml
    terraform_backend_defaults:
      type: gcs
      configuration:
        bucket: ${GCS_BUCKET}
    
    vars:
      project_id: ${PROJECT_ID}
      deployment_name: ${CLUSTER_NAME}
      region: ${REGION}
      zone: ${ZONE}
      static_node_count: 2
      authorized_cidr: 0.0.0.0/0
      reservation_affinity:
        consume_reservation_type: SPECIFIC_RESERVATION
        specific_reservations:
        - name: ${RESERVATION_NAME}
    EOF

    デフォルトでは、デプロイ ファイルは特定の予約を使用するように構成されています。特定の予約がない場合は、クラスタをデプロイする前に、cluster-toolkit/examples/gke-a4/gke-a4-deployment.yaml を更新して、Spot VM や Flex Start VM などの代替の使用オプションを使用できます。構成手順については、GKE の使用オプションをご覧ください。

  5. cluster-toolkit ディレクトリに移動し、gcluster deploy コマンドを使用して GKE クラスタをデプロイしてから、作業ディレクトリに戻ります。

    cd cluster-toolkit
    ./gcluster deploy \
        -d examples/gke-a4/gke-a4-deployment.yaml \
        examples/gke-a4/gke-a4.yaml \
        --auto-approve -w
    cd ..

    クラスタの作成には約 20 ~ 30 分かかります。--auto-approve フラグを指定せずに ./gcluster deploy を実行する場合は、提案された変更を適用するために、プロンプトが表示されたら「a」と入力します。

  6. クラスタと通信するように kubectl 認証情報を構成します。

    gcloud container clusters get-credentials "${CLUSTER_NAME}" \
        --location="${REGION}" \
        --project="${PROJECT_ID}"

KAI Scheduler と NVIDIA Dynamo をインストールする

Hugging Face Secret を作成し、Grove ギャング スケジューリングを使用して KAI Scheduler と NVIDIA Dynamo プラットフォームをインストールして、クラスタを準備します。

  1. Hugging Face アクセス トークンを保存する hf-secret という名前の Kubernetes Secret を作成します。

    kubectl create secret generic hf-secret \
        --from-literal=hf_api_token="${HF_TOKEN}" \
        --dry-run=client -o yaml | kubectl apply -f -
  2. NVIDIA Dynamo プラットフォームの Helm チャート(v1.5.0)をダウンロードし、KAI Scheduler をインストールして、Grove を有効にした Dynamo プラットフォームをインストールします。

    RELEASE_VERSION="${DYNAMO_RELEASE_VERSION:-1.5.0}"
    helm fetch "https://helm.ngc.nvidia.com/nvidia/ai-dynamo/charts/dynamo-platform-${RELEASE_VERSION}.tgz"
    tar -zxf "dynamo-platform-${RELEASE_VERSION}.tgz"
    
    helm upgrade --install kai-scheduler ./dynamo-platform/charts/kai-scheduler \
        --set scheduler.args.default-staleness-grace-period="-1s" \
        --set topologyMigration.enabled=false
    
    kubectl wait --for=condition=Available deployment/kai-operator --timeout=120s
    until kubectl get deployment/queue-controller >/dev/null 2>&1; do sleep 2; done
    kubectl wait --for=condition=Available deployment/queue-controller --timeout=120s
    
    helm upgrade --install dynamo-platform ./dynamo-platform \
        --set global.grove.install=true \
        --set global.grove.enabled=true \
        --set global.kai-scheduler.enabled=true

単一ホストの分離された SGLang サーバーをデプロイする

ワークロード マニフェスト(llama3.1-405b-singlehost-a4.yaml)は、DRA を介してノードのマルチ NIC RDMA デバイス(mrdma.google.com)を割り当てる Kubernetes ResourceClaimTemplate(all-mrdma)と、Grove ギャング スケジューリングが有効になっている NVIDIA Dynamo DynamoGraphDeployment(llama3-405b-a4-disagg)を定義します。デプロイメントは次のものから構成されます。

  • フロントエンド(Frontend): クライアント リクエストを受け入れ、登録済みのプリフィル ワーカーとデコード ワーカーを検出し、分離されたリクエスト ルーティングを調整する 1 つのルーター レプリカを実行します。
  • プリフィル ワーカー(Prefill): 8 個の NVIDIA B200 GPU を搭載した 1 つの a4-highgpu-8g ノードで単一ホスト ワーカーを実行します。起動時に、Pod は NCCL/gIB 環境をソースとし、nvidia/Llama-3.1-405B-Instruct-FP8 チェックポイントを Hugging Face Hub からノードのローカル NVMe SSD にダウンロードし、次のフラグを使用して --disaggregation-mode prefill で python3 -m dynamo.sglang を起動します。
    • --tensor-parallel-size 8
    • --kv-cache-dtype fp8_e4m3
    • --context-length 16384
    • --mem-fraction-static 0.85
  • デコード ワーカー(Decode): 8 個の NVIDIA B200 GPU を搭載した 2 番目の a4-highgpu-8g ノードで単一ホスト ワーカーを実行します。起動時に、Pod はモデルの重みをノードのローカル NVMe SSD にキャッシュし、次のフラグを使用して --disaggregation-mode decode で python3 -m dynamo.sglang を起動します。
    • --tensor-parallel-size 8
    • --kv-cache-dtype fp8_e4m3
    • --context-length 16384
    • --mem-fraction-static 0.85

分離された推論サーバーをデプロイしてモニタリングします。

  1. llama3.1-405b-singlehost-a4.yaml ワークロード マニフェストをダウンロードします。

    curl -O https://raw.githubusercontent.com/GoogleCloudSamples/AIHypercomputerSamples/refs/heads/main/gpu/inference/llama3-405b/llama3.1-405b-singlehost-a4.yaml

    または、次の内容の llama3.1-405b-singlehost-a4.yaml という名前のファイルを作成します。

    # ==============================================================================
    # Single-Host Disaggregated Serving of Llama 3.1 405B FP8 on GKE
    # using NVIDIA Dynamo Platform (v1.5.0) and SGLang on GPU A4 (2 x a4-highgpu-8g)
    # Topology: 1-node Prefill (8 x B200, TP=8) + 1-node Decode (8 x B200, TP=8)
    # ==============================================================================
    apiVersion: resource.k8s.io/v1
    kind: ResourceClaimTemplate
    metadata:
      name: all-mrdma
    spec:
      spec:
        devices:
          requests:
            - name: req-mrdma
              exactly:
                deviceClassName: mrdma.google.com
                allocationMode: All
    ---
    apiVersion: nvidia.com/v1alpha1
    kind: DynamoGraphDeployment
    metadata:
      name: llama3-405b-a4-disagg
      annotations:
        nvidia.com/enable-grove: "true"
    spec:
      backendFramework: sglang
      services:
        # --------------------------------------------------------------------------
        # FRONTEND: Dynamo OpenAI-Compatible Router (`python3 -m dynamo.frontend`)
        # --------------------------------------------------------------------------
        Frontend:
          componentType: frontend
          replicas: 1
          resources:
            requests:
              cpu: "8"
              memory: "32Gi"
            limits:
              cpu: "8"
              memory: "32Gi"
          extraPodSpec:
            tolerations:
              - key: "nvidia.com/gpu"
                operator: "Exists"
                effect: "NoSchedule"
            mainContainer:
              image: nvcr.io/nvidia/ai-dynamo/sglang-runtime:1.5.0
              command: ["/bin/bash", "-c"]
              args:
                - |
                  set -ex
                  exec python3 -m dynamo.frontend --http-port 8000
    
        # --------------------------------------------------------------------------
        # PREFILL WORKER: 1 x GPU A4 (`a4-highgpu-8g`, 8 x B200 GPUs, TP=8)
        # --------------------------------------------------------------------------
        Prefill:
          componentType: worker
          subComponentType: prefill
          replicas: 1
          livenessProbe:
            httpGet:
              path: /live
              port: system
            initialDelaySeconds: 600
            periodSeconds: 60
            timeoutSeconds: 30
            failureThreshold: 60
          readinessProbe:
            httpGet:
              path: /health
              port: system
            initialDelaySeconds: 120
            periodSeconds: 30
            timeoutSeconds: 30
            failureThreshold: 60
          sharedMemory:
            size: 128Gi
          resources:
            requests:
              gpu: "8"
              cpu: "128"
              memory: "1500Gi"
            limits:
              gpu: "8"
              cpu: "128"
              memory: "2000Gi"
          envs:
            - name: MODEL_PATH
              value: "nvidia/Llama-3.1-405B-Instruct-FP8"
            - name: HF_HOME
              value: "/data"
            - name: HF_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_api_token
                  optional: true
            - name: DYN_SYSTEM_ENABLED
              value: "true"
            - name: DYN_SYSTEM_USE_ENDPOINT_HEALTH_STATUS
              value: "[\"generate\"]"
            - name: DYN_SYSTEM_PORT
              value: "9090"
            - name: LD_LIBRARY_PATH
              value: "/usr/local/gib/lib64:/usr/local/nvidia/lib64"
            - name: GLOO_SOCKET_IFNAME
              value: "eth0"
            - name: WITH_NVIDIA_PEERMEM
              value: "0"
            # Xet CAS downloads returned unretried 429s; plain HTTP downloads back off on 429.
            - name: HF_HUB_DISABLE_XET
              value: "1"
          extraPodSpec:
            resourceClaims:
              - name: rdma
                resourceClaimTemplateName: all-mrdma
            nodeSelector:
              cloud.google.com/gke-accelerator: nvidia-b200
              cloud.google.com/gke-gpu: "true"
              kubernetes.io/arch: amd64
            tolerations:
              - key: "nvidia.com/gpu"
                operator: "Exists"
                effect: "NoSchedule"
              - key: "kubernetes.io/arch"
                operator: "Equal"
                value: "amd64"
                effect: "NoSchedule"
            mainContainer:
              image: nvcr.io/nvidia/ai-dynamo/sglang-runtime:1.5.0
              resources:
                claims:
                  - name: rdma
              startupProbe:
                httpGet:
                  path: /live
                  port: system
                initialDelaySeconds: 120
                periodSeconds: 30
                timeoutSeconds: 10
                failureThreshold: 120
              command: ["/bin/bash", "-c"]
              args:
                - |
                  set -ex
                  if [ -f /usr/local/gib/scripts/set_nccl_env.sh ]; then
                    . /usr/local/gib/scripts/set_nccl_env.sh
                  fi
    
                  # Pre-download with huggingface_hub, which backs off on HTTP 429s. Dynamo's built-in
                  # downloader (ModelExpress) aborts on the first 429 and skips fetching if weights are cached.
                  echo "=== [Dynamo Prefill Worker] Ensuring weights are cached in ${HF_HOME:-/data} ==="
                  python3 -c "import os; from huggingface_hub import snapshot_download; snapshot_download(os.environ['MODEL_PATH'], max_workers=16)"
                  # --host 0.0.0.0 is required so MooncakeKVBootstrapServer binds to 0.0.0.0:30001 instead of 127.0.0.1:30001.
                  echo "=== [Dynamo Prefill Worker] Launching dynamo.sglang ==="
                  exec python3 -m dynamo.sglang \
                    --model-path "${MODEL_PATH}" \
                    --host 0.0.0.0 \
                    --disaggregation-mode prefill \
                    --disaggregation-bootstrap-port 30001 \
                    --tensor-parallel-size 8 \
                    --kv-cache-dtype fp8_e4m3 \
                    --context-length 16384 \
                    --mem-fraction-static 0.85 \
                    --enable-metrics
              volumeMounts:
                - name: library-dir-host
                  mountPath: /usr/local/nvidia
                - name: gib
                  mountPath: /usr/local/gib
                - name: data-volume
                  mountPath: /data
            volumes:
              - name: library-dir-host
                hostPath:
                  path: /home/kubernetes/bin/nvidia
              - name: gib
                hostPath:
                  path: /home/kubernetes/bin/gib
              - name: data-volume
                emptyDir: {}
    
        # --------------------------------------------------------------------------
        # DECODE WORKER: 1 x GPU A4 (`a4-highgpu-8g`, 8 x B200 GPUs, TP=8)
        # --------------------------------------------------------------------------
        Decode:
          componentType: worker
          subComponentType: decode
          replicas: 1
          livenessProbe:
            httpGet:
              path: /live
              port: system
            initialDelaySeconds: 600
            periodSeconds: 60
            timeoutSeconds: 30
            failureThreshold: 60
          readinessProbe:
            httpGet:
              path: /health
              port: system
            initialDelaySeconds: 120
            periodSeconds: 30
            timeoutSeconds: 30
            failureThreshold: 60
          sharedMemory:
            size: 128Gi
          resources:
            requests:
              gpu: "8"
              cpu: "128"
              memory: "1500Gi"
            limits:
              gpu: "8"
              cpu: "128"
              memory: "2000Gi"
          envs:
            - name: MODEL_PATH
              value: "nvidia/Llama-3.1-405B-Instruct-FP8"
            - name: HF_HOME
              value: "/data"
            - name: HF_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_api_token
                  optional: true
            - name: DYN_SYSTEM_ENABLED
              value: "true"
            - name: DYN_SYSTEM_USE_ENDPOINT_HEALTH_STATUS
              value: "[\"generate\"]"
            - name: DYN_SYSTEM_PORT
              value: "9090"
            - name: LD_LIBRARY_PATH
              value: "/usr/local/gib/lib64:/usr/local/nvidia/lib64"
            - name: GLOO_SOCKET_IFNAME
              value: "eth0"
            - name: WITH_NVIDIA_PEERMEM
              value: "0"
            # Xet CAS downloads returned unretried 429s; plain HTTP downloads back off on 429.
            - name: HF_HUB_DISABLE_XET
              value: "1"
          extraPodSpec:
            resourceClaims:
              - name: rdma
                resourceClaimTemplateName: all-mrdma
            nodeSelector:
              cloud.google.com/gke-accelerator: nvidia-b200
              cloud.google.com/gke-gpu: "true"
              kubernetes.io/arch: amd64
            tolerations:
              - key: "nvidia.com/gpu"
                operator: "Exists"
                effect: "NoSchedule"
              - key: "kubernetes.io/arch"
                operator: "Equal"
                value: "amd64"
                effect: "NoSchedule"
            mainContainer:
              image: nvcr.io/nvidia/ai-dynamo/sglang-runtime:1.5.0
              resources:
                claims:
                  - name: rdma
              startupProbe:
                httpGet:
                  path: /live
                  port: system
                initialDelaySeconds: 120
                periodSeconds: 30
                timeoutSeconds: 10
                failureThreshold: 120
              command: ["/bin/bash", "-c"]
              args:
                - |
                  set -ex
                  if [ -f /usr/local/gib/scripts/set_nccl_env.sh ]; then
                    . /usr/local/gib/scripts/set_nccl_env.sh
                  fi
    
                  # Pre-download with huggingface_hub, which backs off on HTTP 429s. Dynamo's built-in
                  # downloader (ModelExpress) aborts on the first 429 and skips fetching if weights are cached.
                  echo "=== [Dynamo Decode Worker] Ensuring weights are cached in ${HF_HOME:-/data} ==="
                  python3 -c "import os; from huggingface_hub import snapshot_download; snapshot_download(os.environ['MODEL_PATH'], max_workers=16)"
                  echo "=== [Dynamo Decode Worker] Launching dynamo.sglang ==="
                  exec python3 -m dynamo.sglang \
                    --model-path "${MODEL_PATH}" \
                    --host 0.0.0.0 \
                    --disaggregation-mode decode \
                    --disaggregation-bootstrap-port 30001 \
                    --tensor-parallel-size 8 \
                    --kv-cache-dtype fp8_e4m3 \
                    --context-length 16384 \
                    --mem-fraction-static 0.85 \
                    --enable-metrics
              volumeMounts:
                - name: library-dir-host
                  mountPath: /usr/local/nvidia
                - name: gib
                  mountPath: /usr/local/gib
                - name: data-volume
                  mountPath: /data
            volumes:
              - name: library-dir-host
                hostPath:
                  path: /home/kubernetes/bin/nvidia
              - name: gib
                hostPath:
                  path: /home/kubernetes/bin/gib
              - name: data-volume
                emptyDir: {}
  2. ワークロード マニフェストをクラスタに適用します。

    kubectl apply -f llama3.1-405b-singlehost-a4.yaml
  3. 重みのダウンロードとサーバーの初期化をモニタリングするには、クラスタ内の Pod を一覧表示し、プリフィル Pod とデコード Pod のログをストリーミングします。

    kubectl get pods
    POD_NAME="YOUR_POD_NAME"
    kubectl logs -f "${POD_NAME}"

    YOUR_POD_NAME は、kubectl get pods 出力のプリフィル Pod またはデコード Pod の名前に置き換えます。

    最初の実行では、405B FP8 モデルの重みのダウンロードと SGLang サーバーの初期化に約 10 ~ 20 分かかります。リクエストを送信する前に、フロントエンド、プリフィル、デコードの Pod の kubectl get pods の READY 列に 1/1 が表示されるまで待ちます。

    NAME                                        READY   STATUS    RESTARTS   AGE
    llama3-405b-a4-disagg-0-decode-tgl7q        1/1     Running   0          15m
    llama3-405b-a4-disagg-0-frontend-wrxq5      1/1     Running   0          15m
    llama3-405b-a4-disagg-0-prefill-67h5s       1/1     Running   0          15m
    

推論リクエストを送信する

デプロイされた Llama 3.1 405B サービスにチャット完了リクエストを送信します。

  1. ローカルポート 8000 を llama3-405b-a4-disagg-frontend サービスに転送します。

    kubectl port-forward svc/llama3-405b-a4-disagg-frontend 8000:8000

    このターミナル セッションでポート転送を実行したままにするか、バックグラウンドでコマンドを実行します。

  2. 2 番目のターミナル セッションで、/v1/chat/completions エンドポイントにチャット完了リクエストを送信します。

    curl http://127.0.0.1:8000/v1/chat/completions \
      -H "Content-Type: application/json" \
      -d '{
        "model": "nvidia/Llama-3.1-405B-Instruct-FP8",
        "messages": [{"role": "user", "content": "Explain KV-cache disaggregation in one sentence."}],
        "max_tokens": 64
      }' | jq .

ベンチマーク ワークロードを実行する

sglang.bench_serving を使用して、Dynamo フロントエンド Pod からデプロイされた Llama 3.1 405B サーバーのベンチマークを行います。1,024 個の入力トークン、1,024 個の出力トークン(1k/1k)、2,048 個のプロンプト、最大同時実行数 512 でベンチマークを構成します。

ROUTER_POD=$(kubectl get pod -l 'nvidia.com/dynamo-component-type=frontend' -o jsonpath='{.items[0].metadata.name}')

kubectl exec "${ROUTER_POD}" -- python3 -m sglang.bench_serving \
  --backend sglang-oai-chat \
  --base-url http://localhost:8000 \
  --model nvidia/Llama-3.1-405B-Instruct-FP8 \
  --dataset-name random \
  --random-input-len 1024 \
  --random-output-len 1024 \
  --random-range-ratio 1.0 \
  --num-prompts 2048 \
  --max-concurrency 512 \
  --warmup-requests 10 | tee benchmark.log

ベンチマークが完了したら、次のような指標を含む出力を探します。

  • Output token throughput
  • Total token throughput
  • TTFT
  • TPOT

クリーンアップ

このチュートリアルで使用したリソースについて、 Google Cloud アカウントに継続的な追加料金が発生しないようにするには、Kubernetes ワークロード、GKE クラスタ、Cloud Storage バケットを削除します。

  1. DynamoGraphDeployment リソースと ResourceClaimTemplate リソースを削除します。

    kubectl delete -f llama3.1-405b-singlehost-a4.yaml --ignore-not-found || true
  2. NVIDIA Dynamo プラットフォームと KAI Scheduler Helm リリースをアンインストールします。

    helm uninstall dynamo-platform kai-scheduler || true
  3. Hugging Face Kubernetes Secret を削除します。

    kubectl delete secret hf-secret --ignore-not-found || true
  4. cluster-toolkit ディレクトリから、gcluster destroy コマンドを使用して、GKE クラスタとその関連インフラストラクチャを破棄します。

    cd cluster-toolkit
    ./gcluster destroy "${CLUSTER_NAME}" --auto-approve || true
    cd ..
  5. Terraform の状態を保存する Cloud Storage バケットを削除するには、gcloud storage rm コマンドを使用します。

    gcloud storage rm --recursive "gs://${GCS_BUCKET}"

次のステップ