
# 基于Prometheus指标的弹性伸缩实践
Kubernetes默认的HPA策略只支持基于CPU和内存的自动伸缩，在复杂的业务场景中，仅使用CPU和内存使用率指标进行弹性伸缩往往无法满足日常运维需求。为此，CCE提供云原生监控插件（kube-prometheus-stack），可全面对接开源Prometheus生态，支持类型丰富的组件监控，并提供了多种开箱即用的预置监控大盘。本文介绍如何将华为云Prometheus指标转换成HPA可用的指标，从而为应用提供更加便捷的扩缩机制。
#### 工作原理
CCE全面对接开源Prometheus生态，支持类型丰富的自定义指标监控，同时支持使用自定义指标实现弹性伸缩，原理如下图所示：
图1使用自定义指标的HPA策略示意图   
![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000002625369495.png "点击放大")
利用自定义指标实现HPA弹性伸缩的核心流程如下：
1. **指标暴露**：业务应用需要在代码里预置指标上报能力，将关键指标（如队列长度、在线用户数、每秒请求量）暴露出来。
2. **指标采集**：如果应用无法直接暴露指标，可以部署一个专用的Exporter组件，它负责从应用中抓取数据，并转换成Prometheus能识别的格式。
3. **指标存储**：Prometheus定期从Exporter或应用直接拉取指标，并进行存储，形成历史数据，供后续查询和分析。
4. **指标转换**：通过配置文件（user-adapter-config）定义"PromQL查询语句"与"Kubernetes自定义指标API名称"之间的映射关系。
5. **API接入**：在API Server中注册自定义指标API，使得HPA可以像查询CPU指标一样，通过统一的API接口查询到自定义指标。
6. **执行伸缩**：HPA定期查询自定义指标的值，计算工作负载的期望副本数量并执行扩缩容。
 
