基于ELB监控指标弹性伸缩
应用现状
在使用HPA+CA实现工作负载和节点联动弹性伸缩中,介绍了基于CPU/内存等资源使用率来进行弹性伸缩。
基于CPU/内存使用率有一个问题,就是资源使用率数据反映是滞后的,不能及时反映应用实际需求,根据资源使用率进行扩缩容对一些需要快速弹性扩缩容的业务(比如抢购、社交媒体)来说就来不及了,会导致业务问题。
解决方案
本文介绍一种基于ELB监控指标的弹性伸缩方法,相比CPU/内存使用率进行弹性伸缩,基于ELB的QPS数据弹性伸缩更有针对性,更加及时。
本方案的关键点是获取ELB的指标数据并上报到Prometheus,再将Prometheus中的数据转换成HPA能够识别的metric数据,然后HPA根据metric数据进行弹性伸缩。
基于ELB监控指标的弹性伸缩具体实施方案如下所示:
- 开发一个Prometheus exporter,获取ELB的指标,并转化成Prometheus需要的格式,上报到Prometheus。
- 将Prometheus的数据转换成kubernetes metric api提供给HPA controller使用。
- 设置HPA规则,使用ELB的监控数据作为弹性伸缩指标。


本文介绍的方法不限于ELB指标,其他指标可按照类似方法操作。
前提条件
- 需要您熟悉Prometheus,并能够编写代码开发Prometheus exporter。
- 需要在集群中安装Prometheus、Metrics Server插件。
开发exporter
Prometheus通过周期性的调用exporter的“/metrics”接口获取指标信息,应用只需要通过“/metrics”上报监控数据即可。Prometheus提供了各种语言的客户端,在应用中集成Prometheus客户端可以方便的实现“/metrics”接口,客户端具体请参见Prometheus CLIENT LIBRARIES,开发Exporter具体方法请参见WRITING EXPORTERS。
监控数据需要Prometheus的格式提供,每条数据提供ELB ID、监听器ID、Service所在的命名空间、Service名称以及Service的uid作为标签,如下所示。
获取上述数据的方法如下所示。
- 使用列出Service接口查询当前所有Service。
Service的返回信息中annotations字段可以查出Service关联的ELB。
- kubernetes.io/elb.id
- kubernetes.io/elb.class
- 根据上一步查询到ELB实例ID,使用查询监听器接口查询监听器ID。
- 获取ELB监控数据。
ELB的调用CES批量查询监控数据接口,查询ELB的监控数据,ELB详细的监控数据指标请参见ELB监控指标说明。例如如下几种参数
- m1_cps:并发连接数
- m5_in_pps:流入数据包数
- m6_out_pps:流出数据包数
- m7_in_Bps:网络流入速率
- m8_out_Bps:网络流出速率
- 按Prometheus的格式汇聚数据,并通过“/metrics”接口开放出去。
部署exporter
Prometheus可以动态监测,一般来说给Pod打上Prometheus知名的annotations,Prometheus会自动采集该Pod的监控信息。
有如下prometheus知名的annotations。
- prometheus.io/scrape: true的话该pod会作为监控目标
- prometheus.io/path: 采集的url,默认为/metrics
- prometheus.io/port: 采集endpoint的端口号
- prometheus.io/scheme: 默认http,如果为了安全设置了https,此处需要改为https
通常打上prometheus.io/scrape这个annotations就可以了,这样Prometheus就会从“/metrics”采集Pod的的监控信息。
apiVersion: extensions/v1
kind: Deployment
metadata:
labels:
app: exporter
name: exporter
namespace: default
spec:
template:
metadata:
annotations:
prometheus.io/scrape: "true"
creationTimestamp: null
labels:
app: exporter
spec:
...
转换Prometheus数据
Prometheus收集到监控数据后,需要将Prometheus的数据转换成kubernetes metric api提供给HPA controller使用,这样HPA controller就能根据监控数据进行弹性伸缩。
开源社区有提供了一个Prometheus adapter插件可以将Prometheus的数据转换成kubernetes metric api,仓库地址是https://github.com/DirectXMan12/k8s-prometheus-adapter,您可以根据adapter文档自行安装。
这里最关键的是要了解Prometheus adapter的配置,这些配置决定了哪些prometheus的数据要暴露,怎么暴露。
adapter的规则中都包含了4个部分,
- 发现需要暴露的指标的规则
- 这些指标和kubernetes资源的的关联关系。
- 指标在custom api中暴露的名字,可以不使用prometheus中指标名称对外暴露
- 怎么在prometheus查询值。
示例如下。
- metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>) resources: overrides: namespace: resource: namespace service_name: resource: service seriesQuery: '{app="exporter"}'
这里把刚才exporter的数据和service关联起来,从指标的service_name这个label可以获取对应服务的名称。
创建HPA弹性伸缩规则
exporter上报到Prometheus的数据,经过Prometheus adapter监控数据转换成kubernetes metric api后,就可以创建HPA规则实现弹性伸缩。
创HPA规则示例如下,使用ELB的入流量来作为扩容的标准,当m7_in_Bps(网络流入速率)的值超过10k时,会触发名为nginx的Deployment弹性伸缩。
apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: nginx namespace: default spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx minReplicas: 1 maxReplicas: 10 metrics: - type: Object object: describedObject: kind: Service name: nginx target: type: Value value: 10k metric: name: m7_in_Bps
创建完后,可以对负载进行压测(也就是通过ELB访问Pod),然后HPA controller会根据设置的值计算是否需要扩容。
