水平 Pod 自動スケーリング(HPA)

このドキュメントでは、Google Cloud Managed Service for Prometheus 用に水平 Pod 自動スケーリング(HPA)を有効にする方法について説明します。HPA を有効にするには、次のいずれかを行います。

いずれかの方法を選択する必要があります。トラブルシューティングで説明されているように、リソース定義が重複しているため、両方を使用することはできません。

カスタム指標 Stackdriver アダプタを使用する

v0.13.1 のアダプタから、カスタム指標 Stackdriver アダプタは Managed Service for Prometheus からの指標のクエリをサポートしています。

カスタム指標 Stackdriver アダプタを使用してサンプルの HPA 構成を設定するには、次の操作を行います。

  1. クラスタのマネージド コレクションを設定します。
  2. カスタム指標 Stackdriver アダプタをクラスタにインストールします。

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml
    
  3. Prometheus 指標のエクスポータと HPA リソースをデプロイします。

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/examples/prometheus-to-sd/custom-metrics-prometheus-sd.yaml
    

    このコマンドは、指標 foo と HPA リソースを出力するエクスポータ アプリケーションをデプロイします。HPA は、このアプリケーションを 5 つのレプリカにスケーリングして、指標 foo のターゲット値を達成します。

  4. podmonitoring.yaml という名前のファイルに次の構成を記述して、PodMonitoring リソースを定義します。

    apiVersion: monitoring.googleapis.com/v1
    kind: PodMonitoring
    metadata:
      name: prom-example
    spec:
      selector:
        matchLabels:
          run: custom-metric-prometheus-sd
      endpoints:
      - port: 8080
        interval: 30s
    
  5. 新しい PodMonitoring リソースをデプロイします。

    kubectl -n default apply -f podmonitoring.yaml
    

    数分以内に、Managed Service for Prometheus はエクスポータからスクレイピングされた指標を処理し、長い形式の名前で Cloud Monitoring に保存します。Prometheus の指標は次の規則で保存されます。

    • prometheus.googleapis.com 接頭辞。
    • 通常、この接尾辞は gaugecountersummaryhistogram のいずれかですが、型なしの指標の場合、unknown または unknown:counter という接尾辞が含まれることがあります。接尾辞を確認するには、Metrics Explorer を使用して Cloud Monitoring で指標を検索します。
  6. デプロイされた HPA を更新して、Cloud Monitoring から指標をクエリします。指標 fooprometheus.googleapis.com/foo/gauge として取り込まれます。デプロイされた HorizontalPodAutoscaler リソースで指標をクエリできるようにするため、デプロイされた HPA で長い形式の名前を使用しますが、すべてのスラッシュ(/)をパイプ文字(|)に置き換える必要があります(prometheus.googleapis.com|foo|gauge)。詳細については、カスタム指標 Stackdriver アダプタ リポジトリの Stackdriver で使用可能な指標をご覧ください。

    1. 次のコマンドを実行して、デプロイされた HPA を更新します。

      kubectl edit hpa custom-metric-prometheus-sd
      
    2. pods.metric.name フィールドの値を foo から prometheus.googleapis.com|foo|gauge に変更します。spec セクションは次の例のようになります。

      spec:
         maxReplicas: 5
         metrics:
         - pods:
             metric:
               name: prometheus.googleapis.com|foo|gauge
             target:
               averageValue: "20"
               type: AverageValue
           type: Pods
         minReplicas: 1
      

    この例の HPA 構成では、指標 prometheus.googleapis.com/foo/gauge の平均値は 20 になります。Deployment は指標の値が 40 に設定されているため、HPA コントローラは Pod の数を maxReplicas5)フィールドの値まで増やし、すべての Pod の指標の平均値を 20 に減らそうと試行します。

    HPA クエリのスコープは、HPA リソースがインストールされている Namespace とクラスタであるため、他のクラスタと Namespace の同じ指標は自動スケーリングに影響しません。

  7. ワークロードがスケールアップされたことを確認するには、次のコマンドを実行します。

    kubectl get hpa custom-metric-prometheus-sd --watch
    

    REPLICAS フィールドの値が 1 から 5 に変わります。

    NAME                          REFERENCE                                TARGETS        MINPODS   MAXPODS   REPLICAS   AGE
    custom-metric-prometheus-sd   Deployment/custom-metric-prometheus-sd   40/20          1         5         5          *
    
  8. Deployment をスケールダウンするには、エクスポートした指標値よりもターゲット指標の値を大きくします。この例では、Deployment の prometheus.googleapis.com/foo/gauge 指標の値が 40 に設定されます。ターゲット値を 40 より大きい値に設定すると、Deployment はスケールダウンされます。

    たとえば、kubectl edit を使用して、HPA 構成の pods.target.averageValue フィールドの値を 20 から 100 に変更します。

    kubectl edit hpa custom-metric-prometheus-sd
    

    spec セクションを次のように変更します。

    spec:
      maxReplicas: 5
      metrics:
      - pods:
          metric:
            name: prometheus.googleapis.com|foo|gauge
          target:
            averageValue: "100"
            type: AverageValue
      type: Pods
      minReplicas: 1
    
  9. 次のコマンドを実行して、ワークロードのスケールダウンを監視します。

    kubectl get hpa custom-metric-prometheus-sd --watch
    

    REPLICAS フィールドの値が 5 から 1 に変わります。設計上、これは Pod 数をスケールアップする場合よりも遅くなります。

    NAME                          REFERENCE                                TARGETS        MINPODS   MAXPODS   REPLICAS   AGE
    custom-metric-prometheus-sd   Deployment/custom-metric-prometheus-sd   40/100          1         5         1          *
    
  10. デプロイされたサンプルをクリーンアップするには、次のコマンドを実行します。

    kubectl delete -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml
    kubectl delete -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/examples/prometheus-to-sd/custom-metrics-prometheus-sd.yaml
    kubectl delete podmonitoring/prom-example
    

