KEDA を使用してゼロにスケーリングする


このチュートリアルでは、KEDA を使用して GKE ワークロードを Pod 0 にスケールダウンする方法について説明します。Deployment を 0 Pod にスケーリングすると、非アクティブな期間(週末や勤務時間外など)や、定期的なジョブなどの断続的なワークロードでリソースを節約できます。

目標

このチュートリアルでは、次のユースケースについて説明します。

料金

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

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

始める前に

このチュートリアルでは、Cloud Shell を使用してコマンドを実行します。Google Cloud Shell は、Google Cloud でホストされているリソースを管理するためのシェル環境です。これには、Google Cloud CLIkubectlHelmTerraform コマンドライン ツールがプリインストールされています。Cloud Shell を使用しない場合は、Google Cloud CLI と Helm をインストールする必要があります。

  1. このページにあるコマンドを実行するには、次のいずれかの開発環境で gcloud CLI を設定します。

    Cloud Shell

    gcloud CLI がすでに設定されているオンライン ターミナルを使用するには、Cloud Shell をアクティブにします。

    このページの下部で Cloud Shell セッションが開始し、コマンドライン プロンプトが表示されます。セッションが初期化されるまで数秒かかることがあります。

    ローカルシェル

    ローカル開発環境を使用する手順は次のとおりです。

    1. gcloud CLI をインストールする
    2. gcloud CLI を初期化する
    3. Kubernetes パッケージ管理ツールである Helm をインストールします。
  2. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  3. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  4. Make sure that billing is enabled for your Google Cloud project.

  5. Enable the Resource Manager, Compute Engine, GKE, Pub/Sub APIs.

    Enable the APIs

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

    Go to project selector

  7. Make sure that billing is enabled for your Google Cloud project.

  8. Enable the Resource Manager, Compute Engine, GKE, Pub/Sub APIs.

    Enable the APIs

環境設定

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

  1. 環境変数を設定します。

    export PROJECT_ID=PROJECT_ID
    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format 'get(projectNumber)')
    export LOCATION=LOCATION
    

    PROJECT_ID は Google Cloud のプロジェクト ID に、LOCATION は GKE クラスタを作成するリージョンまたはゾーンに置き換えます。

    チュートリアル全体を 1 つのセッションで完了しない場合や、なんらかの理由で環境変数が設定されていない場合は、このコマンドを再度実行して変数を再度設定してください。

  2. クラスタ自動スケーリングGKE 用 Workload Identity 連携を有効にして、Standard GKE クラスタを作成します。

    gcloud container clusters create scale-to-zero \
        --project=${PROJECT_ID} --location=${LOCATION} \
        --machine-type=n1-standard-2 \
        --enable-autoscaling --min-nodes=1 --max-nodes=5 \
        --workload-pool=${PROJECT_ID}.svc.id.goog
    

KEDA をインストールする

KEDA は、Kubernetes HorizontalPodAutoscaler を補完するコンポーネントです。KEDA を使用すると、Deployment をゼロ Pod にスケールダウンし、ゼロ Pod から 1 Pod にスケールアップできます。Deployment は、クラスタ内のノード間で Pod の複数のレプリカを実行できる Kubernetes API です。標準の HorizontalPodAutoscaler アルゴリズムは、GKE が 1 つ以上の Pod を作成した後に適用されます。

GKE が Deployment を 0 個の Pod にスケーリングすると、実行中の Pod がないため、自動スケーリングは CPU 使用率などの Pod 指標に依存できません。その結果、KEDA では、Kubernetes External Metrics API の実装を使用して、クラスタの外部から指標を取得できます。この API を使用すると、Pub/Sub サブスクリプションの未処理メッセージ数などの指標に基づいて自動スケーリングできます。サポートされているすべての指標ソースの一覧については、KEDA のドキュメントをご覧ください。

Helm または kubectl を使用して、クラスタに KEDA をインストールします。

Helm

次のコマンドを実行して KEDA Helm リポジトリを追加し、KEDA Helm チャートをインストールし、KEDA サービス アカウントに Cloud Monitoring への読み取りアクセス権を付与します。

helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda --create-namespace --namespace keda

gcloud projects add-iam-policy-binding projects/${PROJECT_ID} \
     --role roles/monitoring.viewer \
     --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/keda/sa/keda-operator

