すべてのプロダクト
Search
ドキュメントセンター

Container Service for Kubernetes:ASM メトリクスを用いたワークロードの自動スケーリング

最終更新日:Mar 26, 2026

Service Mesh (ASM) は、アプリケーションコードへの変更を一切加えることなく、サービスメッシュを通過するすべてのリクエストについてテレメトリデータを生成します。モニタリングの「4 つのゴールデンシグナル」(レイテンシー、トラフィック、エラー、飽和度)に基づき、ASM は管理対象のサービスに対して一連のメトリクスを提供します。これらのメトリクスを Kubernetes Horizontal Pod Autoscaler (HPA) に供給することで、CPU やメモリ使用率といったリソース指標に依存せず、リクエスト数などの実際のトラフィック信号に基づいてワークロードをスケーリングできます。

本チュートリアルでは、Prometheus による ASM メトリクスの収集、カスタムメトリクスアダプターのデプロイ、およびサンプルワークロードの平均リクエスト数がしきい値を超えた際にスケールアウトするよう構成された HPA の設定まで、エンドツーエンドの手順を説明します。

仕組み

Kubernetes では、自動スケーリングを以下の 2 つの次元でサポートしています。

  • Cluster Autoscaler (CA) —— ペンディング中の Pod のスケジューリング要求に基づき、ノードを追加または削除します。

  • Horizontal Pod Autoscaler (HPA) —— Deployment または StatefulSet のレプリカ数を調整します。

Kubernetes の集約レイヤーにより、サードパーティ製アプリケーションが API アドオンコンポーネントとして Kubernetes API を拡張できます。これらのアドオンコンポーネントは Custom Metrics API を実装し、HPA が任意のメトリクスにアクセスできるようにします。HPA は以下の 3 つの Kubernetes API からメトリクスを取得します。

API目的例:メトリクス
Resource Metrics API (metrics.k8s.io)コアリソースメトリクスCPU、メモリ
Custom Metrics API (custom.metrics.k8s.io)Kubernetes オブジェクトに関連付けられたアプリケーション固有のメトリクスPod、Ingress
External Metrics API (external.metrics.k8s.io)クラスター外部のシステムから取得されるメトリクスPrometheus クエリ、クラウドモニタリング

ASM メトリクスは、Kubernetes オブジェクトモデルの外側に位置する Prometheus から発生します。このため、External Metrics API を採用することが最適な選択です。kube-metrics-adapter は Prometheus と External Metrics API を橋渡しし、HPA が ASM メトリクスを直接照会できるようにします。

Architecture: ASM sidecar proxies report Istio metrics to Prometheus. The kube-metrics-adapter exposes those metrics through the External Metrics API. The HPA reads the metrics and scales the target Deployment.

自動スケーリングで利用可能な ASM メトリクス

ASM は HTTP、HTTP/2、gRPC トラフィック向けにIstio 標準メトリクスを生成します。自動スケーリングで最もよく使用されるメトリクスは以下のとおりです。

メトリクスタイプ利用シーン例:PromQL
istio_requests_totalCounterリクエスト数に基づくスケーリングsum(rate(istio_requests_total{destination_workload="<workload>"}[1m]))
istio_request_duration_millisecondsDistributionP99 レイテンシーに基づくスケーリングhistogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket{destination_workload="<workload>"}[1m])) by (le))
istio_requests_total(フィルター適用済み)Counterエラー率に基づくスケーリングsum(rate(istio_requests_total{destination_workload="<workload>", response_code=~"5.."}[1m]))

これらのクエリで使用される主なラベル:

  • destination_workload —— 対象ワークロードの名前

  • destination_workload_namespace —— 対象ワークロードの名前空間

  • reporter —— サーバー側レポートには destination、クライアント側レポートには source を指定

本チュートリアルでは、リクエスト数に基づくスケーリングのために istio_requests_total を使用します。レイテンシーまたはエラー率に基づくスケーリングを行う場合は、上記の代替 PromQL クエリに置き換えてください。

前提条件

開始する前に、以下の環境が整っていることを確認してください。

ステップ 1:Prometheus メトリクス収集の有効化

