CPU およびメモリのメトリックは、必ずしも実際のアプリケーション負荷を反映するわけではありません。スケーリング信号がビジネスレベル(例:1 秒あたりの HTTP リクエスト数 (RPS) やメッセージキューの深さなど)である場合、カスタムメトリックを使用すると、より正確なトリガーを得ることができます。このガイドでは、ack-alibaba-cloud-metrics-adapter コンポーネントを用いて AdvancedHorizontalPodAutoscaler (AHPA) を設定し、Prometheus によるスクレイプされたメトリックに基づいて Deployment を自動スケーリングする方法について説明します。
AHPA は Kubernetes External Metrics API を利用しており、Pod レベルのメトリックに限らず、ご利用の Prometheus インスタンスで利用可能なあらゆるメトリックを照会できます。標準の HPA カスタムメトリック(Pods / Object タイプ)と比較して、External Metrics はより広範な柔軟性を提供します。スケーリングの信号源が Managed Service for Prometheus などのモニタリングサービスである場合は、External Metrics をご使用ください。
前提条件
開始する前に、以下の条件を満たしていることを確認してください。
Managed Service for Prometheus が有効化された ACK クラスターが存在すること
ステップ 1:サンプルアプリのデプロイとメトリック収集の構成
このステップでは、requests_per_second を Prometheus メトリックとして公開するサンプルアプリケーションとロードジェネレーターをデプロイし、Prometheus を設定して、このメトリックをスクレイプするようにします。
アプリおよび負荷生成ツールのデプロイ
ACK コンソールにログインします。左側ナビゲーションウィンドウで、[クラスター] をクリックします。
ご使用のクラスター名をクリックします。左側ナビゲーションウィンドウで、[ワークロード] > [デプロイメント] をクリックします。
「デプロイメント」ページで、[YAML からの作成] をクリックします。次の YAML を貼り付け、[作成] をクリックします。これにより、以下のリソースがデプロイされます:
sample-app: ポート 8080 の/metricsでrequests_per_secondメトリックを公開するサーバーfib-loader-qps:sample-appにトラフィックを送信するロードジェネレーター
apiVersion: apps/v1 kind: Deployment metadata: name: sample-app labels: app: sample-app spec: replicas: 1 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - image: registry.cn-hangzhou.aliyuncs.com/acs/knative-sample-fib-server:v1 name: metrics-provider ports: - name: http containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: sample-app namespace: default labels: app: sample-app spec: ports: - port: 8080 name: http protocol: TCP targetPort: 8080 selector: app: sample-app type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: fib-loader-qps namespace: default spec: progressDeadlineSeconds: 600 replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app: fib-loader-qps strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: creationTimestamp: null labels: app: fib-loader-qps spec: containers: - args: - -c - | /ko-app/fib-loader --service-url="http://sample-app.${NAMESPACE}:8080/" --save-path=/tmp/fib-loader-chart.html command: - sh env: - name: NAMESPACE valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.namespace image: registry.cn-huhehaote.aliyuncs.com/kubeway/knative-sample-fib-loader:20201126-110434 imagePullPolicy: IfNotPresent name: loader ports: - containerPort: 8090 name: chart protocol: TCP
ARMS での ServiceMonitor の有効化
ARMS コンソールにログインします。左側ナビゲーションウィンドウで、[統合管理] をクリックします。
[統合環境] タブで、[コンテナサービス] タブをクリックします。ご使用の ACK インスタンスを見つけ、[操作] 列の [メトリック収集] をクリックします。
[メトリック収集] ページで、[Service Monitor] タブをクリックします。
sample-appを見つけ、[操作] 列の [有効化] をクリックし、確認します。
ステップ 2:メトリックアダプターのデプロイ
メトリックアダプターは、Managed Service for Prometheus と Kubernetes External Metrics API を接続するブリッジであり、AHPA がカスタムメトリックを照会できるようにします。
Prometheus の内部エンドポイントの取得
ARMS コンソールにログインします。左側ナビゲーションウィンドウで、[Managed Service for Prometheus] > [インスタンス] を選択します。
[Prometheus インスタンス] ページで、インスタンスのリージョンを選択し、インスタンス名をクリックします。 インスタンス名は
arms_metrics_{RegionId}_XXXのフォーマットです。左側ナビゲーションバーで、[設定項目] をクリックします。HTTP API アドレス(Grafana 読み取りアドレス) の下にある 内部ネットワーク URL をコピーします。
インスタンスでトークン認証が有効になっている場合は、アクセストークンもコピーします。

