HPA を使用して GKE ワークロードをゼロにスケーリングする

このチュートリアルでは、ワークロードがアイドル状態のときに自動的にゼロ レプリカにスケーリングし、需要の増加に応じてスケールアップするように構成して、Google Kubernetes Engine(GKE)でリソース使用率を最適化する方法について説明します。このアプローチでは、水平 Pod オートスケーラー(HPA)を GKE のマネージド自動スケーリング インフラストラクチャと統合して、外部指標に基づいてスケーリングを管理します。

minReplicas フィールドの値を 0 に設定し、HPA マニフェスト内で External タイプまたは Object タイプの指標を定義して、ゼロにスケーリングするようにデプロイを構成します。GKE は、AutoscalingMetric カスタム リソースを介してこれらの指標をモニタリングします。これにより、アプリケーションのリソース管理を効率的に行うことができます。

この構成では、KEDA などのサードパーティの指標アダプタを使用して GKE ワークロードをスケーリングする必要はありません。このソリューションは、指標の取り込みとスケーリングの推奨事項を GKE コントロール プレーンで直接管理し、クラスタ管理のオーバーヘッドを削減します。

このチュートリアルでは、Pub/Sub キューからメッセージを処理する非同期ワーカー アプリケーションの例をデプロイします。AutoscalingMetric カスタム リソースを使用して、キューの深さ(pubsub.googleapis.com:num_undelivered_messages)をモニタリングするように水平 Pod オートスケーラーを構成します。

  • サブスクリプションにメッセージが到着した場合: GKE は、キューを処理するためにワーカー Pod をスケールアップします。
  • キューが空の場合: GKE は、ワーカーの Deployment を自動的にゼロ レプリカにスケールダウンします。

このチュートリアルは、ワークロードがアイドル状態のときにゼロにスケーリングして GKE のリソース使用率を最適化するアプリケーション デベロッパー、プラットフォーム管理者とオペレーター、DevOps を対象としています。

考慮事項

ワークロードをゼロにスケーリングするように構成する前に、次の考慮事項を確認してください。

  • HPA を使用してワークロードをゼロにスケーリングするには、新規クラスタとアップグレードされた既存のクラスタの両方で、GKE クラスタのコントロール プレーンとノードがバージョン 1.37 以降を実行している必要があります。既存のクラスタを使用する場合は、そのバージョンを確認するか、クラスタまたはそのノードをバージョン 1.37 以降にアップグレードします。
  • HPA マニフェストは、minReplicas: 0 設定と外部指標をサポートするために apiVersion: autoscaling/v2 構成を使用する必要があります。
  • ノードプールをダウングレードして 1.37 より前のバージョンにする前に、ゼロとの間でスケーリングするように構成された HPA マニフェストを更新し、minReplicas フィールドを 1 以上に設定します。1.37 より前のバージョンでは minReplicas: 0 設定がサポートされていないため、ワークロードがゼロ レプリカのままになることがあります。
  • 水平 Pod 自動スケーラーで、External 指標または Object 指標(キューの深さなど)を 1 つ以上構成する必要があります。ワークロードに Pod がない場合、GKE は CPU またはメモリ(Resource)指標を収集できません。そのため、リソース指標だけではゼロからのスケールアップをトリガーできません。
  • AutoscalingMetric、HorizontalPodAutoscaler、ターゲット Deployment は同じ Kubernetes Namespace に存在する必要があります。

始める前に

  1. Google Cloud CLI をインストールします。

  2. フェデレーション ID(連携 ID)を使用するように gcloud CLI を構成します。

    詳細については、連携 ID を使用して gcloud CLI にログインするをご覧ください。

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

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

    プロジェクトの選択または作成に必要なロール

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

      gcloud projects create PROJECT_ID

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

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

      gcloud config set project PROJECT_ID

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

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

  6. GKE API と Pub/Sub API を有効にします。

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

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

    gcloud services enable container.googleapis.com pubsub.googleapis.com

必要なロール

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

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

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

環境の設定

わかりやすくするため、このチュートリアルのコマンドでは、すべてのリソース(GKE クラスタ、Pub/Sub トピック、サブスクリプション)を 1 つの Google Cloud プロジェクト(PROJECT_ID)内に作成します。

