kuernetes – 自定义指标HPA,实现PHP-FPM弹性伸缩

HPA通过监控POD的CPU和MEM使用率,实现了默认的弹性伸缩功能。

然而,在实际环境中,伸缩的判断依据通常不单单是CPU/MEM,还可能是:

  • POD的线程使用率
  • POD的QPS
  • POD的带宽

无法一一列举。

HPA支持我们扩展自定义指标,只要我们让prometheus采集到POD的这些指标,那么HPA就可以通过一定的机制查询prometheus来得到这些指标值,进而做出伸缩依据。

HPA基础指标架构

HPA版本要求

为了最终使用自定义指标,需要使用如下版本的HPA:

HPA工作原理

HPA实现在kube-controller-manager中,是一个控制器。

该控制器周期性扫描所有配置的HPA对象,每个HPA对象关联到1个Deployment,进而关联到N个POD。

控制器将获取这些POD的CPU和MEM资源使用量,求这些POD的平均值,然后做出是否伸缩的决策。

问题来了,HPA是从哪里取到POD的CPU和MEM使用率的呢?

我们也知道,通过下面的命令同样可以查看POD的资源使用量:

其实top命令和HPA都采用了同一种方法来获取CPU/MEM指标,下面是调用流程:

metrics-server是一个开源项目,它采集集群所有kubelet中的容器CPU/MEM指标数据,保存到内存里。

当HPA调用apiserver的特定URL时,apiserver转发请求给metrics-server得到应答,也就是我们上面kubectl top看到的数据了。

我们完全可以直接请求apiserver的特定URL,方法如下:

这个命令调用apiserver,获取abtest11这个namespace下面所有pod的cpu/mem指标,将得到metrics-server的JSON应答。

这个转发关系是通过配置apiservice资源类型实现的:

也就是说,apiserver收到/apis/metrics.k8s.io/v1beta1/前缀的调用,就会转发流量给metrics-server这个service。

当然,metrics-server是需要我们自己部署配置的,具体方法大家去github主页参考即可。

HPA自定义指标架构

其实呢,HPA Controller逻辑上已经预埋了自定义指标的扩展能力,自定义指标的获取与上述基础指标的获取,原理上是一模一样的。

HPA控制器会通过调用apiserver的另外一个URL前缀,经过代理后调用到k8s-prometheus-adaptor服务,该服务会从prometheus采集到自定义指标,并转换成JSON格式作为返回。

可见,

  • 基础指标:metrics-server采集kubelet
  • 自定义指标:k8e-prometheus-adaptor采集prometheus

因为我们有大量指标存储在prometheus中,因此有了k8s-prometheus-adaptor的加持,我们就可以把他们利用到HPA中。

k8s-prometheus-adaptor架构

在了解这个开源项目的过程中,我发现最难理解的还是它的工作原理,所以我还是阅读了一下它的代码。

该程序由”定时拉取”和”实时查询”两部分组成,既然有一个实时查询prometheus指标的功能,为什么还要定时拉取?拉取什么?这是我在接触该项目过程中最大的困惑,直接影响到我们对其规则配置的理解。

要解释这个问题,很难离开实际的配置例子,所以我们直接进入本篇博客的主题,根据PHP-FPM进程使用率的HPA。(PHP是依靠启动多个PHP-FPM进程来实现并发的,如果POD里面的FPM进程使用率太高的话,我们认为应该扩容)

明确指标计算

给HPA自定义指标叫做fpm_active_rate,代表1个POD的FPM进程使用率。

在prometheus中并没有fpm_active_rate这个东西,只有2类原始数据:

pm_status是prometheus采集的原始序列数据。

标签state分为”active processes”和”total processes”,分别代表活跃进程数和总进程数。

标签namespace和pod_name则标识了所归属的POD。

因此,每个POD的fpm_active_rate的计算思路就是用active除以total即可。

配置文件

现在,我们必须看一下配置文件了:

adapter支持配置多条规则,为了搞定fpm_active_rate指标,我只需要一个rule。

定时拉取

adapter会定时执行seriesQuery,这是一个promql。

它过滤出最新采集到的所有pm_status,并且还需要满足state是active processes的,这是干啥呢?

假设prom中只有这两条记录:

那么,上述语句将得到结果:

然后adapter根据resources.overwrites配置,从这条记录中进行提取+映射,得到如下信息:

  • namespace标签的abtest11就是POD所属的namespace
  • pod_name标签的abtest-bgm-smzdm-com-b56679fdf-2fhlv就是POD的name。

同时,adapter根据name.as配置,将pm_status名字改为fpm_active_rate,也就是HPA自定义指标的名字。

此后,adapter在内存中记录一个这样的映射关系:

fpm_active_rate, abtest11, abtest-bgm-smzdm-com-b56679fdf-2fhlv  —->  rule

也就是这个POD到这条配置规则的关系。

可见,定时任务的目的就是『发现』: 发现所有的POD,记录它们与所属rule之间的关系。

实时查询

之所以要定时构建上述索引关系,其目的是为了满足实时查询。

你必须付费加入我的知识星球,为有效知识付费是对作者最好的回报。

二维码见下方 或者 右侧边栏。

发表评论

电子邮件地址不会被公开。