GPU 指標を使用して vLLM モデル提供を自動スケーリングする

このチュートリアルでは、vLLM で LLM を提供する Cloud Run サービスを、Cloud Run External Metrics Autoscaling(CREMA) を使用してカスタム GPU 指標に基づいて自動スケーリングする方法について説明します。

Cloud Run はデフォルトで CPU 使用率と同時実行を使用して自動スケーリングしますが、GPU を多用する推論ワークロードでは、実行中のリクエスト数や KV キャッシュ使用率などのキュー指標に基づいて自動スケーリングが必要になることがよくあります。CREMA は、Kubernetes ベースの Event Driven Autoscaling(KEDA)を Cloud Run と統合し、Prometheus 指標に基づく動的なスケーリングを可能にします。vLLM は Prometheus 指標を公開し、Cloud Monitoring に送信します。

目標

このチュートリアルの内容は次のとおりです。

費用

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

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

新規の Google Cloud ユーザーの方は、無料トライアルをご利用いただける場合があります。

始める前に

  1. アカウントに Google Cloud ログインします。 を初めて使用する場合は、 Google Cloud、 アカウントを作成して、 実際のシナリオでプロダクトがどのように機能するかを評価してください。新規のお客様には、ワークロードの実行、テスト、デプロイに利用できる $300 分の無料クレジットも提供されます。
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  5. Verify that billing is enabled for your Google Cloud project.

  6. Cloud Run、Parameter Manager、Artifact Registry、Cloud Build、Secret Manager、Cloud Monitoring API を有効にします。

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

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

    API を有効にする

  7. gcloud CLI をインストールして初期化します
  8. このチュートリアル全体で使用する環境変数を設定します。
    export PROJECT_ID=PROJECT_ID
    export REGION=us-central1
    export VLLM_SERVICE_NAME=vllm-service
    export MODEL_NAME=gemma-2-2b-it
    export REPO_NAME=vllm-repo
    export BUCKET_NAME=my-vllm-models-${PROJECT_ID}
    export CREMA_SERVICE_NAME=crema-service
    PROJECT_ID は、 実際の Google Cloud プロジェクト ID に置き換えます。
  9. プロジェクト構成を設定します。
    gcloud config set project $PROJECT_ID
  10. Hugging Face のアカウントをお持ちでない場合は、アカウントを作成します。次に、読み取り トークンを Hugging Face サイトで作成します。 Hugging Face では、トークンは 1 回だけ表示されます。安全な場所に保存してください。再度表示することはできません。
  11. Hugging Face の gemma-2-2b-it モデルページに移動し、モデルの利用規約に同意します。

必要なロール

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

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

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

モデルの重みをダウンロードして Cloud Storage にアップロードする

Hugging Face からモデルの重みをダウンロードし、Cloud Storage バケットに転送して、モデル提供に使用できるようにします。

  1. Hugging Face CLI をインストールします。

    pip install -U "huggingface_hub[cli]"
    
  2. Hugging Face CLI を使用して、モデルの重みをローカルにダウンロードします。

    export HF_TOKEN="HF_TOKEN"
    export LOCAL_DIR="/tmp/$MODEL_NAME"
    HF_HOME=/tmp/huggingface python -m huggingface_hub.cli.hf download google/$MODEL_NAME --token $HF_TOKEN --local-dir=$LOCAL_DIR
    

    HF_TOKEN は、Hugging Face ユーザー アクセス トークンに置き換えます。トークンは hf_ で始まり、その後に 35 個のランダムな英数字が続きます(例: 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)。

  3. Cloud Storage バケットを作成し、ダウンロードした重みをコピーします。

    gcloud storage buckets create gs://$BUCKET_NAME \
        --project=$PROJECT_ID \
        --location=$REGION \
        --uniform-bucket-level-access
    
    gcloud storage cp -r $LOCAL_DIR gs://$BUCKET_NAME/
    

vLLM コンテナ イメージを Artifact Registry に push する

モデル提供コンテナ イメージを pull して、Artifact Registry のリポジトリに push します。

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

    gcloud artifacts repositories create $REPO_NAME \
        --repository-format=docker \
        --location=$REGION \
        --description="vLLM Docker Images"
    
  2. ローカル Docker デーモンをレジストリで認証します。

    gcloud auth configure-docker ${REGION}-docker.pkg.dev
    
  3. vLLM イメージを pull し、タグを付けて Artifact Registry に push します。

    docker pull docker.io/vllm/vllm-openai:latest
    docker tag docker.io/vllm/vllm-openai:latest ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/vllm-openai:latest
    docker push ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/vllm-openai:latest
    

CREMA オートスケーラー サービスをデプロイする

