全部產品
Search
文件中心

Container Service for Kubernetes:基於阿里雲Prometheus指標的容器水平伸縮

更新時間:Sep 12, 2024

HPA預設支援基於CPU和記憶體指標實現自動調整,可能無法滿足更為複雜的營運情境。如果您需要將Prometheus收集的Custom Metrics與External Metrics轉換為HPA可用的Auto Scaling指標,您可以參見本文擷取監控資料並實現對應的伸縮配置,為應用提供更靈活、便捷的擴縮機制。

前提條件

功能介紹

預設HPA只支援基於CPU和記憶體的自動調整,並不能滿足日常的營運需求。阿里雲Prometheus監控全面對接開源Prometheus生態,支援類型豐富的組件監控,提供多種開箱即用的預置監控大盤,且提供全面託管的Prometheus服務。此功能主要分為三個步驟:

  1. 在ACK叢集中使用Prometheus監控透出監控指標。

  2. 依託alibaba-cloud-metrics-adapter組件,負責轉換Prometheus監控指標為HPA可消費的Kubernetes彙總指標。更多資訊,請參見Autoscaling on multiple metrics and custom metrics

  3. 配置並部署HPA,根據上一步的指標進行彈性擴縮。

    指標類型根據情境分為兩種:

下文介紹如何配置alibaba-cloud-metrics-adapter,實現將阿里雲Prometheus指標轉換為HPA可用指標,並實現該指標自動調整。

步驟一:擷取Prometheus監控資料

樣本一:使用ACK預設容器監控指標

您可以直接使用ACK預設安裝的阿里雲Prometheus中的預設指標進行HPA彈性擴縮。支援的指標包括容器監控cAdvisor指標、節點基礎監控Node-Exporter、GPU-Exporter指標,以及您當前已接入到阿里雲Prometheus中的所有指標。查看已接入阿里雲Prometheus的指標的步驟如下:

  1. 登入Container Service管理主控台,在左側導覽列選擇叢集

  2. 叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇營運管理 > Prometheus 監控

  3. 單擊右上方跳轉到Prometheus服務

  4. 在Prometheus監控服務控制台的左側導覽列,單擊設定,查看所有已接入阿里雲Prometheus的指標。

樣本二:通過Pod自身上報的Prometheus指標進行HPA擴縮

部署測試應用,並通過Prometheus標準方式暴露指標。更多資訊,請參見metric_type。下文介紹如何部署sample-app應用,並自身透出http_requests_total的指標用來標識訪問次數。

  1. 部署應用的工作負載。

    1. 登入Container Service管理主控台,在左側導覽列選擇叢集

    2. 叢集列表頁面,單擊目的地組群名稱,在左側導覽列,單擊工作負載 > 無狀態

    3. 無狀態頁面右側,單擊使用YAML建立資源,然後在建立頁面,樣本模板選擇自訂,配置以下YAML,單擊建立

      展開查看YAML詳細資料

      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: luxas/autoscale-demo:v0.1.2
              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
      說明

      此容器暴露出http_requests_total的指標用來標識訪問次數。

  2. 添加ServiceMonitor。

    1. 登入ARMS控制台

    2. 在左側導覽列選擇Prometheus監控 > 執行個體列表

    3. 在頁面左上方選擇Container ServiceK8s叢集所在的地區,然後單擊與叢集同名的執行個體名稱。

    4. 在左側導覽列單擊服務發現,然後單擊配置頁簽。

    5. 配置頁簽下單擊ServiceMonitor

    6. ServiceMonitor頁簽下單擊添加ServiceMonitor建立ServiceMonitor,然後單擊確定

      apiVersion: monitoring.coreos.com/v1
      kind: ServiceMonitor
      metadata:
        name: sample-app
        namespace: default
      spec:
        endpoints:
        - interval: 30s
          port: http
          path: /metrics
        namespaceSelector:
          any: true
        selector:
          matchLabels:
            app: sample-app
  3. 確認監控狀態。

    服務發現頁面,單擊Targets頁簽,如果看到default/sample-app/0(1/1 up),則說明您已成功在阿里雲Prometheus監控到了部署的應用。

  4. 通過在Prometheus大盤中,查詢最近時間範圍的http_requests_total數值,確定監控資料已經正確擷取。

