[アップデート] GKEのカスタムメトリクスを使ったHPAでのスケーリングが外部コンポーネントなしでできるようになったので試してみた

[アップデート] GKEのカスタムメトリクスを使ったHPAでのスケーリングが外部コンポーネントなしでできるようになったので試してみた

2026.05.02

はじめに

皆様こんにちは、あかいけです。

「CPU/メモリ以外のメトリクスでHPAを使ってPodをスケールさせたい」と思ったことはありますか?私はあります。
もちろんPrometheusやKEDAを使えば実現できますが、そのためのコンポーネントを別途構築・運用する必要があり、めんどくさいなぁ…と感じていました。

そして先日開催されたGoogle Cloud Next 2026でGKEに関する様々なアップデートが発表され、
その中に「Intent-based autoscaling on custom metrics(カスタムメトリクスに基づくインテントベースのオートスケーリング)」というものがありました。

https://cloud.google.com/blog/products/containers-kubernetes/whats-new-in-gke-at-next26?hl=en

どうやら、カスタムメトリクスを使ったHPAがGKEネイティブでできるようになった機能みたいです。
外部コンポーネントなしでサクッと試せるらしいので、早速使ってみました。

なお本ブログで利用しているファイルは以下リポジトリにおいているので、ご自由にご利用ください。

https://github.com/Lamaglama39/gke-custom-metrics-demo

カスタムメトリクスでのオートスケーリングについて

従来の方法と課題

まずGKEにおいて、カスタムメトリクスを使ったHPAでのスケーリングは以前から実現可能でした。

https://docs.cloud.google.com/stackdriver/docs/managed-prometheus/hpa?hl=ja

主な方法としては以下のようなものがあります。

  • Prometheus + Prometheus Adapter
  • KEDA(Kubernetes Event-driven Autoscaling)
  • custom-metrics-stackdriver-adapter

これらの方法は、
動かすためにコンポーネントを別途クラスターにデプロイして自前で運用しなければならないのが課題でした。

新機能の概要

今回のアップデートで追加された機能は、
GKEがカスタムメトリクスの収集をネイティブにサポートしてくれるようになったという点がメリットかなと思います。

https://cloud.google.com/blog/products/containers-kubernetes/gke-now-supports-custom-metrics-natively?hl=en

AutoscalingMetricというCRDをデプロイするだけで、直接PodのPrometheusエンドポイントからメトリクスをスクレイピングしてHPAに連携してくれます。
PrometheusもAdapterも不要で、GKEクラスターに追加コンポーネントを入れずに使えます。

なお現時点ではゲージメトリクスのみ対応・クラスタあたり最大20メトリクスといった制約もあるため、
対象とするメトリクス数が多い場合や複雑な要件には、引き続きPrometheusやKEDAの方が適しているケースもあると思います。

前提条件と制限

  • GKEバージョン
    • GKE 1.35.1-gke.1396000以上(Rapidチャンネル推奨)
  • メトリクス形式
    • HTTP エンドポイントでアクセス可能
    • Prometheus形式のゲージメトリクスのみ対応
  • メトリクス数の上限
    • クラスタあたり最大20ユニークメトリクス
  • メトリクス名の制約
    • 英数字、ハイフン、アンダースコアのみ使用可能(最大63文字)

https://docs.cloud.google.com/kubernetes-engine/docs/how-to/expose-custom-metrics-autoscaling

どんなユースケースがありそう?

アップデート資料でも特にAI/MLワークロードへの活用が強調されており、具体的には以下のようなケースに向いてそうです。

  • 推論キューのスケーリング
    • リクエストキューの深さに応じてPodをスケール
  • GPU/TPU利用率ベースのスケーリング
    • 強化学習などの学習ジョブに対応
  • マルチエージェントワークフロー
    • 処理量に応じた動的なスケーリング
  • 一般的なキュー処理システム
    • ジョブキューの深さに応じたワーカーのスケール

本機能に限った話ではないですが、CPU/メモリ使用率とは異なり、アプリケーションのビジネスロジックに直結したメトリクスでスケーリングできるのが嬉しいポイントですね。

ざっくりアーキテクチャ

機能のアーキテクチャ

まず機能全体の仕組みを整理します。

AutoscalingMetric CRDで「どのPodのどのエンドポイントからどのメトリクスを収集するか」を定義すると、GKEの内部コンポーネントがPodへ直接スクレイプします。
収集したメトリクス値は autoscaling API に push され、HPA がこれを参照してスケーリングの可否を判断します。
また複数レプリカが存在する場合、GKEはPodごとに個別にスクレイプし、HPAはその平均値(AverageValue)を使ってレプリカ数を計算します。

今回の検証のアーキテクチャ

今回の検証では、キューの深さをメトリクスとして公開するシンプルなPythonアプリを使いました。