ASM がメトリクスを Prometheus インスタンスにエクスポートできるようにします。詳細については、「Managed Service for Prometheus で監視メトリクスを収集する」をご参照ください。

ステップ 2:カスタムメトリクスアダプターのデプロイ

kube-metrics-adapter をインストールします。このアダプターは External Metrics API のプロバイダーとして自身を登録し、HPA のメトリクス要求を Prometheus クエリに変換します。

  1. Helm を使用してアダプターをインストールします。Prometheus サーバーが異なる名前空間で実行されている場合、または別のサービス名を使用している場合は、http://prometheus.istio-system.svc:9090 をご利用の Prometheus サーバーの URL に置き換えてください。

       helm -n kube-system install asm-custom-metrics ./kube-metrics-adapter \
         --set prometheus.url=http://prometheus.istio-system.svc:9090
  2. インストールを検証します。

    1. autoscaling/v2 API が利用可能であることを確認します。

         kubectl api-versions | grep "autoscaling/v2"

      期待される出力:

         autoscaling/v2
    2. アダプターポッドが実行中であることを確認します。

         kubectl get po -n kube-system | grep metrics-adapter

      期待される出力:

         asm-custom-metrics-kube-metrics-adapter-85c6d5d865-2****   1/1     Running   0   19s
    3. External Metrics API エンドポイントが正しく登録されていることを確認します。

         kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1" | jq .

      期待される出力:

         {
           "kind": "APIResourceList",
           "apiVersion": "v1",
           "groupVersion": "external.metrics.k8s.io/v1beta1",
           "resources": [
             {
               "name": "prometheus-query",
               "singularName": "",
               "namespaced": true,
               "kind": "ExternalMetricValueList",
               "verbs": [
                 "get"
               ]
             }
           ]
         }

      resources 配列が空になっているのは、まだ HPA がメトリクスクエリを登録していないためです。ステップ 4 で HPA をデプロイすると、配列が埋まります。

ステップ 3:サンプルアプリケーションのデプロイ

名前空間の作成

test という名前の名前空間を作成し、自動サイドカーインジェクションを有効にします。詳細については、「名前空間とクォータの管理」および「自動インジェクションを有効にする」をご参照ください。

podinfo アプリケーションのデプロイ

  1. 以下の内容で podinfo.yaml というファイルを作成します。

    podinfo.yaml

       apiVersion: apps/v1
       kind: Deployment
       metadata:
         name: podinfo
         namespace: test
         labels:
           app: podinfo
       spec:
         minReadySeconds: 5
         strategy:
           rollingUpdate:
             maxUnavailable: 0
           type: RollingUpdate
         selector:
           matchLabels:
             app: podinfo
         template:
           metadata:
             annotations:
               prometheus.io/scrape: "true"
             labels:
               app: podinfo
           spec:
             containers:
             - name: podinfod
               image: stefanprodan/podinfo:latest
               imagePullPolicy: IfNotPresent
               ports:
               - containerPort: 9898
                 name: http
                 protocol: TCP
               command:
               - ./podinfo
               - --port=9898
               - --level=info
               livenessProbe:
                 exec:
                   command:
                   - podcli
                   - check
                   - http
                   - localhost:9898/healthz
                 initialDelaySeconds: 5
                 timeoutSeconds: 5
               readinessProbe:
                 exec:
                   command:
                   - podcli
                   - check
                   - http
                   - localhost:9898/readyz
                 initialDelaySeconds: 5
                 timeoutSeconds: 5
               resources:
                 limits:
                   cpu: 2000m
                   memory: 512Mi
                 requests:
                   cpu: 100m
                   memory: 64Mi
       ---
       apiVersion: v1
       kind: Service
       metadata:
         name: podinfo
         namespace: test
         labels:
           app: podinfo
       spec:
         type: ClusterIP
         ports:
           - name: http
             port: 9898
             targetPort: 9898
             protocol: TCP
         selector:
           app: podinfo
  2. マニフェストを適用します。

       kubectl apply -n test -f podinfo.yaml