步驟二:修改alibaba-cloud-metrics-adapter組件配置

  1. 登入Container Service管理主控台,在左側導覽列選擇叢集

  2. 叢集列表頁面,單擊目的地組群名稱,在左側導覽列,單擊應用 > Helm

  3. Helm頁面的操作列,單擊ack-alibaba-cloud-metrics-adapter對應的更新

  4. 更新發布面板,配置如下YAML,然後單擊確定

    展開查看YAML詳細資料

      AlibabaCloudMetricsAdapter:
      ......
        prometheus:
          enabled: true    # 這裡設定為true,開啟整體Prometheus adapter功能。
          # 填寫阿里雲Prometheus監控的地址。
          url: https://cn-beijing.arms.aliyuncs.com:9443/api/v1/prometheus/xxxx/xxxx/xxxx/cn-beijing
        	# 阿里雲Prometheus開啟鑒權Token後,請配置prometheusHeader Authorization。
          prometheusHeader:
          - Authorization: xxxxxxx
          	
          metricsRelistInterval: 1m # 重新擷取指標列表的時間周期,推薦保持預設1min。
        	logLevel: 5								# 組件調試記錄層級,推薦保持預設。
        
          adapter:
            rules:
              default: false  			# 預設指標擷取配置,推薦保持false。
              custom:
              
              # 樣本1:this is an example of custom metric config.
              # this config will convert prometheus metric: container_memory_working_set_bytes to a custom metric container_memory_working_set_bytes_per_second
              # and cpu metric container_cpu_usage_seconds_total convert to container_cpu_usage_core_per_second
              # you can run command to check the memory/cpu value:
              # kubectl get --raw  "/apis/custom.metrics.k8s.io/v1beta1/namespaces/kube-system/pods/*/container_memory_working_set_bytes_per_second"
              # kubectl get --raw  "/apis/custom.metrics.k8s.io/v1beta1/namespaces/kube-system/pods/*/container_cpu_usage_core_per_second"
              # refer to doc: https://help.aliyun.com/document_detail/184519.html
      
              - seriesQuery: 'container_memory_working_set_bytes{namespace!="",pod!=""}'
                resources:
                  overrides:
                    namespace: { resource: "namespace" }
                    pod: { resource: "pod" }
                name:
                  matches: "^(.*)_bytes"
                  as: "${1}_bytes_per_second"
                metricsQuery: 'sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)' # metricsQuery配置中的labelSelector不會繼承series_Query的過濾標籤。
              - seriesQuery: 'container_cpu_usage_seconds_total{namespace!="",pod!=""}'
                resources:
                  overrides:
                    namespace: { resource: "namespace" }
                    pod: { resource: "pod" }
                name:
                  matches: "^(.*)_seconds_total"
                  as: "${1}_core_per_second"
                metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)'  # metricsQuery配置中的labelSelector不會繼承series_Query的過濾標籤。
      
              # 樣本2:this is an example of external metric config.
              
              # refer to doc: https://help.aliyun.com/document_detail/608768.html
      
              # 添加新的轉換規則,請確保阿里雲Prometheus中指標標籤和此處一致,如果不一致,請參見ARMS Prometheus中指標標籤修改。
              
              #- seriesQuery: http_requests_total{namespace!="",pod!=""}
              #  resources:
              #    overrides:
              #      # 此處resource為Kubernetes的API Resource,可通過kubectl api-resources -o wide查看。
              #      # 此處key對應Prometheus資料中的LabelName,請確認Prometheus指標資料中有此LabelName。
              #      namespace: {resource: "namespace"}
              #      pod: {resource: "pod"}
              #  name:
              #    matches: ^(.*)_total
              #   as: ${1}_per_second
              #  metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)
      
      
              # this is an example of external metric config.
              
              # refer to doc: https://help.aliyun.com/document_detail/608768.html
      
              #- seriesQuery: arms_app_requests_count
              #  metricsQuery: sum by (rpc) (sum_over_time(<<.Series>>{rpc="/demo/queryUser/{id}",service="arms-demo:arms-k8s-demo",prpc="__all__",ppid="__all__",endpoint="__all__",destId="__all__",<<.LabelMatchers>>}[1m]))
              #  name:
              #    as: ${1}_per_second_queryuser
              #    matches: ^(.*)_count
              #  resources:
              #    namespaced: false
      
      
              # this is an example of custom metric from user define prometheus metric: http_requests_total
              # refer to doc: https://help.aliyun.com/document_detail/184519.html
      
              #- seriesQuery: 'http_requests_total{namespace!="",pod!=""}'
              #  resources:
              #    overrides:
              #      namespace: {resource: "namespace"}
              #      pod: {resource: "pod"}
              #  name:
              #    matches: "^(.*)_total"
              #    as: "${1}_per_second"
              #  metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)'
              # - seriesQuery: '{__name__=~"^some_metric_count$"}'
              #   resources:
              #     template: <<.Resource>>
              #   name:
              #     matches: ""
              #     as: "my_custom_metric"
              #   metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)
      
        ......

    部分欄位說明如下。關於ack-alibaba-cloud-adapter設定檔的詳細說明,請參見ack-alibaba-cloud-adapter設定檔詳解

    欄位

    說明

    AlibabaCloudMetricsAdapter. prometheus.adapter.rules.custom

    該欄位內容請修改為樣本YAML中對應的內容。

    alibabaCloudMetricsAdapter. prometheus.url

    填寫阿里雲Prometheus監控的地址。關於如何擷取Prometheus資料請求URL,請參見如何擷取Prometheus資料請求URL

    AlibabaCloudMetricsAdapter. prometheus.prometheusHeader[].Authorization

    填寫Token。關於如何擷取Token,請參見如何擷取Prometheus資料請求URL

    AlibabaCloudMetricsAdapter. prometheus.adapter.rules.default

    預設建立預置指標,推薦關閉,配置為false