詳細については、カスタム指標 Stackdriver アダプタ リポジトリの Prometheus の例またはアプリケーションのスケーリングをご覧ください。

Prometheus アダプタを使用する

既存の prometheus-adapter 構成ファイルは、いくつかの変更を行うだけで自動スケーリングに使用できます。Managed Service for Prometheus を使用してスケーリングするように prometheus-adapter を構成する場合は、アップストリーム Prometheus を使用してスケーリングする場合と比較して、2 つの制限が加わります。

  • Prometheus API または UI を使用して Managed Service for Prometheus のクエリを実行する場合と同様に、クエリは Prometheus フロントエンド UI プロキシ経由でルーティングされる必要があります。Prometheus アダプタの場合は、prometheus-adapter デプロイを編集して、prometheus-url 値を次のように変更する必要があります。

    --prometheus-url=http://frontend.NAMESPACE_NAME.svc:9090/
    

    ここで、NAMESPACE_NAME はフロントエンドがデプロイされている Namespace です。

  • ルール構成ファイルの .seriesQuery フィールドの指標名に正規表現マッチャーは使用できません。代わりに、完全な指標名を指定する必要があります。

アップストリームの Prometheus と比較して Managed Service for Prometheus ではデータが利用可能になるまでに少し時間がかかる場合があります。過剰な自動スケーリング ロジックを構成すると、望ましくない動作が発生する可能性があります。データの鮮度は保証されませんが、通常はネットワーク レイテンシを除いて Managed Service for Prometheus に送信した 3~7 秒後にデータはクエリの実行に使用できます。

prometheus-adapter によって発行されるすべてのクエリは、グローバル スコープです。つまり、同じ名前の指標を出力する 2 つの名前空間にアプリケーションがある場合、その指標を使用する HPA 構成は両方のアプリケーションのデータを使用してスケーリングされます。間違ったデータを使用してスケーリングしないように、PromQL では常に namespace または cluster フィルタを使用することをおすすめします。