オートスケーラー サービスをデプロイする前に、CREMA のサービス アカウント ロールとパラメータ マニフェストを構成します。

カスタム サービス アカウントを作成する

プロビジョニングされたリソースを使用するために必要な最小権限を持つカスタム サービス アカウントを作成します。 このサービス アカウントは、オートスケーラーの ID として機能します。次のコマンドを実行して、CREMA サービス アカウントを作成します。

export CREMA_SA="crema-autoscaler@${PROJECT_ID}.iam.gserviceaccount.com"

gcloud iam service-accounts create crema-autoscaler \
    --description="Service account for Cloud Run CREMA to read metrics and scale workloads" \
    --display-name="CREMA Autoscaler System"

カスタム サービス アカウントに追加の権限を付与する

サービスをスケーリングするには、カスタム サービス アカウントに次の権限を付与します。

  1. Parameter Manager から読み取る権限を CREMA サービス アカウントに付与します。

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/parametermanager.parameterViewer"
    
  2. サービスをスケーリングする権限を CREMA サービス アカウントに付与します。

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/run.developer"
    
  3. サービス アカウント ユーザーロールを CREMA サービス アカウントに付与します。

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/iam.serviceAccountUser"
    
  4. 指標を表示する権限を CREMA サービス アカウントに付与します。

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/monitoring.viewer"
    

CREMA 構成を作成して登録する

CREMA 構成マニフェストでスケーリングのしきい値とルールを定義し、Parameter Manager に登録します。

  1. 次の構成を my-crema-config.yaml として保存します。この構成では、実行中のリクエスト数(vllm:num_requests_running)が 2 を超えるとスケーリングがトリガーされます。

    apiVersion: crema/v1
    kind: CremaConfig
    spec:
      pollingInterval: 15
      triggerAuthentications:
        - metadata:
            name: adc-trigger-auth
          spec:
            podIdentity:
              provider: gcp
      scaledObjects:
        - spec:
            scaleTargetRef:
              name: projects/PROJECT_ID/locations/us-central1/services/vllm-service
            minReplicaCount: 1
            maxReplicaCount: 5
            triggers:
              - type: prometheus
                authenticationRef:
                  name: adc-trigger-auth
                metadata:
                  serverAddress: https://monitoring.googleapis.com/v1/projects/PROJECT_ID/location/global/prometheus
                  metric: vllm:num_requests_running
                  query: sum(vllm:num_requests_running)
                  threshold: '2'
    
  2. 構成ファイルを Parameter Manager に登録します。

    gcloud parametermanager parameters create crema-config \
        --location=global \
        --parameter-format=YAML
    
    gcloud parametermanager parameters versions create 1 \
        --location=global \
        --parameter=crema-config \
        --payload-data-from-file=my-crema-config.yaml
    

CREMA サービスをデプロイする

CREMA イメージを Cloud Run の内部バックグラウンド サービスとしてデプロイします。

gcloud run deploy $CREMA_SERVICE_NAME \
    --image=us-central1-docker.pkg.dev/cloud-run-oss-images/crema-v1/autoscaler:1.0 \
    --region=$REGION \
    --service-account="$CREMA_SA" \
    --no-allow-unauthenticated \
    --no-cpu-throttling \
    --cpu=1 \
    --memory=1Gi \
    --min-instances=1 \
    --max-instances=1 \
    --ingress=internal \
    --base-image=us-central1-docker.pkg.dev/serverless-runtimes/google-24/runtimes/java25 \
    --set-env-vars="CREMA_CONFIG=projects/$PROJECT_ID/locations/global/parameters/crema-config/versions/1,OUTPUT_SCALER_METRICS=True"

vLLM サービスの権限を構成する

デフォルトの Compute Engine サービス アカウントに、指標をエクスポートして Cloud Storage からモデルの重みを読み取る権限を付与します。

  1. プロジェクト番号を取得します。

    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
    
  2. 指標を書き込む権限をサービス アカウントに付与します。

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
        --role="roles/monitoring.metricWriter"
    
  3. Cloud Storage からモデルの重みを読み取る権限をサービス アカウントに付与します。

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
        --role="roles/storage.objectViewer"
    

OpenTelemetry サイドカーを使用して vLLM サービスをデプロイする