配置Metrics-adapter組件參數,並成功部署Metrics-adapter組件後,可通過如下命令查看K8s彙總API是否已經成功接入資料。

  1. 通過Custom Metrics進行容器伸縮。

    1. 執行以下命令,通過Custom Metrics指標查詢方式,查看HPA可用指標的詳情和列表。

      kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq .
    2. 執行以下命令,查詢http_requests_per_second指標在default命名空間下的當前數值。

      # 通過查詢container_memory_working_set_bytes_per_second查看kube-system namespace中Pod的工作記憶體當前每秒大小。
      kubectl get --raw  "/apis/custom.metrics.k8s.io/v1beta1/namespaces/kube-system/pods/*/container_memory_working_set_bytes_per_second"
      
      # 通過查詢container_cpu_usage_core_per_second查看kube-system namespace中Pod的CPU使用核心數每秒大小。
      kubectl get --raw  "/apis/custom.metrics.k8s.io/v1beta1/namespaces/kube-system/pods/*/container_cpu_usage_core_per_second"

      指標查詢結果樣本:

      {
        "kind": "MetricValueList",
        "apiVersion": "custom.metrics.k8s.io/v1beta1",
        "metadata": {
          "selfLink": "/apis/custom.metrics.k8s.io/v1beta1/namespaces/kube-system/pods/%2A/container_memory_working_set_bytes_per_second"
        },
        "items": [
          {
            "describedObject": {
              "kind": "Pod",
              "namespace": "kube-system",
              "name": "ack-alibaba-cloud-metrics-adapter-7cf8dcb845-h****",
              "apiVersion": "/v1"
            },
            "metricName": "container_memory_working_set_bytes_per_second",
            "timestamp": "2023-08-09T06:30:19Z",
            "value": "24576k",
            "selector": null
          }
        ]
      }
  2. 通過External Metrics進行容器伸縮。

    1. 執行以下命令,通過External Metrics指標查詢方式,查看HPA可用的External指標詳情和列表。

      kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/" | jq .
    2. 執行以下命令,查詢http_requests_per_second指標在default命名空間下的當前數值。

      kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/default/http_requests_per_second"

      樣本輸出:

      {
        "kind": "ExternalMetricValueList",
        "apiVersion": "external.metrics.k8s.io/v1beta1",
        "metadata": {},
        "items": [
          {
            "metricName": "http_requests_per_second",
            "metricLabels": {},
            "timestamp": "2022-01-28T08:40:20Z",
            "value": "33m"
          }
        ]
      }
      

步驟三:配置並部署HPA,根據獲得的指標進行彈性擴縮

部署HPA

目前的版本已支援Prometheus Metrics同時透出Custom Metrics與External Metrics。您可以根據需求任選以下方式通過HPA進行容器伸縮。

類型

說明

Custom Metric

根據與要進行擴縮的Kubernetes目標對象(例如Pod)相關的指標進行擴縮,例如Pod自身維度指標。更多資訊,請參見autoscaling-on-multiple-metrics-and-custom-metrics

External Metric