/enqueueを叩くとキューの深さが増え、HPAがスケールアウトの判断をします。
/dequeueを叩くとキューの深さが減り、HPAがスケールインの判断をします。

デプロイ

Google Cloudリソース作成

まずはGKEクラスターとイメージ格納用のArtifact Registryのリポジトリを作成します。

クラスターの作成

以下の環境変数を設定します。

export PROJECT_ID=$(gcloud config get project)
export REGION="asia-northeast1"
export CLUSTER_NAME="custom-metrics-cluster"
export REPO_NAME="custom-metrics-repo"

次にGKEクラスターを作成します。

AutoscalingMetricにはGKE 1.35.1以上が必要なため、Rapidチャンネルを指定します。
今回は検証用途なので最小構成にしています。

gcloud container clusters create ${CLUSTER_NAME} \
    --project=${PROJECT_ID} \
    --location=${REGION}-a \
    --release-channel=rapid \
    --machine-type=e2-medium \
    --num-nodes=2 \ #スケーリングを考慮して2ノード
    --spot

作成後はkubectlの認証情報を取得します。

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

今回作成されたクラスターのバージョンはv1.35.2-gke.1485000で、
要件の1.35.1以上を満たしていることが確認できます。

kubectl get node
NAME                                                  STATUS   ROLES    AGE   VERSION
gke-custom-metrics-clust-default-pool-653901b9-576d   Ready    <none>   69s   v1.35.2-gke.1485000
gke-custom-metrics-clust-default-pool-653901b9-9wz4   Ready    <none>   67s   v1.35.2-gke.1485000

リポジトリの作成

続いて、コンテナイメージを格納するArtifact Registryのリポジトリを作成します。

gcloud artifacts repositories create ${REPO_NAME} \
    --project=${PROJECT_ID} \
    --repository-format=docker \
    --location=${REGION}

最後にCloud Buildを使ってアプリのイメージをビルド&プッシュします。

export IMAGE="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/queue-app:latest"

gcloud builds submit \
    --project=${PROJECT_ID} \
    --region=${REGION} \
    --tag=${IMAGE} \
    app/

以下のようにSTATUSがSUCCESSになればOKです。

ID                   CREATE_TIME                DURATION  SOURCE                               IMAGES                                                                      STATUS
XXX-XXX-XXX-XXX-XXX  2026-05-02T05:41:41+00:00  17S       gs://XXX-XXX_XXX/source/XXX.XXX.tgz  asia-northeast1-docker.pkg.dev/XXX/custom-metrics-repo/queue-app (+1 more)  SUCCESS

Kubernetesリソース作成

ここではAutoscalingMetricとHPAの設定に触れます。
他のリソースについては冒頭のGithubリポジトリにてご確認ください。

AutoscalingMetricの設定

AutoscalingMetricはGKEがどのPodのどのエンドポイントからメトリクスを収集するか、を定義するリソースです。

autoscaling-metric.yaml
apiVersion: autoscaling.gke.io/v1beta1
kind: AutoscalingMetric
metadata:
  name: queue-depth-metric
  namespace: custom-metrics-demo
spec:
  metrics:
  - pod:
      selector:
        matchLabels:
          app: queue-app            # 対象Podのラベルセレクタ
      containers:
      - endpoint:
          port: 8080
          path: /metrics            # Prometheusエンドポイントのパス
        metrics:
        - gauge:
            name: queue-depth                   # HPA側で参照する名前
            prometheusMetricName: app_queue_depth  # Prometheusのメトリクス名

HPAの設定

HPAのメトリクス名にはautoscaling.gke.io|{AutoscalingMetric名}|{gauge名}という命名規則があります。
この点が少しクセがあるので注意が必要です。

hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: queue-app-hpa
  namespace: custom-metrics-demo
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: queue-app
  minReplicas: 1
  maxReplicas: 5
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 60   # 検証用に短縮(デフォルト300秒)
    scaleUp:
      stabilizationWindowSeconds: 0    # 即時スケールアウト
  metrics:
  - type: Pods
    pods:
      metric:
        # autoscaling.gke.io|{AutoscalingMetric名}|{gauge名}
        name: autoscaling.gke.io|queue-depth-metric|queue-depth
      target:
        type: AverageValue
        averageValue: "5"              # Pod あたりの平均 queue_depth が 5 を超えたらスケールアウト

デプロイ

namespace → app → HPAの順に適用します。

kubectl apply -f manifests/namespace.yaml
kubectl apply -f manifests/deployment.yaml
kubectl apply -f manifests/service.yaml
kubectl apply -f manifests/autoscaling-metric.yaml
kubectl apply -f manifests/hpa.yaml

デプロイ後にAutoscalingMetricの状態を確認します。

kubectl describe autoscalingmetric queue-depth-metric -n custom-metrics-demo

Metric StatusesにHPA側で使用するメトリクス名が表示されていれば、GKEがPodからメトリクスを正常に収集できている状態です。