prometheus-adapter とマネージド コレクションを使用して HPA 構成の例を設定するには、次の手順を行います。

  1. クラスタのマネージド コレクションを設定します。
  2. クラスタに Prometheus フロントエンド UI プロキシをデプロイします。Workload Identity を使用する場合は、サービス アカウントの構成と認可も行う必要があります。
  3. prometheus-engine リポジトリ内の examples/hpa/ ディレクトリにマニフェストをデプロイします。
    • example-app.yaml: 指標を出力するデプロイとサービスの例。
    • pod-monitoring.yaml: サンプル指標のスクレイピングを構成するリソース。
    • hpa.yaml: ワークロードのスケーリングを構成する HPA リソース。
  4. クラスタに prometheus-adapter がインストールされていることを確認します。これを行うには、サンプルのインストール マニフェストをクラスタにデプロイします。このマニフェストは次のように構成されています。

    • default Namespace にデプロイされたフロントエンド プロキシをクエリします。
    • PromQL を発行して、サンプル デプロイから http_requests_per_second 指標を計算して返します。
  5. それぞれ個別のターミナル セッションで、以下のコマンドを実行します。

    1. prometheus-example-app サービスに対する HTTP の負荷を生成します。
      kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://prometheus-example-app; done"
    2. HorizontalPodAutoscaler を確認します。
      kubectl get hpa prometheus-example-app --watch
    3. ワークロードのスケールアップを確認します。
      kubectl get po -lapp.kubernetes.io/name=prometheus-example-app --watch
  6. Ctrl+C を使用して HTTP 負荷の生成を停止し、ワークロードのスケールダウンを確認します。

トラブルシューティング

カスタム指標 Stackdriver アダプタでは、Prometheus アダプタと同じ名前のリソース定義(prometheus-adapter)を使用します。この名前の重複のため、同じクラスタ内で複数のアダプタを実行すると、エラーが発生します

以前に「カスタム指標 Stackdriver アダプタ」がインストールされているクラスタに Prometheus Adapter をインストールすると、名前の競合により、FailedGetObjectMetric などのエラーがスローされる場合があります。この問題を解決するには、以前にカスタム指標アダプタによって登録された v1beta1.external.metrics.k8s.iov1beta1.custom.metrics.k8s.iov1beta2.custom.metrics.k8s.io の各 API サービスの削除が必要になる場合があります。

