默认HPA只支持基于CPU和内存的自动伸缩,并不能满足日常的运维需求。阿里云Prometheus监控全面对接开源Prometheus生态,支持类型丰富的组件监控,提供多种开箱即用的预置监控大盘,且提供全面托管的Prometheus服务。本文介绍如何将阿里云Prometheus指标转换成HPA可用的指标,从而为应用提供更加便捷的扩缩机制。

前提条件

在将阿里云Prometheus指标转换成HPA可用的指标前,您需要部署相关组件。

  1. 部署阿里云Prometheus监控组件。具体操作,请参见开启阿里云Prometheus监控
  2. 部署alibaba-cloud-metrics-adapter组件。具体操作,请参见部署alibaba-cloud-metrics-adapter组件

示例

本文举例如何配置alibaba-cloud-metrics-adapter,实现将阿里云Prometheus指标转换为HPA可用指标,并实现该指标自动伸缩。

  1. 部署工作负载。
    1. 登录容器服务管理控制台,在左侧导航栏选择集群
    2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 无状态
    3. 无状态页面,单击使用YAML创建资源
    4. 创建页面,部署以下YAML文件创建一个名为sample-app的应用及对应的Service,然后单击创建
      说明 此容器暴露出http_requests_total的指标用来标识访问次数。
      以下为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
  2. 添加ServiceMonitor。
    1. 登录ARMS控制台
    2. 在左侧导航栏选择Prometheus监控 > Prometheus实例列表
    3. Prometheus监控页面左上角选择容器服务K8s集群所在的地域,然后单击目标实例名称进入对应实例页面。
    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. 修改alibaba-cloud-metrics-adapter配置。
    1. 登录容器服务管理控制台,在左侧导航栏选择集群
    2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择应用 > Helm
    3. Helm页面的发布名称列,找到alibaba-cloud-metrics-adapter,并单击右侧的更新
    4. 将下面的YAML文件内容复制,然后粘贴并覆盖模板中对应的参数。注意修改下面说明中的三个参数,单击更新
      说明
      • AlibabaCloudMetricsAdapter. prometheus.adapter.rules.custom字段内容修改为下面示例YAML中对应的内容。
      • AlibabaCloudMetricsAdapter. prometheus.url:填写阿里云Prometheus监控的地址。 如何获取Prometheus数据请求URL,请参见如何获取Prometheus数据请求URL
      • AlibabaCloudMetricsAdapter. prometheus.adapter.rules.default修改为false
      • 有关ack-alibaba-cloud-adapter配置文件详细说明,请参见ack-alibaba-cloud-adapter配置文件详解
      以下为部分YAML文件内容,请展开查看。
        ......
        prometheus:
          adapter:
            rules:
              custom:
              # 添加新的转换规则,请确保阿里云Prometheus中指标标签和此处一致,如果不一致,请参见阿里云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>>)
              default: false
          enabled: true    # 这里设置为true,打开Prometheus adapter。
          ......
  5. 部署HPA。

    当前版本已支持Prometheus Metrics同时透出Custom Metrics与External Metrics,您可以根据需求选择两种不同方式通过HPA进行容器伸缩。

    • 方式一:通过Custom Metrics进行容器伸缩
      1. 执行以下命令,通过Custom Metrics指标查询方式,查看HPA可用指标详情。
        kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests_per_second" | jq .
        以下为指标查询结果,请展开查看。
        {
          "kind": "MetricValueList",
          "apiVersion": "custom.metrics.k8s.io/v1beta1",
          "metadata": {
            "selfLink": "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/%2A/http_requests_per_second"
          },
          "items": [
            {
              "describedObject": {
                "kind": "Pod",
                "namespace": "default",
                "name": "sample-app-579bc6774c-rmjfd",
                "apiVersion": "/v1"
              },
              "metricName": "http_requests_per_second",
              "timestamp": "2022-01-28T08:42:58Z",
              "value": "33m",
              "selector": null
            }
          ]
        }
      2. 使用以下YAML文件部署HPA,然后执行kubectl apply -f hpa.yaml创建HPA应用。
        以下为YAML文件内容,请展开查看。
        kind: HorizontalPodAutoscaler
        apiVersion: autoscaling/v2beta1
        metadata:
          name: sample-app
        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/http_requests。
              metricName: http_requests_per_second
         # AverageValue类型的目标值,Pods指标类型下只支持AverageValue类型的目标值。
              targetAverageValue: 500m       #当出现了小数点,K8s又需要高精度时,会使用单位m或k。例如1001m=1.001,1k=1000。
      3. 在Service中开启负载均衡后,执行压测验证。
        1. 执行以下命令进行压测实验。
          ab -c 50 -n 2000 LoadBalancer(sample-app):8080/
        2. 执行以下命令查看HPA详情。
          kubectl get hpa sample-app
          预期输出:
          NAME         REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
          sample-app   Deployment/sample-app   33m/500m   1         10        1          7m
    • 方式二:通过External Metrics进行容器伸缩
      1. 执行以下命令,通过External Metrics指标查询方式,查看HPA可用指标详情。
        kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/default/http_requests_per_second" | jq .
        以下为指标查询结果,请展开查看。
        {
          "kind": "ExternalMetricValueList",
          "apiVersion": "external.metrics.k8s.io/v1beta1",
          "metadata": {},
          "items": [
            {
              "metricName": "http_requests_per_second",
              "metricLabels": {},
              "timestamp": "2022-01-28T08:40:20Z",
              "value": "33m"
            }
          ]
        }
      2. 使用以下YAML文件部署HPA,然后执行kubectl apply -f hpa.yaml创建HPA应用。
        以下为YAML文件内容,请展开查看。
        apiVersion: autoscaling/v2beta2
        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
      3. 在Service中开启负载均衡后,执行压测验证。
        1. 执行以下命令进行压测实验。
          ab -c 50 -n 2000 LoadBalancer(sample-app):8080/
        2. 执行以下命令查看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请求的数据做聚合操作。
  • resources:是PromQL里的数据Label,与resource进行匹配,这里的resouce是指集群内的api-resource,比如Pod、Namespace和Node。可通过kubectl api-resources -o wide查看。此处Key对应Prometheus数据中的LabelName,请确认Prometheus指标数据中有此LabelName。
  • name:是指根据正则匹配把Prometheus指标名转为比较可读的指标名,这里是把http_request_total转为http_request_per_second
  • Discovery
    指定待转换的Prometheus指标,您可以通过seriesFilters精确过滤指标。seriesQuery可以根据标签进行查找(示例代码如下)。
    seriesQuery: http_requests_total{namespace!="",pod!=""}
    seriesFilters:
        - isNot: "^container_.*_seconds_total"
    说明 seriesFilters为非必填项,用来过滤指标:
    • is:<regex>,匹配包含该正则表达式的指标。
    • isNot:<regex>,匹配不包含该正则表达式的指标。
  • Association
    设置Prometheus指标标签与Kubernetes中的资源映射关系。http_requests_total指标的标签包括namespace!=""pod!=""
    - seriesQuery: http_requests_total{namespace!="",pod!=""}
      resources:
        overrides:
          namespace: {resource: "namespace"}
          pod: {resource: "pod"}
  • 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"
  • 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. 登录ARMS控制台
  2. 在左侧导航栏选择Prometheus监控 > Prometheus实例列表
  3. Prometheus监控页面左上角选择容器服务K8s集群所在的地域,然后单击目标实例名称进入对应实例页面。
  4. 在左侧导航栏单击设置,然后单击设置页签。
  5. 设置页签下获取HTTP API地址(Grafana读取地址)。
    推荐使用内网,如无法使用内网时,可使用公网。grafana读取地址

开源Prometheus监控场景

  1. 部署Prometheus监控方案。
    1. 登录容器服务管理控制台,在左侧导航栏选择市场 > 应用市场
    2. 应用市场页面单击应用目录页签,搜索并单击ack-prometheus-operator
    3. ack-prometheus-operator页面,单击一键部署
    4. 创建面板中,选择集群和命名空间,然后单击下一步
    5. 参数配置页面,设置相应参数,然后单击确定
      查看部署结果:
      1. 执行以下命令,将集群中的Prometheus映射到本地9090端口。
        kubectl port-forward svc/ack-prometheus-operator-prometheus 9090:9090 -n monitoring
      2. 在浏览器中访问localhost:9090,即可查看Prometheus。
      3. 选择菜单栏Status > Targets,查看所有采集任务。采集任务如果所有任务的状态为UP,表示所有采集任务均已正常运行。Targets
  2. 查看Labels中对应的servicenamespce
    以ServiceName是ack-prometheus-operator-prometheus,ServiceNamespace是monitoring为例说明该开源Prometheus数据请求的URL:
    http://ack-prometheus-operator-prometheus.monitoring.svc.cluster.local:9090