根據與要進行擴縮的Kubernetes目標對象(例如Pod)不相關的指標進行擴縮,例如通過整體的業務QPS指標來擴縮某一個Workload的Pod。更多資訊,請參見autoscaling-on-metrics-not-related-to-kubernetes-objects

通過Custom Metrics進行容器伸縮

  1. 使用以下內容,建立hpa.yaml檔案。

    kind: HorizontalPodAutoscaler
    apiVersion: autoscaling/v2
    metadata:
      name: sample-app-memory-high
    spec:
    # HPA的伸縮對象描述,HPA會動態修改該對象的Pod數量。
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: sample-app
    # HPA的最小Pod數量和最大Pod數量。
      minReplicas: 1
      maxReplicas: 10
    # 監控的指標數組,支援多種類型的指標共存。
      metrics:
      - type: Pods
        pods:
          # 使用指標:pods/container_memory_working_set_bytes_per_second。
          metric: 
            name: container_memory_working_set_bytes_per_second
     # AverageValue類型的目標值,Pods指標類型下只支援AverageValue類型的目標值。
          target:
            type: AverageValue
            averageValue: 1024000m       # 此處1024000m代表1 KB記憶體閾值,當前指標單位為byte/per second,m為K8s轉換精度單位,當出現了小數點,K8s又需要高精度時,會使用單位m或k。例如1001m=1.001,1k=1000。
    
  2. 執行以下命令,建立HPA應用。

    kubectl apply -f hpa.yaml
  3. 執行以下命令,查看HPA是否生效。

    kubectl get hpa sample-app-memory-high

    預期輸出:

    NAME                     REFERENCE               TARGETS           MINPODS   MAXPODS   REPLICAS   AGE
    sample-app-memory-high   Deployment/sample-app   24576k/1024000m   3         10        1          7m

通過External Metrics進行容器伸縮

  1. 使用以下內容,建立hpa.yaml檔案。

    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: sample-app
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: sample-app
      minReplicas: 1
      maxReplicas: 10
      metrics:
        - type: External
          external:
            metric:
              name: http_requests_per_second
              selector:
                matchLabels:
                  job: "sample-app"
    # External指標類型下只支援Value和AverageValue類型的目標值。
            target:
              type: AverageValue
              averageValue: 500m
  2. 執行以下命令,建立HPA應用。

    kubectl apply -f hpa.yaml
  3. 在Service中開啟負載平衡後,執行以下命令,進行壓測實驗。

    ab -c 50 -n 2000 LoadBalancer(sample-app):8080/
  4. 執行以下命令,查看HPA詳情。

    kubectl get hpa sample-app

    預期輸出:

    NAME         REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
    sample-app   Deployment/sample-app   33m/500m   1         10        1          7m

ack-alibaba-cloud-adapter設定檔詳解

ack-alibaba-cloud-adapter通過以下步驟將Prometheus中的指標轉換成HPA可用的指標:

  1. Discovery:ack-alibaba-cloud-adapter會從Prometheus發現可用的指標。

  2. Association:將指標與Kubernetes資源(Pod、Node、Namespace)相關聯。

  3. Naming:定義轉換後的HPA可用指標名稱。

  4. Querying:定義查詢Prometheus語句。

以上文中sample-app容器中暴露出來的http_requests_total指標轉換成HPA中的http_requests_per_second為例,完整的ack-alibaba-cloud-adapter設定檔如下。

- seriesQuery: http_requests_total{namespace!="",pod!=""}
  resources:
    overrides:
      namespace: {resource: "namespace"}
      pod: {resource: "pod"}
  name:
    matches: ^(.*)_total
    as: ${1}_per_second
  metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)

欄位

說明

seriesQuery

PromQL請求資料。

metricsQuery

對seriesQuery中PromQL請求的資料做彙總操作。

說明

metricsQuery配置中的labelSelector不會繼承series_Query的過濾標籤。

resources

是PromQL裡的資料Label,與resource進行匹配。此處的resource是指叢集內的api-resource,例如Pod、Namespace和Node。您可以通過kubectl api-resources -o wide命令查看。此處Key對應Prometheus資料中的LabelName,請確認Prometheus指標資料中有此LabelName。

name