このコマンドは、クラスタに GKE 用 Workload Identity 連携を設定することを要求する認可ルールも設定します。

kubectl

次のコマンドを実行して kubectl apply を使用して KEDA をインストールし、KEDA サービス アカウントに Cloud Monitoring への読み取りアクセス権を付与します。

kubectl apply --server-side  -f https://github.com/kedacore/keda/releases/download/v2.15.1/keda-2.15.1.yaml

gcloud projects add-iam-policy-binding projects/${PROJECT_ID} \
     --role roles/monitoring.viewer \
     --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/keda/sa/keda-operator

このコマンドは、クラスタに GKE 用 Workload Identity 連携を設定することを要求する認可ルールも設定します。

すべての KEDA リソースが keda Namespace に表示されていることを確認します。

kubectl get all -n keda

KEDA の設計とリソースの詳細については、KEDA のドキュメントをご覧ください。

Pub/Sub ワークロードをゼロにスケーリングする

このセクションでは、Pub/Sub サブスクリプションからのメッセージを処理し、各メッセージを処理して完了を確認するワークロードについて説明します。ワークロードは動的にスケーリングされます。未確認メッセージの数が増えると、自動スケーリングにより Pod がインスタンス化され、タイムリーな処理が保証されます。

0 にスケーリングすると、しばらくメッセージが受信されなかったときに Pod がインスタンス化されなくなります。これにより、Pod が長時間アイドル状態にならないため、リソースを節約できます。

Pub/Sub ワークロードをデプロイする

Pub/Sub トピックにキューに入れられたメッセージを処理するサンプル ワークロードをデプロイします。実際のワークロードをシミュレートするため、このサンプル プログラムは、メッセージを確認する前に 3 秒間待機します。ワークロードは、keda-pubsub-sa サービス アカウントで実行するように構成されています。

次のコマンドを実行して Pub/Sub トピックとサブスクリプションを作成し、権限を構成して、keda-pubub Namespace でワークロードを開始する Deployment を作成します。

gcloud pubsub topics create keda-echo
gcloud pubsub subscriptions create keda-echo-read --topic=keda-echo
gcloud projects add-iam-policy-binding projects/${PROJECT_ID}  \
    --role=roles/pubsub.subscriber \
  --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/keda-pubsub/sa/keda-pubsub-sa

kubectl apply -f https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/tree/main/cost-optimization/gke-keda/cloud-pubsub/deployment/keda-pubsub-with-workload-identity.yaml

ゼロへのスケーリングを構成する

Pub/Sub ワークロードをゼロにスケーリングするように構成するには、KEDA を使用して ScaledObject リソースを定義し、デプロイメントのスケーリング方法を指定します。KEDA は、基盤となる HorizontalPodAutoscaler(HPA)オブジェクトを自動的に作成して管理します。

  1. 想定される自動スケーリングの動作を記述する ScaledObject リソースを作成します。

    envsubst < https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/tree/main/cost-optimization/gke-keda/cloud-pubsub/deployment/keda-pubsub-scaledobject.yaml | kubectl apply -f -
    

    これにより、次のオブジェクトが作成されます。

    apiVersion: keda.sh/v1alpha1
    kind: ScaledObject
    metadata:
      name: keda-pubsub
      namespace: keda-pubsub
    spec:
      maxReplicaCount: 5
      scaleTargetRef:
        name: keda-pubsub
      triggers:
        - type: gcp-pubsub
          authenticationRef:
            name: keda-auth
          metadata:
            subscriptionName: "projects/${PROJECT_ID}/subscriptions/keda-echo-read"
    
  2. ScaledObject オブジェクトに基づいて KEDA が作成する HorizontalPodAutoscaler(HPA)オブジェクトを調べます。

    kubectl get hpa keda-hpa-keda-pubsub -n keda-pubsub -o yaml
    

    自動スケーリングの詳細については、Kubernetes のドキュメントをご覧ください。

  3. KEDA が Pub/Sub サブスクリプションが空であることを認識し、Deployment をゼロ レプリカにスケーリングするまで待機します。

    ワークロード オートスケーラーを調べます。

    kubectl describe hpa keda-hpa-keda-pubsub -n keda-pubsub
    

    コマンド レスポンスで、ScalingActive 条件が false になっていることを確認します。関連するメッセージは、Horizontal Pod Autoscaler が KEDA が Deployment を 0 にスケーリングしたことを認識したことを示しています。この時点で、Deployment が 1 つの Pod にスケールバックされるまで、オペレーションは停止します。

    Name:                                                  keda-hpa-keda-pubsub
    Namespace:                                             keda-pubsub
    Metrics:                                               ( current / target )
      "s0-gcp-ps-projects-[...]]" (target average value):  0 / 10
    Min replicas:                                          1
    Max replicas:                                          5
    Deployment pods:                                       5 current / 5 desired
    Conditions:
      Type            Status  Reason               Message
      ----            ------  ------               -------
      AbleToScale     True    ScaleDownStabilized  recent recommendations were higher than current one [...]
      ScalingActive   False   ScalingDisabled      scaling is disabled since the replica count of the target is zero
      ScalingLimited  True    TooManyReplicas      the desired replica count is more than the maximum replica count
    