Cloud Storage からマウントされたモデルの重みを使用して、プライマリ vLLM 提供コンテナを Cloud Run にデプロイします。Cloud Run でサイドカーを使用してマルチコンテナ サービスをデプロイするには、宣言型 YAML サービス仕様が必要なため、OpenTelemetry サイドカー コレクタとともにプライマリ vLLM エンジンを構成して、vLLM 指標をスクレイピングしてエクスポートします。

  1. 次のマルチコンテナ デプロイ仕様を vllm-service.yaml として保存します。

    apiVersion: serving.knative.dev/v1
    kind: Service
    metadata:
      name: vllm-service
      labels:
        cloud.googleapis.com/location: us-central1
      annotations:
        run.googleapis.com/scalingMode: manual
        run.googleapis.com/manualInstanceCount: "1"
    spec:
      template:
        metadata:
          annotations:
            run.googleapis.com/execution-environment: gen2
            run.googleapis.com/cpu-throttling: "false"
            run.googleapis.com/gpu-zonal-redundancy-disabled: "true"
            autoscaling.knative.dev/minScale: "1"
        spec:
          containerConcurrency: 80
          nodeSelector:
            run.googleapis.com/accelerator: nvidia-l4
          volumes:
            - name: gcs-volume
              csi:
                driver: gcsfuse.run.googleapis.com
                volumeAttributes:
                  bucketName: my-vllm-models-PROJECT_ID
          containers:
            # Primary container: vLLM serving engine
            - name: vllm-container
              image: us-central1-docker.pkg.dev/PROJECT_ID/vllm-repo/vllm-openai:latest
              ports:
                - containerPort: 8080
              resources:
                limits:
                  cpu: "4"
                  memory: 16Gi
                  nvidia.com/gpu: "1"
              args:
                - "--model"
                - "/gcs/gemma-2-2b-it"
                - "--port"
                - "8080"
                - "--max-model-len"
                - "2048"
                - "--chat-template"
                - "{% for msg in messages %}{{ msg['content'] }}{% endfor %}"
              volumeMounts:
                - name: gcs-volume
                  mountPath: /gcs
              startupProbe:
                httpGet:
                  path: /health
                  port: 8080
                periodSeconds: 10
                failureThreshold: 24
    
            # Sidecar container: OpenTelemetry Collector
            - name: otel-collector
              image: otel/opentelemetry-collector-contrib:latest
              resources:
                limits:
                  cpu: "1"
                  memory: 1Gi
              args:
                - |
                  --config=yaml:
                  receivers:
                    prometheus:
                      config:
                        scrape_configs:
                          - job_name: 'vllm'
                            scrape_interval: 10s
                            metrics_path: '/metrics'
                            static_configs:
                              - targets: ['localhost:8080']
                  processors:
                    resourcedetection:
                      detectors: [gcp]
                      timeout: 2s
                    transform:
                      metric_statements:
                        - context: datapoint
                          statements:
                            - set(attributes["exported_location"], attributes["location"])
                            - delete_key(attributes, "location")
                            - set(attributes["exported_cluster"], attributes["cluster"])
                            - delete_key(attributes, "cluster")
                            - set(attributes["exported_namespace"], attributes["namespace"])
                            - delete_key(attributes, "namespace")
                            - set(attributes["exported_job"], attributes["job"])
                            - delete_key(attributes, "job")
                            - set(attributes["exported_instance"], attributes["instance"])
                            - delete_key(attributes, "instance")
                  exporters:
                    googlemanagedprometheus:
                  service:
                    pipelines:
                      metrics:
                        receivers: [prometheus]
                        processors: [resourcedetection, transform]
                        exporters: [googlemanagedprometheus]
    
  2. 既存のサービス構成をマルチコンテナ マニフェストに置き換えます。

    gcloud run services replace vllm-service.yaml
    

CREMA サービスログを確認する

  1. コンソール Google Cloud で、[Cloud Run] ページに移動します。
  2. crema-service を選択します。
  3. [ログ] タブをクリックし、指標ポーリング サイクルがアクティブであることを確認します。

    [INFO] [METRIC-PROVIDER] Starting metric collection cycle
    [INFO] [METRIC-PROVIDER] Successfully fetched scaled object metrics ...
    [INFO] [METRIC-PROVIDER] Sending scale request ...
    [INFO] [SCALER] Received ScaleRequest ...
    [INFO] [SCALER] Current instances ...
    [INFO] [SCALER] Recommended instances ...
    

負荷テストを実行する

自動スケーリングをテストするには、負荷テスト スクリプトを実行して、vLLM サービスに同時リクエストを送信します。

  1. 作業ディレクトリに load-test.sh という名前のファイルを作成し、次のコードを追加します。

    #!/bin/bash
    
    export SERVICE_URL=$(gcloud run services describe $VLLM_SERVICE_NAME --region $REGION --format='value(status.url)')
    
    echo "Launching 5 parallel heavy requests to trigger autoscaling..."
    
    for i in {1..5}; do
        curl -s -X POST "${SERVICE_URL}/v1/chat/completions" \
            -H "Authorization: Bearer $(gcloud auth print-identity-token)" \
            -H "Content-Type: application/json" \
            -d "{
                \"model\": \"/gcs/${MODEL_NAME}\",
                \"messages\": [{\"role\": \"user\", \"content\": \"Write an exceptionally long, detailed, and exhaustive essay about the entire history of the universe from the Big Bang to the modern day.\"}]
            }" > /dev/null &
    done
    
    echo "All 5 requests dispatched. Waiting for requests to complete..."
    wait
    echo "Done."
    
  2. スクリプトを実行可能にして、負荷テストを実行します。

    chmod +x load-test.sh
    ./load-test.sh
    
  3. crema-service ログと Cloud Run 指標ダッシュボードを再度確認し、キューに登録されたリクエストに応じて推奨インスタンス数がスケールアップしていることを確認します。