トラブルシューティングのヒント:

  • Pub/Sub 指標など、一部の Cloud Monitoring システム指標は 60 秒以上遅延します。Prometheus アダプタは現在のタイムスタンプを使用してクエリを実行するため、Prometheus アダプタを使用してこれらの指標をクエリすると、データが返されないことがあります。遅延した指標をクエリするには、PromQL の offset 修飾子を使用して、クエリの時間オフセットを変更して必要な時間を設定します。

  • フロントエンド UI プロキシが想定どおりに動作し、権限に問題がないことを確認するには、ターミナルで次のコマンドを実行します。

    kubectl -n NAMESPACE_NAME port-forward svc/frontend 9090
    

    次に、別のターミナルを開いて次のコマンドを実行します。

    curl --silent 'localhost:9090/api/v1/series?match%5B%5D=up'
    

    フロントエンド UI プロキシが正常に機能している場合、2 番目のターミナルでのレスポンスは次のようになります。

    curl --silent 'localhost:9090/api/v1/series?match%5B%5D=up' | jq .
    {
      "status": "success",
      "data": [
         ...
      ]
    }
    

    403 エラーが発生した場合は、フロントエンド UI プロキシが正しく構成されていません。403 エラーを解決する方法については、サービス アカウントの構成と認可ガイドをご覧ください。

  • カスタム指標の apiserver が使用可能であることを確認するには、次のコマンドを実行します。

    kubectl get apiservices.apiregistration.k8s.io v1beta1.custom.metrics.k8s.io
    

    apiserver が使用可能な場合、レスポンスは次のようになります。

    $ kubectl get apiservices.apiregistration.k8s.io v1beta1.custom.metrics.k8s.io
    NAME                            SERVICE                         AVAILABLE   AGE
    v1beta1.custom.metrics.k8s.io   monitoring/prometheus-adapter   True        33m
    
  • HPA が意図したとおりに機能していることを確認するには、次のコマンドを実行します。

    $ kubectl describe hpa prometheus-example-app
    Name:                                  prometheus-example-app
    Namespace:                             default
    Labels:                                
    Annotations:                           
    Reference:                             Deployment/prometheus-example-app
    Metrics:                               ( current / target )
    "http_requests_per_second" on pods:  11500m / 10
    Min replicas:                          1
    Max replicas:                          10
    Deployment pods:                       2 current / 2 desired
    Conditions:
    Type            Status  Reason              Message
    ----            ------  ------              -------
    AbleToScale     True    ReadyForNewScale    recommended size matches current size
    ScalingActive   True    ValidMetricFound    the HPA was able to successfully calculate a replica count from pods metric http_requests_per_second
    ScalingLimited  False   DesiredWithinRange  the desired count is within the acceptable range
    Events:
    Type     Reason               Age                   From                       Message
    ----     ------               ----                  ----                       -------
    Normal   SuccessfulRescale    47s                   horizontal-pod-autoscaler  New size: 2; reason: pods metric http_requests_per_second above target
    

    レスポンスに FailedGetPodsMetric などのステートメントが含まれている場合、HPA は失敗しています。HPA が失敗した場合の describe 呼び出しのレスポンスを以下に示します。

    $ kubectl describe hpa prometheus-example-app
    Name:                                  prometheus-example-app
    Namespace:                             default
    Reference:                             Deployment/prometheus-example-app
    Metrics:                               ( current / target )
      "http_requests_per_second" on pods:   / 10
    Min replicas:                          1
    Max replicas:                          10
    Deployment pods:                       1 current / 1 desired
    Conditions:
      Type            Status  Reason               Message
      ----            ------  ------               -------
      AbleToScale     True    ReadyForNewScale     recommended size matches current size
      ScalingActive   False   FailedGetPodsMetric  the HPA was unable to compute the replica count: unable to get metric http_requests_per_second: unable to fetch metrics from custom metrics API: the server could not find the metric http_requests_per_second for pods
      ScalingLimited  False   DesiredWithinRange   the desired count is within the acceptable range
    Events:
      Type     Reason               Age                   From                       Message
      ----     ------               ----                  ----                       -------
      Warning  FailedGetPodsMetric  104s (x11 over 16m)   horizontal-pod-autoscaler  unable to get metric http_requests_per_second: unable to fetch metrics from custom metrics API: the server could not find the metric http_requests_per_second for pods
    

    HPA が失敗した場合は、load-generator で指標を生成していることを確認します。カスタム指標 API は、次のコマンドで直接確認できます。

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

    正常な場合の出力は次のようになります。

    $ kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq .
      {
      "kind": "APIResourceList",
      "apiVersion": "v1",
      "groupVersion": "custom.metrics.k8s.io/v1beta1",
      "resources": [
         {
            "name": "namespaces/http_requests_per_second",
            "singularName": "",
            "namespaced": false,
            "kind": "MetricValueList",
            "verbs": [
            "get"
            ]
         },
         {
            "name": "pods/http_requests_per_second",
            "singularName": "",
            "namespaced": true,
            "kind": "MetricValueList",
            "verbs": [
            "get"
            ]
         }
      ]
      }
    

    指標がない場合、出力の "resources" の下にデータはありません。次に例を示します。

    kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq .
    {
    "kind": "APIResourceList",
    "apiVersion": "v1",
    "groupVersion": "custom.metrics.k8s.io/v1beta1",
    "resources": []
    }