環境の設定手順は次のとおりです。

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

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

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

  2. Workload Identity Federation for GKE を有効にして、バージョン 1.37 以降を実行する GKE クラスタを作成します。フルマネージドの Kubernetes エクスペリエンスを実現し、ワークロードがゼロにスケーリングされたときにコスト削減を最大化するには、Autopilot クラスタを使用することをおすすめします。ワークロードに最適な運用モードを選択するには、GKE の運用モードを選択するをご覧ください。

    Autopilot

    Autopilot クラスタを作成します。

    gcloud container clusters create-auto scale-to-zero \
        --project=${PROJECT_ID} \
        --location=${LOCATION}
    

    Workload Identity Federation for GKE は、Autopilot クラスタではデフォルトで有効になっています。

    標準

    Workload Identity Federation for GKE を有効にして Standard クラスタを作成します。

    gcloud container clusters create scale-to-zero \
        --project=${PROJECT_ID} \
        --location=${LOCATION} \
        --workload-pool=${PROJECT_ID}.
    
  3. クラスタと通信を行うように kubectl を構成します。

    gcloud container clusters get-credentials scale-to-zero \
        --project=${PROJECT_ID} \
        --location=${LOCATION}
    

Pub/Sub リソースを作成する

このチュートリアルでは、外部指標ソースの例として Pub/Sub キューの深さを使用します。

Pub/Sub トピックとサブスクリプションを作成する手順は次のとおりです。

  1. Pub/Sub トピックを作成します。

    gcloud pubsub topics create my-worker-topic \
        --project=${PROJECT_ID}
    
  2. トピックに関連付けられたサブスクリプションを作成します。

    gcloud pubsub subscriptions create my-worker-subscription \
        --topic=my-worker-topic \
        --project=${PROJECT_ID}
    

Workload Identity Federation for GKE を設定する

ワーカー アプリケーションが Google Cloud API で認証を行い、Pub/Sub からメッセージを消費できるように、Workload Identity Federation for GKE を構成します。

GKE は、同じプロジェクト内の AutoscalingMetric リソースの Cloud Monitoring による認証を自動的に処理します。自動スケーリングの指標の定義の詳細については、Cloud Monitoring からカスタム指標または外部指標を取得するをご覧ください。

ワーカー ワークロード用に Workload Identity Federation for GKE を構成する手順は次のとおりです。

  1. default Namespace にワーカー アプリケーション用の Kubernetes サービス アカウントを作成します。

    kubectl create serviceaccount async-worker-sa \
        --namespace default
    
  2. アプリケーションが Pub/Sub サブスクリプションからメッセージを受信できるように、Kubernetes サービス アカウントに roles/pubsub.subscriber ロールを付与します。

    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}./subject/ns/default/sa/async-worker-sa
    

詳細については、Workload Identity Federation for GKE を使用するようにアプリケーションを構成するをご覧ください。

サンプル Deployment の作成

HPA オブジェクトを作成する前に、モニタリング対象のワークロードを作成する必要があります。

Deployment のサンプルを作成する手順は次のとおりです。

  1. 次のマニフェストを async-worker.yaml として保存します。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: async-worker
      namespace: default
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: async-worker
      template:
        metadata:
          labels:
            app: async-worker
        spec:
          containers:
          - name: async-worker
            image: nginx:latest
            ports:
            - containerPort: 80
            resources:
              limits:
                memory: 100Mi
              requests:
                cpu: 50m
                memory: 100Mi
    
  2. async-worker.yaml Deployment を適用します。

    kubectl apply -f async-worker.yaml
    

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

このセクションでは、Pub/Sub キューが空になったときにゼロにスケールダウンし、新しいメッセージが到着したときにスケールアップするように async-worker Deployment を構成します。

AutoscalingMetric リソースを作成する

GKE でモニタリングする外部シグナルを定義するには、AutoscalingMetric カスタム リソースを作成します。次のマニフェストの例では、指標は my-worker-subscription サブスクリプションの未配信の Pub/Sub メッセージの数を Cloud Monitoring にクエリします。

AutoscalingMetric リソースを作成する手順は次のとおりです。

  1. 次のマニフェストを pubsub-metric.yaml ファイルとして保存します。

    apiVersion: autoscaling.gke.io/v1beta1
    kind: AutoscalingMetric
    metadata:
      name: pubsub-queue-depth
      namespace: default
    spec:
      metrics:
      - promql:
          name: pubsub-undelivered
          query: >
              {
                "pubsub.googleapis.com/subscription/num_undelivered_messages",
                subscription_id="my-worker-subscription"
              }
    
  2. pubsub-metric.yaml マニフェストを適用します。

    kubectl apply -f pubsub-metric.yaml
    
  3. 指標のステータスを確認し、指標識別子を取得します。

    kubectl describe autoscalingmetric pubsub-queue-depth
    

    出力の Status セクションで、エラーがリストされていないことを確認し、autoscaling.gke.io|CUSTOM_RESOURCE_NAME|METRIC_NAME 形式の Hpa Name 値をメモします。この外部指標識別子は、次のセクションで HorizontalPodAutoscaler オブジェクトを作成するときに参照します。Status セクションで構成エラーが報告された場合や、指標が想定どおりに取得されない場合は、自動スケーリング用に取得された指標のトラブルシューティングをご覧ください。