Cloud Monitoring で vLLM 指標を確認する

負荷テストを実行したら、トラフィックが Cloud Monitoring のモデル提供指標にどのように影響するかを確認します。

  1. コンソール Google Cloud で、Cloud Monitoring の [**Metrics Explorer**] ページに移動します。

    Metrics Explorer に移動

  2. [指標を選択] をクリックします。

  3. [Prometheus Target] > [Vllm] を展開し、/gauge で終わる使用可能な指標を選択します。たとえば、prometheus/vllm:num_requests_running/gauge を選択すると、負荷テスト中のアクティブなリクエスト数が表示されます。

vLLM の本番環境指標のドキュメントで説明されているように、Cloud Monitoring にエクスポートされる追加の vLLM 指標は次のとおりです。

  • prometheus/vllm:num_requests_waiting/gauge: vLLM エンジンで処理されるのを待機しているリクエストの数。
  • prometheus/vllm:num_requests_running/gauge: モデル バッチで実行されているリクエストの数。
  • prometheus/vllm:gpu_cache_usage_perc/gauge: 使用されている GPU KV キャッシュ メモリの割合。
  • prometheus/vllm:num_requests_swapped/gauge: メモリ不足のため、KV キャッシュがホスト CPU メモリにスワップされたリクエストの数。

このチュートリアルでは vllm:num_requests_running に基づいてスケーリングしますが、CREMA 構成でこれらの vLLM 指標のいずれかを使用して、キューサイズ、KV キャッシュ使用率、リクエスト スワップに基づいてワークロードの自動スケーリング ルールをカスタマイズできます。

すべてのリクエストを均等に扱う標準の HTTP リクエスト同時実行指標とは異なり、vLLM の内部指標は、プロンプトの長さが異なる場合の動的な GPU メモリ使用量を考慮します。vllm:num_requests_running でスケーリングすると、実際の GPU 負荷に基づいてプロアクティブにスケーリングできます。これにより、サーバーがリクエストを vllm:num_requests_waiting にキューに入れる前にアクティブな容量バッファが維持され、ユーザーが Time To First Token(TTFT)のレイテンシが大幅に増加するのを防ぐことができます。

クリーンアップ

Google Cloud アカウントで追加料金が発生しないようにするには、このチュートリアルでデプロイしたすべてのリソースを削除します。

プロジェクトを削除する

このチュートリアル用に新規プロジェクトを作成した場合は、そのプロジェクトを削除します。既存のプロジェクトを使用し、このチュートリアルで行った変更を加えずに残す場合は、チュートリアル用に作成したリソースを削除します。

課金されないようにする最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。

プロジェクトを削除するには:

  1. コンソール Google Cloud で [**リソースの管理**] ページに移動します。

    [リソースの管理] に移動

  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、 [Shut down] をクリックしてプロジェクトを削除します。

チュートリアル リソースの削除

  1. このチュートリアルでデプロイした Cloud Run サービスを削除します。Cloud Run サービスの費用は、リクエストを受け取るまでは発生しません。

    Cloud Run サービスを削除するには、次のコマンドを実行します。

    gcloud run services delete SERVICE-NAME

    SERVICE-NAME は、サービスの名前に置き換えます。

    Cloud Run サービスは Google Cloud コンソールで削除することもできます。

  2. チュートリアルの設定時に追加した gcloud のデフォルトのリージョン構成を削除します。

     gcloud config unset run/region
    
  3. プロジェクト構成を削除します。

     gcloud config unset project
    
  4. Parameter Manager に割り当てられた CREMA 構成を削除します。

    gcloud parametermanager parameters delete crema-config \
        --location=global \
        --quiet
    
  5. CREMA 用に作成したカスタム サービス アカウントを削除します。

    gcloud iam service-accounts delete $CREMA_SA \
        --quiet
    
  6. モデルを含む Cloud Storage バケットを削除します。

    gcloud storage rm --recursive gs://$BUCKET_NAME
    
  7. このチュートリアルで作成した他の Google Cloud リソースを削除します。

次のステップ