水平 Pod 自動調度資源 (HPA)

本文說明如何為 Google Cloud Managed Service for Prometheus 啟用水平 Pod 自動調度資源功能 (HPA)。您可以執行下列任一操作來啟用 HPA:

疑難排解一節所述,由於 Stackdriver 轉接器和 Prometheus 轉接器的資源定義重疊,因此無法在同一個叢集中同時使用這兩種轉接器。建議您只選擇一個 HPA 解決方案。

使用 KEDA

KEDA (Kubernetes 事件驅動型自動調度資源) 是最近發布的使用 Prometheus 指標的自動調度資源,並且已成為 Prometheus 社群中偏好的解決方案。

如要開始使用,請參閱 KEDA 說明文件,瞭解如何整合 Google Cloud Managed Service for Prometheus。

使用自訂指標 Stackdriver 轉接器

自訂指標 Stackdriver 轉接器支援從 Prometheus 的 Managed Service 查詢指標,從轉接器的 0.13.1 版開始。

如要使用自訂指標 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. 如果您使用 GKE 適用的工作負載身分聯盟,則必須將「監控檢視者」角色授予在該轉接器下執行的服務帳戶。如果您尚未在 Kubernetes 叢集中啟用 Workload Identity Federation for GKE,請略過這個步驟。

    export PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format 'get(projectNumber)')
    gcloud projects add-iam-policy-binding projects/PROJECT_ID \
      --role roles/monitoring.viewer \
      --member=principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/custom-metrics/sa/custom-metrics-stackdriver-adapter
    
  5. 將下列設定放入名為 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
    
  6. 部署新的 PodMonitoring 資源:

    kubectl -n default apply -f podmonitoring.yaml
    

    在幾分鐘內,Managed Service for Prometheus 會處理從匯出工具擷取的指標,並使用長名稱將這些指標儲存在 Cloud Monitoring 中。Prometheus 指標會採用下列慣例儲存:

    • 前置字串 prometheus.googleapis.com
    • 這個字尾通常是 gaugecountersummaryhistogram,但未指定類型的指標可能會使用 unknownunknown:counter 字尾。如要確認後置字串,請使用 Metrics Explorer 在 Cloud Monitoring 中查詢指標。
  7. 更新已部署的 HPA,以便從 Cloud Monitoring 查詢指標。指標 foo 會以 prometheus.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|gaugespec 部分應如下所示:

      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 數量增加至 maxReplicas (5) 欄位的值,嘗試將所有 Pod 的指標平均值降至 20

    HPA 查詢的範圍僅限於安裝 HPA 資源的命名空間和叢集,因此其他叢集和命名空間中的相同指標不會影響自動調整大小功能。

  8. 如要觀察工作負載調度資源,請執行下列指令:

    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          *
    
  9. 如要縮減部署作業,請更新目標指標值,使其高於匯出的指標值。在這個範例中,部署作業會將 prometheus.googleapis.com/foo/gauge 指標的值設為 40。如果您將目標值設為大於 40 的數字,則部署作業會縮減。

    舉例來說,您可以使用 kubectl edit 將 HPA 設定中 pods.target.averageValue 欄位的值從 20 變更為 100

    kubectl edit hpa custom-metric-prometheus-sd
    

    修改規格部分,使其符合下列內容:

    spec:
      maxReplicas: 5
      metrics:
      - pods:
          metric:
            name: prometheus.googleapis.com|foo|gauge
          target:
            averageValue: "100"
            type: AverageValue
      type: Pods
      minReplicas: 1
    
  10. 如要查看工作負載縮減情形,請執行下列指令:

    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          *
    
  11. 如要清理已部署的範例,請執行下列指令:

    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 轉接程式設定,即可用於自動調度資源。與使用上游 Prometheus 進行調整相比,設定 Prometheus 轉接程式以使用 Managed Service for Prometheus 進行調整時,有兩項額外的限制:

  • 查詢必須經過 Prometheus 前端 UI Proxy,就像使用 Prometheus API 或 UI 查詢 Managed Service for Prometheus 一樣。針對 Prometheus 轉接程式,您需要編輯 prometheus-adapter 部署,以便變更 prometheus-url 值,如下所示:

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

    其中 NAMESPACE_NAME 是前端部署的命名空間。

  • 您無法在規則設定的 .seriesQuery 欄位中,對指標名稱使用規則運算式比對工具。而是必須完整指定指標名稱。

相較於上游 Prometheus,Managed Service for Prometheus 可能需要稍長一點的時間才能提供資料,因此如果設定過度急切的自動調度資源邏輯,可能會導致不必要的行為。雖然無法保證資料的最新性,但資料通常會在傳送至 Managed Service for Prometheus 後 3 到 7 秒內可供查詢,不含任何網路延遲時間。

Prometheus-adapter 發出的所有查詢都屬於全域範圍。也就是說,如果您在兩個命名空間中都有應用程式,且這些應用程式會傳送名稱相同的指標,則使用該指標的 HPA 設定會使用兩個應用程式的資料進行調整。建議您在 PromQL 中一律使用 namespacecluster 篩選器,避免使用錯誤資料進行調整。

如要使用 Prometheus 轉接程式和受管理的收集資料設定範例 HPA 設定,請按照下列步驟操作:

  1. 在叢集中設定代管集合
  2. 在叢集中部署 Prometheus 前端 UI 代理程式。如果您使用 Workload Identity Federation for GKE,也必須設定及授權服務帳戶
  3. 在 prometheus-engine 存放區的 examples/hpa/ 目錄中部署資訊清單
    • example-app.yaml:發出指標的部署和服務範例。
    • pod-monitoring.yaml:用於設定擷取範例指標的資源。
    • hpa.yaml:設定工作負載資源配置的 HPA 資源。
  4. 請確認叢集中已安裝 prometheus-adapter。方法是將範例安裝資訊清單部署至叢集。這份資訊清單的設定如下:

    • 查詢在 default 命名空間中部署的前端 Proxy
    • 發出 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. 觀察水平 Pod 自動配置器:
      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 轉接器,可能會因為名稱衝突而擲回 FailedGetObjectMetric 等錯誤。如要解決這個問題,您可能需要刪除自訂指標轉接器先前註冊的 v1beta1.external.metrics.k8s.iov1beta1.custom.metrics.k8s.iov1beta2.custom.metrics.k8s.io apiservices。

疑難排解提示:

  • 部分 Cloud Monitoring 系統指標 (例如 Pub/Sub 指標) 會延遲 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 代理程式正常運作時,第二個終端機中的回應會類似以下內容:

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

    如果您收到 403 錯誤,表示前端 UI Proxy 未正確設定。如要瞭解如何解決 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
    
  • 如要確認水平 Pod 自動配置器是否正常運作,請執行下列指令:

    $ 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": []
    }