ロードテスターのデプロイ

  1. 以下の内容で loadtester.yaml というファイルを作成します。

    loadtester.yaml

       apiVersion: apps/v1
       kind: Deployment
       metadata:
         name: loadtester
         namespace: test
         labels:
           app: loadtester
       spec:
         selector:
           matchLabels:
             app: loadtester
         template:
           metadata:
             labels:
               app: loadtester
             annotations:
               prometheus.io/scrape: "true"
           spec:
             containers:
               - name: loadtester
                 image: weaveworks/flagger-loadtester:0.18.0
                 imagePullPolicy: IfNotPresent
                 ports:
                   - name: http
                     containerPort: 8080
                 command:
                   - ./loadtester
                   - -port=8080
                   - -log-level=info
                   - -timeout=1h
                 livenessProbe:
                   exec:
                     command:
                       - wget
                       - --quiet
                       - --tries=1
                       - --timeout=4
                       - --spider
                       - http://localhost:8080/healthz
                   timeoutSeconds: 5
                 readinessProbe:
                   exec:
                     command:
                       - wget
                       - --quiet
                       - --tries=1
                       - --timeout=4
                       - --spider
                       - http://localhost:8080/healthz
                   timeoutSeconds: 5
                 resources:
                   limits:
                     memory: "512Mi"
                     cpu: "1000m"
                   requests:
                     memory: "32Mi"
                     cpu: "10m"
                 securityContext:
                   readOnlyRootFilesystem: true
                   runAsUser: 10001
       ---
       apiVersion: v1
       kind: Service
       metadata:
         name: loadtester
         namespace: test
         labels:
           app: loadtester
       spec:
         type: ClusterIP
         selector:
           app: loadtester
         ports:
           - name: http
             port: 80
             protocol: TCP
             targetPort: http
  2. マニフェストを適用します。

       kubectl apply -n test -f loadtester.yaml

デプロイの検証

  1. 両方の Pod がサイドカーアイネクション付きで実行中であることを確認します(2/2 コンテナ)。期待される出力:

       kubectl get pod -n test
       NAME                          READY   STATUS    RESTARTS   AGE
       loadtester-64df4846b9-nxhvv   2/2     Running   0          2m8s
       podinfo-6d845cc8fc-26xbq      2/2     Running   0          11m
  2. ロードテスターからテストリクエストを送信し、接続性を確認します。正常な応答が得られれば、サンプルアプリケーションがサービスメッシュ経由で到達可能であることが確認できます。

       export loadtester=$(kubectl -n test get pod -l "app=loadtester" \
         -o jsonpath='{.items[0].metadata.name}')
       kubectl -n test exec -it ${loadtester} -c loadtester -- \
         hey -z 5s -c 10 -q 2 http://podinfo.test:9898

ステップ 4:ASM メトリクスを用いた HPA の構成

リクエスト数に基づき podinfo Deployment をスケーリングする HPA を定義します。この構成では、以下の 3 つの要素を関連付けます。