Statusのみ抜粋
Status:
  Metric Statuses:
    Hpa Name:  autoscaling.gke.io|queue-depth-metric|queue-depth
    Name:      queue-depth

HPAの状態も確認します。

kubectl describe hpa queue-app-hpa -n custom-metrics-demo

ValidMetricFoundと表示されていれば、HPAがカスタムメトリクスを正常に取得できています。

Conditionsのみ抜粋
Conditions:
  Type            Status  Reason               Message
  ----            ------  ------               -------
  AbleToScale     True    ScaleDownStabilized  recent recommendations were higher than current one, applying the highest recent recommendation
  ScalingActive   True    ValidMetricFound     the HPA was able to successfully calculate a replica count from pods metric autoscaling.gke.io|queue-depth-metric|queue-depth
  ScalingLimited  False   DesiredWithinRange   the desired count is within the acceptable range

使ってみた

では実際にキューを操作してスケールアウト/スケールインを確認してみます。

まずポートフォワードでローカルからサービスにアクセスできるようにします。

kubectl port-forward svc/queue-app 8080:8080 -n custom-metrics-demo
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

また別ターミナルからHPAのステータスをウォッチしておきます。

kubectl get hpa queue-app-hpa -n custom-metrics-demo -w
NAME            REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
queue-app-hpa   Deployment/queue-app   0/5       1         5         1          4m41s

スケールアウトの確認

別ターミナルから/enqueueを15回呼び出して、キューをためます。

for i in $(seq 1 15); do
  curl -s -X POST http://localhost:8080/enqueue
  echo ""
done
# 現在の値を確認
curl -s http://localhost:8080/metrics
# HELP app_queue_depth Current number of pending items in the queue
# TYPE app_queue_depth gauge
app_queue_depth 15

queue_depthが15になりました。
今回のHPAはaverageValue: 5で設定しているので、ceil(1 * 15 / 5) = 3レプリカへのスケールアウトするはずです。

その後ウォッチしていたHPAのステータスを見ていると、10秒程度でスケールアウトしました。
(stabilizationWindowSecond=0にしているので、想定通り)

NAME            REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
queue-app-hpa   Deployment/queue-app   0/5       1         5         1          4m41s
queue-app-hpa   Deployment/queue-app   15/5      1         5         1          5m16s
queue-app-hpa   Deployment/queue-app   15/5      1         5         3          5m26s #ここでスケールアウト
queue-app-hpa   Deployment/queue-app   5/5       1         5         3          6m20s

Podが3台に増えていることが確認できます。

kubectl get pod -n custom-metrics-demo
NAME                        READY   STATUS    RESTARTS   AGE
queue-app-777cb4ccc-jf62q   1/1     Running   0          2m47s
queue-app-777cb4ccc-mv8ck   1/1     Running   0          8m3s
queue-app-777cb4ccc-zz49r   1/1     Running   0          2m47s

スケールインの確認

では次に/dequeueを15回呼び出してキューを空にします。

for i in $(seq 1 15); do
  curl -s -X POST http://localhost:8080/dequeue
  echo ""
done
# 現在の値を確認
curl -s http://localhost:8080/metrics
# HELP app_queue_depth Current number of pending items in the queue
# TYPE app_queue_depth gauge
app_queue_depth 0

その後ウォッチしていたHPAのステータスを見ていると、1分程度でスケールインしました。
(stabilizationWindowSecond=60にしているので、想定通り)

NAME            REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
queue-app-hpa   Deployment/queue-app   0/5       1         5         1          4m41s
queue-app-hpa   Deployment/queue-app   15/5      1         5         1          5m16s
queue-app-hpa   Deployment/queue-app   15/5      1         5         3          5m26s
queue-app-hpa   Deployment/queue-app   5/5       1         5         3          6m20s
queue-app-hpa   Deployment/queue-app   0/5       1         5         3          9m6s
queue-app-hpa   Deployment/queue-app   0/5       1         5         3          9m56s
queue-app-hpa   Deployment/queue-app   0/5       1         5         1          10m #スケールイン

Podも1台に減っていることが確認できます。

kubectl get pod -n custom-metrics-demo
NAME                        READY   STATUS    RESTARTS   AGE
queue-app-777cb4ccc-zz49r   1/1     Running   0          5m29s

さいごに

以上、GKEのカスタムメトリクスを使ったHPAでのスケーリングが外部コンポーネントなしでできるようになったので試してみました。

従来はPrometheusやCustom Metrics Adapterの構築・運用が必要だったところ、AutoscalingMetric CRDを定義するだけでGKEが直接Podからメトリクスを収集してHPAに連携してくれるのはとてもシンプルで良いと思います。

なお現時点ではゲージ型のみ・クラスタあたり最大20メトリクスといった制約はありますが、シンプルなユースケースであれば追加コンポーネントなしで十分活用できそうです。

この記事をシェアする

関連記事