ack-alibaba-cloud-metrics-adapter のインストール
ACK コンソールで、左側ナビゲーションウィンドウから [マーケットプレイス] > [マーケットプレイス] をクリックします。
[アプリカタログ] タブをクリックし、
ack-alibaba-cloud-metrics-adapterを検索して、右上隅の [デプロイ] をクリックします。[基本情報] ページで、ご使用の [クラスター] および [名前空間] を選択し、[次へ] をクリックします。
[パラメーター設定] ウィザードで、[チャートバージョン] を選択します。[パラメーター] 領域で以下の値を設定し、[OK] をクリックします。
パラメーター 必須 説明 prometheus.urlはい Managed Service for Prometheus インスタンスの内部ネットワーク URL prometheus.prometheusHeaderいいえ トークン認証用の Authorization ヘッダー。認証が無効な場合は空欄のままにしてください。 prometheus: enabled: true # 必須:Managed Service for Prometheus の内部ネットワーク URL url: http://cn-beijing-intranet.arms.aliyuncs.com:9090/api/v1/prometheus/<instance-id>/<uid>/<cluster-id>/<region> # トークン認証が有効な場合のみ必須 prometheusHeader: - Authorization: <your-access-token>
カスタムメトリックの構成
ACK コンソールで、左側ナビゲーションウィンドウから [アプリケーション] > [Helm] をクリックします。alibaba-cloud-metrics-adapter を見つけ、[操作] 列の [更新] をクリックします。
以下の YAML コンテンツをコピーし、テンプレート内の対応するパラメーターを上書きします。
requests_per_secondパラメーターは、実際の Prometheus メトリック名に変更する必要があります。その後、[更新] をクリックします。以下は構成の一部です。既存の Helm values ファイル全体を置き換えるのではなく、該当するパラメーター部分のみを上書きしてください。
パラメーター 必須 説明 seriesQueryはい Prometheus 内のメトリック名。完全一致する必要があります。 name.asはい External Metrics API 経由で公開される名前。AHPA はこの名前を参照します。 metricsQueryはい AHPA がメトリックを照会する際に適用される PromQL 集約式。 enabledはい Prometheus アダプターを有効化するには、 trueを設定します。...... prometheus: adapter: rules: custom: - metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) name: as: requests_per_second # External Metrics API に公開される名前 resources: overrides: namespace: resource: namespace seriesQuery: requests_per_second # Prometheus 内のメトリック名と完全一致する必要があります default: false enabled: true # Prometheus アダプターを有効化するには true を設定します ......External Metrics API 経由でメトリックが利用可能であることを確認します。
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/default/requests_per_second"期待される出力:
{"kind":"ExternalMetricValueList","apiVersion":"external.metrics.k8s.io/v1beta1","metadata":{},"items":[{"metricName":"requests_per_second","metricLabels":{},"timestamp":"2023-08-15T07:59:09Z","value":"10"}]}応答にメトリックが表示された場合、アダプターは正しく構成されています。
ステップ 3:AHPA リソースの作成
External Metrics API がデータを返すようになったら、sample-app を requests_per_second に基づいて自動スケーリングするための AHPA リソースを作成します。
以下の YAML を適用します。メトリック名、
averageValueのしきい値、およびminReplicas/maxReplicasをご使用のワークロードに合わせて調整してください。この例では
minReplicas: 0を設定しており、AHPA がデプロイメントをゼロまでスケールダウンできるようにしています。ゼロから 1 へのスケールアップには、メトリック値がaverageValueのしきい値を超える必要があります。デプロイメントがゼロにスケールダウンした場合、AHPA がゼロから 1 へのトランジションを担当します。1 つ以上のレプリカが実行中になると、標準的なスケーリングロジック(1 から N 個のレプリカ)が、averageValueのしきい値に基づいて適用されます。パラメーター 説明 metrics[].external.metric.nameアダプター構成内の name.asの値と一致する必要があります。target.averageValuePod あたりのトリガーしきい値。メトリック値がこの値を超えるとスケールアウトします。 prediction.quantile予測的スケーリングのために使用される過去のメトリック予測のパーセンタイル。 prediction.scaleUpForward予測されるトラフィックスパイクの発生時刻より何秒前にスケールアップを実行するか。 scaleStrategyobserverを設定すると、AHPA はスケール決定を強制せずに観察およびレポートを行います。instanceBoundscron 式を使用した時間ベースの最小/最大レプリカ数のオーバーライド。 apiVersion: autoscaling.alibabacloud.com/v1beta1 kind: AdvancedHorizontalPodAutoscaler metadata: name: customer-deployment namespace: default spec: metrics: - external: metric: name: requests_per_second # アダプター構成内の name.as と一致する必要があります selector: matchLabels: namespace: default service: sample-app target: type: AverageValue averageValue: 10 # Pod あたりの平均 RPS が 10 を超えるとスケールアウトします type: External minReplicas: 0 maxReplicas: 50 prediction: quantile: 95 # 予測的スケーリングに 95 パーセンタイルの予測を使用します scaleUpForward: 180 # 予測される需要の急増の 180 秒前に事前スケールアップします scaleStrategy: observer scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: sample-app instanceBounds: - startTime: "2023-08-01 00:00:00" endTime: "2033-08-01 00:00:00" bounds: - cron: "* 0-8 ? * MON-FRI" maxReplicas: 50 minReplicas: 4 - cron: "* 9-15 ? * MON-FRI" maxReplicas: 50 minReplicas: 5 - cron: "* 16-23 ? * MON-FRI" maxReplicas: 50 minReplicas: 1AHPA が正しくスケーリングしていることを確認します。
kubectl get ahpa期待される出力:
NAME STRATEGY REFERENCE METRIC TARGETS DESIREDPODS REPLICAS MINPODS MAXPODS AGE customer-deployment observer Deployment/sample-app requests_per_second 60000m/10 6 1 1 50 7h53mKubernetes は精度向上のため、メトリック値をミリ単位(m)で表現します。この例では、
60000mは 60 RPS に相当します。しきい値が 10 のため、AHPA はDESIREDPODSを 6(60 ÷ 10)と計算します。
AHPA スケーリングのトラブルシューティング
AHPA が想定通りにスケーリングしない場合は、ステータスの条件を確認します。
kubectl describe ahpa customer-deployment出力の Conditions セクションを確認します。主なフィールドは以下のとおりです。
| フィールド | 確認事項 |
|---|---|
AbleToScale | AHPA がスケール決定を発行できるかどうか。値が False の場合、コントローラーまたは権限に関する問題が発生しています。 |
ScalingActive | AHPA がメトリックを正常に取得できたかどうか。False の場合、通常は External Metrics API がデータを返していないことを意味します。 |
ScalingLimited | minReplicas、maxReplicas、または instanceBounds によって現在のレプリカ数が制限されているかどうか。 |
ScalingActive が False の場合、ステップ 2 の検証コマンドを再実行し、メトリックが利用可能であることを確認します。
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/default/requests_per_second"次のステップ
observerモードからアクティブな自動スケーリングに移行するには、scaleStrategyをスケーリング戦略に変更し、observerの設定を削除します。異なるメトリックにこのパターンを適用するには、アダプター構成内の
seriesQueryおよびname.asを更新し、AHPA リソース内のmetrics[].external.metric.nameをそれらと一致するように更新します。