設定対象設定先目的
PromQL クエリHPA アノテーション照会する Prometheus メトリクスを定義
メトリクス名+ラベルspec.metrics[].externalHPA がアノテーションを参照するために使用する検索キー
ターゲットしきい値spec.metrics[].external.targetスケールアウトが開始されるリクエストレート
本例では、Kubernetes 1.23 以降が必要な HPA API バージョン autoscaling/v2 を使用しています。v2beta2 は Kubernetes 1.26 で削除されています。
  1. 以下の内容で hpa.yaml というファイルを作成します。

    主要フィールドの説明:

    フィールド説明
    metric-config.external.prometheus-query.prometheus/processed-requests-per-secondPromQL クエリを埋め込むアノテーションです。接尾辞(processed-requests-per-second)は、アノテーションと HPA メトリクスセレクターを関連付けるユーザー定義の名前です。
    metrics[].external.metric.name固定識別子 prometheus-query を指定する必要があります。これは kube-metrics-adapter が認識する識別子です。
    metrics[].external.metric.selector.matchLabels.query-nameアノテーションキーの接尾辞(processed-requests-per-second)と一致させる必要があります。
    target.averageValuePod あたりのしきい値です。HPA はクエリ結果の合計値を現在のレプリカ数で割り、この値と比較します。
       apiVersion: autoscaling/v2
       kind: HorizontalPodAutoscaler
       metadata:
         name: podinfo
         namespace: test
         annotations:
           # アノテーション形式:metric-config.external.prometheus-query.prometheus/<query-name>
           # <query-name> は、以下 spec.metrics 内の query-name ラベルと一致させる必要があります。
           # 値は、kube-metrics-adapter が Prometheus に送信する PromQL クエリです。
           metric-config.external.prometheus-query.prometheus/processed-requests-per-second: |
             sum(
                 rate(
                     istio_requests_total{
                       destination_workload="podinfo",
                       destination_workload_namespace="test",
                       reporter="destination"
                     }[1m]
                 )
             )
       spec:
         maxReplicas: 10
         minReplicas: 1
         scaleTargetRef:
           apiVersion: apps/v1
           kind: Deployment
           name: podinfo
         metrics:
           - type: External          # Prometheus メトリクスは Kubernetes オブジェクトではないため、External を使用
             external:
               metric:
                 name: prometheus-query                  # kube-metrics-adapter 用の固定メトリクス名
                 selector:
                   matchLabels:
                     query-name: processed-requests-per-second  # 上記アノテーションキーと一致させる必要があります
               target:
                 type: AverageValue
                 averageValue: "10"   # Pod あたりの平均リクエスト数が 10 req/s を超えるとスケールアウト
  2. HPA を適用します。

       kubectl apply -f hpa.yaml
  3. External Metrics API が登録済みのメトリクスをリスト表示することを確認します。期待される出力: prometheus-query リソースが、HPA がアダプターにメトリクスを登録したことを示します。

       kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1" | jq .
       {
         "kind": "APIResourceList",
         "apiVersion": "v1",
         "groupVersion": "external.metrics.k8s.io/v1beta1",
         "resources": [
           {
             "name": "prometheus-query",
             "singularName": "",
             "namespaced": true,
             "kind": "ExternalMetricValueList",
             "verbs": [
               "get"
             ]
           }
         ]
       }

自動スケーリングの検証

  1. ロードテスターポッドから継続的な負荷を発生させます。この操作では、5 分間、10 並列ワーカー × 各ワーカー 5 QPS(合計 50 RPS)の負荷をかけます。

       # ロードテスターポッド名を取得(ステップ 3 で $loadtester が既に設定済みの場合はスキップ)
       export loadtester=$(kubectl -n test get pod -l "app=loadtester" \
         -o jsonpath='{.items[0].metadata.name}')
    
       kubectl -n test exec -it ${loadtester} -c loadtester -- \
         hey -z 5m -c 10 -q 5 http://podinfo.test:9898
  2. 別ターミナルで HPA の状態を監視します。期待される出力(約 1 分後):

    説明

    HPA は 30 秒ごとにメトリクスを同期します。スケーリング判断は、直前の 3~5 分間にスケーリングイベントが発生していない場合にのみ有効になります。このクールダウン期間により、急激かつ矛盾したスケーリング判断が防止され、必要に応じて Cluster Autoscaler が新規ノードをプロビジョニングする時間を確保できます。

       watch kubectl -n test get hpa/podinfo
       NAME      REFERENCE            TARGETS          MINPODS   MAXPODS   REPLICAS   AGE
       podinfo   Deployment/podinfo   8308m/10 (avg)   1         10        6          124m
  3. 負荷テスト終了後のスケールダウンを観察します。負荷テストが完了すると、リクエスト数はゼロに低下します。HPA は徐々に Deployment をスケールダウンし、最終的にレプリカ数を 1 に戻します。

次のステップ

  • リクエスト数ではなくレイテンシーまたはエラー率に基づいてスケーリングする場合は、HPA アノテーション内の PromQL クエリを、「自動スケーリングで利用可能な ASM メトリクス」表に掲載されている代替クエリに置き換えてください。

  • スケールアップ/スケールダウンの動作(安定化ウィンドウ、スケーリングポリシー)を調整する場合は、HPA spec に behavior フィールドを追加します。「Configurable scaling behavior」(Kubernetes ドキュメント)をご参照ください。

  • Istio メトリクスおよびそのラベルの完全な一覧については、「Istio 標準メトリクス」をご参照ください。