スケールアップをトリガーする

Deployment をスケールアップするには:

  1. Pub/Sub トピックにメッセージをキューに追加します。

    for num in {1..20}
    do
      gcloud pubsub topics publish keda-echo --project=${PROJECT_ID} --message="Test"
    done
    
  2. Deployment がスケールアップされていることを確認します。

    kubectl get deployments -n keda-pubsub
    

    出力で、[Ready] 列に 1 つのレプリカが表示されていることを確認します。

    NAME          READY   UP-TO-DATE   AVAILABLE   AGE
    keda-pubsub   1/1     1            1           2d
    

KEDA は、キューが空でないことを確認した後、Deployment をスケールアップします。

LLM ワークロードをゼロにスケーリングする

このセクションでは、GPU が接続された Ollama サーバーをデプロイする大規模言語モデル(LLM)ワークロードについて説明します。Ollama を使用すると、GemmaLamma 2 などの一般的な LLM を実行できます。また、主に HTTP を介して機能を公開します。

KEDA-HTTP アドオンをインストールする

非アクティブな期間中に HTTP サービスをゼロ Pod にスケールダウンすると、リクエストを処理するバックエンドがないため、リクエストが失敗します。

このセクションでは、KEDA-HTTP アドオンを使用してこの問題を解決する方法について説明します。KEDA-HTTP は、ユーザー リクエストを受信してゼロスケーリングするように構成された Service に転送する HTTP プロキシを起動します。Service に Pod がない場合、プロキシは Service のスケールアップをトリガーし、Service が少なくとも 1 つの Pod にスケールアップするまでリクエストをバッファリングします。

Helm を使用して KEDA-HTTP アドオンをインストールします。詳細については、KEDA-HTTP のドキュメントをご覧ください。

helm repo add ollama-helm https://otwld.github.io/ollama-helm/
helm repo update

# Set the proxy timeout to 120s, giving Ollama time to start.
helm install http-add-on kedacore/keda-add-ons-http  \
  --create-namespace --namespace keda \
  --set interceptor.responseHeaderTimeout=120s

Ollama LLM ワークロードをデプロイする

Ollama LLM ワークロードをデプロイするには:

  1. GPU が接続された g2-standard-4 ノードを含むノードプールを作成し、0 ~ 2 個のノードを提供するクラスタ自動スケーリングを構成します。

    gcloud container node-pools create gpu --machine-type=g2-standard-4 \
        --location=${LOCATION} --cluster=scale-to-zero \
        --min-nodes 0 --max-nodes 2 --num-nodes=1 --enable-autoscaling 
    
  2. 公式の Ollama Helm チャート リポジトリを追加し、ローカル Helm クライアントのリポジトリを更新します。

    helm repo add ollama-helm https://otwld.github.io/ollama-helm/
    helm repo update
    
  3. Helm チャートを使用して Ollama サーバーをデプロイします。

    helm install ollama ollama-helm/ollama --create-namespace --namespace ollama \
      -f https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/tree/main/cost-optimization/gke-keda/ollama/helm-values-ollama.yaml
    

    helm-values-ollama.yaml 構成では、読み込む LLM モデル、GPU 要件、Ollama サーバーの TCP ポートを指定します。