#### 前提条件
- 已创建一个集群。
- 已通过kubectl连接集群，详情请参见[通过kubectl连接集群](https://support.huaweicloud.com/usermanual-cce/cce_10_0107.html)。
 
#### 步骤一：安装云原生监控插件
1. 登录[CCE控制台](https://console.huaweicloud.com/cce2.0/?#/cce/cluster/list)，单击集群名称进入集群，单击左侧导航栏的"插件中心"。
2. 在"插件中心"页面右侧找到**云原生监控插件** ，单击"安装"。
   
   建议您关注以下配置，其他配置可按需进行设置。详情请参见[云原生监控插件](https://support.huaweicloud.com/usermanual-cce/cce_10_0406.html)。
   - 本地数据存储：使用本地存储监控数据，监控数据可选择是否上报至AOM或三方监控平台。
   
   - 自定义指标采集：该配置在本实践中必须选择开启，否则将无法采集自定义指标。
    
   
   
3. 插件配置完成后，单击"安装"。
 
#### 步骤二：获取Prometheus监控数据
本文中通过与Pod相关的指标进行HPA扩缩，例如Pod自身维度的指标。您也可以通过与Pod不相关的指标进行HPA扩缩，例如外部ELB指标，请参见[基于ELB监控指标的弹性伸缩实践](https://support.huaweicloud.com/bestpractice-cce/cce_bestpractice_00283.html)。
下文介绍如何部署sample-app应用，并通过Prometheus标准方式暴露container_memory_working_set_bytes_per_second的指标用来标识容器内存工作集每秒字节。关于Prometheus指标的更多信息，请参见[metric_type](https://prometheus.io/docs/concepts/metric_types/)。
1. 部署测试应用。 
   1. 创建sample-app.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: swr.cn-east-3.myhuaweicloud.com/container/autoscale-demo:v0.1.2 #示例镜像
              name: metrics-provider 
              resources:
                requests:
                  cpu: 250m
                  memory: 512Mi
                limits:
                  cpu: 250m
                  memory: 512Mi
              ports:
              - name: http
                containerPort: 8080   #容器暴露的端口
            imagePullSecrets:
              - name: default-secret
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: sample-app
        namespace: default
        labels: 
          app: sample-app
      spec:
        ports: 
          - port: 80
            name: http
            protocol: TCP
            targetPort: 8080
        selector:
          app: sample-app 
        type: ClusterIP
      ```
      ![](https://support.huaweicloud.com/bestpractice-cce/public_sys-resources/note_3.0-zh-cn.png)
      该应用将暴露指标container_memory_working_set_bytes_per_second，用于查看容器每秒的工作内存大小。
      
   
   2. 创建工作负载。
      ```
      kubectl apply -f sample-app.yaml
      ```
      
   
   
   
   
2. 创建ServiceMonitor监控自定义指标。 
   1. 创建servicemonitor.yaml文件，内容如下：
      ```
      apiVersion: monitoring.coreos.com/v1 
      kind: ServiceMonitor
      metadata:
        name: sample-app  # ServiceMonitor名称
        namespace: default
      spec:
        endpoints:        # 定义要监控的服务的端点，包括名称、端口、路径、协议等信息
        - interval: 30s   # 表示Prometheus Operator将每30秒检查一次服务是否需要添加到监控目标列表中
          port: http
          path: /metrics
        namespaceSelector:
          any: true
        selector: 
          matchLabels:
            app: sample-app  #需要采集数据的对象标签
      ```
      
   
   2. 创建ServiceMonitor。
      ```
      kubectl apply -f servicemonitor.yaml
      ```
      
   
   
   
   
 
#### 步骤三：修改配置文件
1. 修改Prometheus的adapter-config配置项，通过修改adapter-config中rules字段将Prometheus暴露出的指标转换为HPA可关联的指标。 
   ```
   kubectl -n monitoring edit configmap user-adapter-config
   ```
   
   
2. 在rules字段下添加自定义指标采集规则。如果您需要增加多个采集规则，可在rules字段下添加多个配置，关于采集规则配置详情请参见[Metrics Discovery and Presentation Configuration](https://github.com/kubernetes-sigs/prometheus-adapter/blob/master/docs/config.md)。
   
   自定义采集规则示例如下：
   ```
   rules:
   - seriesQuery: container_memory_working_set_bytes{namespace!="",pod!=""}
     resources:
       overrides:
         namespace: 
           resource: namespace
         pod: 
   resource: pod
     name:
       matches: ^(.*)_bytes
       as: ${1}_bytes_per_second #此处${1}取值为matches:"^(.*)_bytes"中^(.*)匹配到的值
     metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)
   ```
   - seriesQuery：PromQL请求数据（用户需要查询的指标，可根据实际情况填写）。
   
   - metricsQuery：对seriesQuery中PromQL请求的数据进行聚合操作。
   
   - resources：是PromQL里的数据Label，与resource进行匹配。此处的resource是指集群内的api-resource，例如Pod、Namespace和Node。您可以通过kubectl api-resources -o wide命令查看。此处Key对应Prometheus数据中的LabelName，请确认Prometheus指标数据中有此LabelName。
   
   - name：指根据正则匹配把Prometheus指标名转为比较可读的指标名，此处将container_memory_working_set_bytes转为container_memory_working_set_bytes_per_second。
   
   
   
   
3. 重新部署monitoring命名空间下的custom-metrics-apiserver工作负载。 
   ```
   kubectl -nmonitoring delete pod -l app=custom-metrics-apiserver
   ```
   
   
4. 执行命令查看指标是否添加成功。 
   ```
   kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/container_memory_working_set_bytes_per_second
   ```
   ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001850905038.png "点击放大")
   
   
 
#### 步骤四：创建HPA策略
1. 使用自定义指标创建HPA策略。 
   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:
            metric: 
              name: container_memory_working_set_bytes_per_second   # 使用自定义容器指标
            target:
              type: AverageValue  # AverageValue类型的目标值，Pods指标类型下只支持AverageValue类型的目标值
              averageValue: 1024000m   # 此处1024000m代表1KB
      ```
      
   
   2. 创建HPA策略。
      ```
      kubectl apply -f hpa.yaml
      ```
      
   
   
   
   
2. 查看HPA策略是否生效。 
   ```
   kubectl get hpa sample-app-memory-high
   ```
   ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001851063754.png "点击放大")
   可见副本数已由初始1扩容至10。
   
   
 
#### 相关文档
- 如果该应用使用ELB对外提供访问，您可以根据ELB的监控指标（如QPS）进行弹性伸缩，详情请参见[基于ELB监控指标的弹性伸缩实践](https://support.huaweicloud.com/bestpractice-cce/cce_bestpractice_00283.html)。
- 如果该应用使用Nginx Ingress实现流量路由转发，您可以根据Nginx Ingress监控指标进行弹性伸缩，详情请参见[通过Nginx Ingress对多个应用进行弹性伸缩](https://support.huaweicloud.com/bestpractice-cce/cce_bestpractice_10038.html)。
 
