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 メトリクスを直接照会できるようにします。
自動スケーリングで利用可能な ASM メトリクス
ASM は HTTP、HTTP/2、gRPC トラフィック向けにIstio 標準メトリクスを生成します。自動スケーリングで最もよく使用されるメトリクスは以下のとおりです。
| メトリクス | タイプ | 利用シーン | 例:PromQL |
|---|---|---|---|
istio_requests_total | Counter | リクエスト数に基づくスケーリング | sum(rate(istio_requests_total{destination_workload="<workload>"}[1m])) |
istio_request_duration_milliseconds | Distribution | P99 レイテンシーに基づくスケーリング | 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 クエリに置き換えてください。
前提条件
開始する前に、以下の環境が整っていることを確認してください。
クラスターにデプロイされた Prometheus および Grafana インスタンス
Prometheus メッシュモニタリングとの連携
ステップ 1:Prometheus メトリクス収集の有効化
ASM がメトリクスを Prometheus インスタンスにエクスポートできるようにします。詳細については、「Managed Service for Prometheus で監視メトリクスを収集する」をご参照ください。
ステップ 2:カスタムメトリクスアダプターのデプロイ
kube-metrics-adapter をインストールします。このアダプターは External Metrics API のプロバイダーとして自身を登録し、HPA のメトリクス要求を Prometheus クエリに変換します。
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インストールを検証します。
autoscaling/v2API が利用可能であることを確認します。kubectl api-versions | grep "autoscaling/v2"期待される出力:
autoscaling/v2アダプターポッドが実行中であることを確認します。
kubectl get po -n kube-system | grep metrics-adapter期待される出力:
asm-custom-metrics-kube-metrics-adapter-85c6d5d865-2**** 1/1 Running 0 19sExternal 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 アプリケーションのデプロイ
以下の内容で
podinfo.yamlというファイルを作成します。マニフェストを適用します。
kubectl apply -n test -f podinfo.yaml
ロードテスターのデプロイ
以下の内容で
loadtester.yamlというファイルを作成します。マニフェストを適用します。
kubectl apply -n test -f loadtester.yaml
デプロイの検証
両方の Pod がサイドカーアイネクション付きで実行中であることを確認します(2/2 コンテナ)。期待される出力:
kubectl get pod -n testNAME READY STATUS RESTARTS AGE loadtester-64df4846b9-nxhvv 2/2 Running 0 2m8s podinfo-6d845cc8fc-26xbq 2/2 Running 0 11mロードテスターからテストリクエストを送信し、接続性を確認します。正常な応答が得られれば、サンプルアプリケーションがサービスメッシュ経由で到達可能であることが確認できます。
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[].external | HPA がアノテーションを参照するために使用する検索キー |
| ターゲットしきい値 | spec.metrics[].external.target | スケールアウトが開始されるリクエストレート |
本例では、Kubernetes 1.23 以降が必要な HPA API バージョンautoscaling/v2を使用しています。v2beta2は Kubernetes 1.26 で削除されています。
以下の内容で
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 を超えるとスケールアウトHPA を適用します。
kubectl apply -f hpa.yamlExternal 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" ] } ] }
自動スケーリングの検証
ロードテスターポッドから継続的な負荷を発生させます。この操作では、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別ターミナルで HPA の状態を監視します。期待される出力(約 1 分後):
説明HPA は 30 秒ごとにメトリクスを同期します。スケーリング判断は、直前の 3~5 分間にスケーリングイベントが発生していない場合にのみ有効になります。このクールダウン期間により、急激かつ矛盾したスケーリング判断が防止され、必要に応じて Cluster Autoscaler が新規ノードをプロビジョニングする時間を確保できます。
watch kubectl -n test get hpa/podinfoNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE podinfo Deployment/podinfo 8308m/10 (avg) 1 10 6 124m負荷テスト終了後のスケールダウンを観察します。負荷テストが完了すると、リクエスト数はゼロに低下します。HPA は徐々に Deployment をスケールダウンし、最終的にレプリカ数を 1 に戻します。
次のステップ
リクエスト数ではなくレイテンシーまたはエラー率に基づいてスケーリングする場合は、HPA アノテーション内の PromQL クエリを、「自動スケーリングで利用可能な ASM メトリクス」表に掲載されている代替クエリに置き換えてください。
スケールアップ/スケールダウンの動作(安定化ウィンドウ、スケーリングポリシー)を調整する場合は、HPA spec に
behaviorフィールドを追加します。「Configurable scaling behavior」(Kubernetes ドキュメント)をご参照ください。Istio メトリクスおよびそのラベルの完全な一覧については、「Istio 標準メトリクス」をご参照ください。