ゼロへのスケーリングを構成する

ゼロにスケーリングするように Ollama ワークロードを構成するには、KEDA-HTTP が HTTPScaledObject を使用します。

  1. 想定される自動スケーリングの動作を記述する HTTPScaledObject リソースを作成します。

    kubectl apply -f https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/tree/main/cost-optimization/gke-keda/ollama/keda-ollama-httpscaledobject.yaml
    

    これにより、次のフィールドを定義する HTTPScaledObject オブジェクトが作成されます。

    • scaleTargetRef: KEDA-HTTP がリクエストを転送する Service を指定します。この例では、ホスト ollama.ollama を持つすべてのリクエストが Ollama サーバーに転送されます。
    • scaledownPeriod: リクエストを受信していないときにスケールダウンする速度(秒単位)を指定します。
    • replicas: Ollama デプロイメントで維持する Pod の最小数と最大数を指定します。
    • scalingMetric: この例ではリクエスト レートなど、自動スケーリングの実行に使用される指標を指定します。その他の指標オプションについては、KEDA-HTTP のドキュメントをご覧ください。
    kind: HTTPScaledObject
    apiVersion: http.keda.sh/v1alpha1
    metadata:
        namespace: ollama
        name: ollama
    spec:
        hosts:
        - ollama.ollama
        scaleTargetRef:
            name: ollama
            kind: Deployment
            apiVersion: apps/v1
            service: ollama
            port: 11434
        replicas:
            min: 0
            max: 2
        scaledownPeriod: 3600
        scalingMetric:
            requestRate:
                targetValue: 20
    
  2. 次のコマンドを実行して、KEDA-HTTP が前の手順で作成した HTTPScaledObject を正常に処理したことを確認します。

    kubectl get hpa,scaledobject -n ollama
    

    出力には、HorizontalPodAutoscaler(KEDA によって作成)と ScaledObject(KEDA-HTTP によって作成)のリソースが表示されます。

    NAME                                                  REFERENCE           TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
    horizontalpodautoscaler.autoscaling/keda-hpa-ollama   Deployment/ollama   0/100 (avg)   1         2         1          2d
    
    NAME                          SCALETARGETKIND      SCALETARGETNAME   MIN   MAX   TRIGGERS        AUTHENTICATION   READY   ACTIVE   FALLBACK   PAUSED    AGE
    scaledobject.keda.sh/ollama   apps/v1.Deployment   ollama            0     2     external-push                    True    False    False      Unknown   2d
    
  3. Deployment が Pod を 0 にスケールダウンしていることを確認します。

    scaledownPeriod フィールドで設定した時間待ってから、次のコマンドを実行します。

    kubectl get deployments -n ollama
    

    出力には、KEDA が Ollama Deployment をスケールダウンし、Pod が実行されていないことが示されます。

    NAME     READY   UP-TO-DATE   AVAILABLE   AGE
    ollama   0/0     0            0           2d
    

スケールアップをトリガーする

Deployment のスケールアップを促すには、KEDA-HTTP アドオンによって設定されたプロキシを使用して Ollama サービスを呼び出します。これにより、リクエスト レート指標の値が増加し、最初の Pod の作成がトリガーされます。

プロキシは外部に公開されていないため、kubectl ポート転送機能を使用してプロキシにアクセスします。

kubectl port-forward svc/keda-add-ons-http-interceptor-proxy -n keda 8080:8080 &

# Set the 'Host' HTTP header so that the proxy routes requests to the Ollama server.
curl -H "Host: ollama.ollama" \
  http://localhost:8080/api/generate \
  -d '{ "model": "gemma:7b", "prompt": "Hello!" }'

curl コマンドは、プロンプト「Hello!」を Gemma モデルに送信します。レスポンスで返される回答トークンを観察します。API の仕様については、Ollama ガイドをご覧ください。

クリーンアップ

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

  1. Pub/Sub サブスクリプションとトピックをクリーンアップします。

    gcloud pubsub subscriptions delete keda-echo-read
    gcloud pubsub topics delete keda-echo
    
  2. GKE クラスタを削除します。

    gcloud container clusters delete scale-to-zero --location=${LOCATION}
    

次のステップ