指根據正則匹配把Prometheus指標名轉為比較可讀的指標名,此處將http_requests_total轉為http_requests_per_second

  1. Discovery

    指定待轉換的Prometheus指標,您可以通過seriesFilters精確過濾指標。seriesQuery可以根據標籤進行尋找,範例程式碼如下。

    seriesQuery: http_requests_total{namespace!="",pod!=""}
    seriesFilters:
        - isNot: "^container_.*_seconds_total"

    seriesFilters為非必填項,用於過濾指標:

    • is:<regex>:匹配包含該Regex的指標。

    • isNot:<regex>:匹配不包含該Regex的指標。

  2. Association

    設定Prometheus指標標籤與Kubernetes中的資源地圖關係。http_requests_total指標的標籤包括namespace!=""pod!=""

    - seriesQuery: http_requests_total{namespace!="",pod!=""}
      resources:
        overrides:
          namespace: {resource: "namespace"}
          pod: {resource: "pod"}
  3. Naming

    用於將Prometheus指標名稱轉換成HPA的指標名稱,但不會改變Prometheus本身的指標名稱。如果使用Prometheus原來的指標,可以不設定。

    您可以通過執行命令kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1"查看HPA可用的所有指標。

    - seriesQuery: http_requests_total{namespace!="",pod!=""}
      resources:
        overrides:
          namespace: {resource: "namespace"}
          pod: {resource: "pod"}
      name:
        matches: "^(.*)_total"
        as: "${1}_per_second"
  4. Querying

    查詢Prometheus API的模板。ack-alibaba-cloud-adapter會根據HPA中的參數,填充參數到此模板中,然後發送給Prometheus API請求,並將獲得的值最終提供給HPA進行彈性擴縮。

    - seriesQuery: http_requests_total{namespace!="",pod!=""}
      resources:
        overrides:
          namespace: {resource: "namespace"}
          pod: {resource: "pod"}
      name:
        matches: ^(.*)_total
        as: ${1}_per_second
      metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)

如何擷取Prometheus資料請求URL

情境一:阿里雲Prometheus監控

  1. 登入Container Service管理主控台,在左側導覽列選擇叢集

  2. 叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇營運管理 > Prometheus 監控

  3. 單擊右上方跳轉到Prometheus服務

  4. 在Prometheus監控服務控制台的左側導覽列,單擊設定,然後單擊設定頁簽,擷取HTTP API地址(Grafana 讀取地址)

    推薦使用內網,如無法使用內網時,可使用公網。

    3.png

情境二:開源Prometheus監控

針對開源自建Prometheus方案,您需要通過Service暴露Prometheus的標準訪問API,然後將其配置在metrics-adapter組件的Prometheus資料來源URL參數中,即可完成基於開源Prometheus資料的HPA資料來源配置。

下文以ACK應用市場提供的ack-prometheus-operator社區版應用Helm Chart為例。更多資訊,請參見開源Prometheus監控

  1. 部署Prometheus監控方案,並暴露標準Prometheus API。

    • 登入Container Service管理主控台,在左側導覽列選擇市場 > 應用市場

    • 應用市場頁面,搜尋並單擊ack-prometheus-operator,然後在頁面右側,單擊一鍵部署

    • 在建立頁面,選擇叢集命名空間,按需修改發布名稱,然後單擊下一步,按需修改參數,然後單擊確定

    • 查看部署結果。

      1. 通過Service暴露Prometheus的標準API,當前以ack-prometheus-operator的Service:ack-prometheus-operator-prometheus為例。

      2. 在瀏覽器中訪問ServiceIP:9090,如需為Service開通公網訪問SLB,查看Prometheus控制台。

      3. 在頁面上方功能表列,單擊Status > Targets,查看所有採集任務。image.png

        如果所有任務的狀態為UP,表示所有採集任務均已正常運行。

        image.png

    • 查看Labels中對應的servicenamespace

      本樣本以ServiceName為ack-prometheus-operator-prometheus,ServiceNamespace為monitoring為例說明該開源Prometheus資料請求的URL。

      http://ack-prometheus-operator-prometheus.monitoring.svc.cluster.local:9090
  2. 配置組件的Prometheus資料來源URL參數中,以確保組件與Prometheus之間的通訊正常。

    如果選擇通過公網訪問Prometheus的標準API,可參見以下樣本進行配置。

      AlibabaCloudMetricsAdapter:
      ......
        prometheus:
          enabled: true
          url: http://your_domain.com:9090   # 請將your_domain.com替換為您的公網IP

    以ack-prometheus-operator方案為例,此時url值為http://ack-prometheus-operator-prometheus.monitoring.svc.cluster.local:9090

相關文檔