水平 Pod オートスケーラーを構成する

自動スケーリングの動作を構成するには、Deployment をターゲットとする HorizontalPodAutoscaler リソースを作成します。

水平 Pod オートスケーラーを構成する手順は次のとおりです。

  1. 次のマニフェストを worker-hpa.yaml ファイルとして保存します。

    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: async-worker-hpa
      namespace: default
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: async-worker
      minReplicas: 0
      maxReplicas: 20
      metrics:
      - type: External
        external:
          metric:
            name: autoscaling.gke.io|pubsub-queue-depth|pubsub-undelivered
          target:
            type: AverageValue
            averageValue: "10"
    

    このマニフェストでは、次のキーフィールドを構成します。

    • minReplicas: 0: コントローラが Deployment を 0 レプリカにスケールダウンできるようにすることで、需要がゼロになったときにゼロへのスケーリングを有効にします。
    • type: External: 外部指標ソースを構成します。これにより、ワークロードに Pod がない場合に HPA がスケールアップをトリガーできます。
    • name: autoscaling.gke.io|pubsub-queue-depth|pubsub-undelivered: autoscaling.gke.io|CUSTOM_RESOURCE_NAME|METRIC_NAME 識別子形式を使用して、HPA を前のステップで作成した AutoscalingMetric リソースに直接マッピングします。
  2. worker-hpa.yaml マニフェストを適用します。

    kubectl apply -f worker-hpa.yaml
    

ゼロスケールの動作と条件を確認する

Pub/Sub サブスクリプション内のすべてのメッセージが処理されると、水平 Pod オートスケーラーは需要がゼロであることを評価し、Deployment を 0 レプリカにスケールダウンします。

水平 Pod オートスケーラーがゼロ状態をアクチュエートしたことを確認するには、次のコマンドを実行して async-worker-hpa リソースのステータス条件を調べます。

kubectl describe hpa async-worker-hpa

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

Name:             async-worker-hpa
Namespace:        default
Reference:        Deployment/async-worker
Metrics:          ( current / target )
  "autoscaling.gke.io|pubsub-queue-depth|pubsub-undelivered" (external metric):  0 / 10
Min replicas:     0
Max replicas:     20
Deployment pods:  0 current / 0 desired
Conditions:
  Type            Status  Reason               Message
  ----            ------  ------               -------
  AbleToScale     True    SucceededGetScale    the HPA controller was able to get the target's current scale
  ScalingActive   True    ValidMetricFound     the HPA was able to successfully calculate a replica count from external metric
  ScaledToZero    True    ScaledToZero         the HPA has scaled the target resource to 0 replicas due to zero metric demand

ScaledToZero 条件について

ScaledToZero 条件は、水平方向 Pod オートスケーラーがワークロードをゼロ レプリカにスケーリングしたかどうかを示します。

  • ScaledToZero: TrueReason: ScaledToZero: 外部指標の需要がゼロになったため、HPA コントローラがワークロードを 0 レプリカに正常にスケーリングしたことを示します。HPA はアクティブな状態(ScalingActive: True)を維持し、GKE を継続的にポーリングして、ワークロードの需要が増加したタイミングを検出します。
  • ScaledToZero: False: ワークロードが 1 つ以上のレプリカにスケールアップされたことを示します。

たとえば、kubectl scale --replicas=0 コマンドを使用して Deployment をゼロ レプリカに手動でスケーリングすると、HPA は競合する変更を防ぐために自動スケーリング(ScalingActive: False)を一時停止します。自動スケーリングを再開するには、デプロイを 1 つ以上のレプリカ(kubectl scale deployment async-worker --replicas=1)にスケールバックします。

ワークロードがゼロにスケールダウンできない場合や、ゼロからスケールアップできない場合のトラブルシューティング シナリオについては、HPA を使用して GKE ワークロードをゼロにスケールダウンするトラブルシューティングをご覧ください。HorizontalPodAutoscaler が外部指標の欠落または無効を報告する場合は、自動スケーリング用に取得された指標のトラブルシューティングをご覧ください。

クリーンアップ

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

  1. GKE クラスタを削除します。

    gcloud container clusters delete scale-to-zero \
        --project=${PROJECT_ID} \
        --location=${LOCATION}
    
  2. Pub/Sub サブスクリプションとトピックを削除します。

    gcloud pubsub subscriptions delete my-worker-subscription \
        --project=${PROJECT_ID}
    gcloud pubsub topics delete my-worker-topic \
        --project=${PROJECT_ID}
    

次のステップ