共计 9193 个字符,预计需要花费 23 分钟才能阅读完成。
本篇内容介绍了“监控自定义指标的 HPA 怎么部署”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
HPA 简介
HPA(Horizontal Pod Autoscaler)是 kubernetes(以下简称 k8s)的一种资源对象,能够根据某些指标对在 statefulSet、replicaController、replicaSet 等集合中的 pod 数量进行动态伸缩,使运行在上面的服务对指标的变化有一定的自适应能力。
HPA 目前支持四种类型的指标,分别是 Resource、Object、External、Pods。其中在稳定版本 autoscaling/v1 中只支持对 CPU 指标的动态伸缩,在测试版本 autoscaling/v2beta2 中支持 memory 和自定义指标的动态伸缩,并以 annotation 的方式工作在 autoscaling/v1 版本中。HPA 在 k8s 中的结构
首先可以看一下 HPA 在 k8s 中的结构,这里找了一个 k8s 官方给出的 HPA 例子,我在关键字段上给出一些注释方便理解。
- type: Pods
pods:
metric:
name: packets-per-second
# AverageValue 类型的目标值,Pods 指标类型下只支持 AverageValue 类型的目标值
target:
type: AverageValue
averageValue: 1k
# External 类型的指标
- type: External
external:
metric:
name: queue_messages_ready
# 该字段与第三方的指标标签相关联,(此处官方文档有问题,正确的写法如下) selector:
matchLabels:
env: stage
app: myapp
# External 指标类型下只支持 Value 和 AverageValue 类型的目标值
target:
type: AverageValue
averageValue: 30
autoscaling/v1 版本将 metrics 字段放在了 annotation 中进行处理。
target 共有 3 种类型:Utilization、Value、AverageValue。Utilization 表示平均使用率;Value 表示裸值;AverageValue 表示平均值。
metrics 中的 type 字段有四种类型的值:Object、Pods、Resource、External。
Resource 指的是当前伸缩对象下的 pod 的 cpu 和 memory 指标,只支持 Utilization 和 AverageValue 类型的目标值。
Object 指的是指定 k8s 内部对象的指标,数据需要第三方 adapter 提供,只支持 Value 和 AverageValue 类型的目标值。
Pods 指的是伸缩对象(statefulSet、replicaController、replicaSet)底下的 Pods 的指标,数据需要第三方的 adapter 提供,并且只允许 AverageValue 类型的目标值。
External 指的是 k8s 外部的指标,数据同样需要第三方的 adapter 提供,只支持 Value 和 AverageValue 类型的目标值。
HPA 动态伸缩的原理
HPA 在 k8s 中也由一个 controller 控制,controller 会间隔循环 HPA,检查每个 HPA 中监控的指标是否触发伸缩条件,默认的间隔时间为 15s。一旦触发伸缩条件,controller 会向 k8s 发送请求,修改伸缩对象(statefulSet、replicaController、replicaSet)子对象 scale 中控制 pod 数量的字段。k8s 响应请求,修改 scale 结构体,然后会刷新一次伸缩对象的 pod 数量。伸缩对象被修改后,自然会通过 list/watch 机制增加或减少 pod 数量,达到动态伸缩的目的。
HPA 伸缩过程叙述
HPA 的伸缩主要流程如下:
1. 判断当前 pod 数量是否在 HPA 设定的 pod 数量区间中,如果不在,过小返回最小值,过大返回最大值,结束伸缩。
2. 判断指标的类型,并向 api server 发送对应的请求,拿到设定的监控指标。一般来说指标会根据预先设定的指标从以下三个 aggregated APIs 中获取:metrics.k8s.io、custom.metrics.k8s.io、 external.metrics.k8s.io。其中 metrics.k8s.io 一般由 k8s 自带的 metrics-server 来提供,主要是 cpu,memory 使用率指标,另外两种需要第三方的 adapter 来提供。custom.metrics.k8s.io 提供自定义指标数据,一般跟 k8s 集群有关,比如跟特定的 pod 相关。external.metrics.k8s.io 同样提供自定义指标数据,但一般跟 k8s 集群无关。许多知名的第三方监控平台提供了 adapter 实现了上述 api(如 prometheus),可以将监控和 adapter 一同部署在 k8s 集群中提供服务,甚至能够替换原来的 metrics-server 来提供上述三类 api 指标,达到深度定制监控数据的目的。
3. 根据获得的指标,应用相应的算法算出一个伸缩系数,并乘以目前 pod 数量获得期望 pod 数量。系数是指标的期望值与目前值的比值,如果大于 1 表示扩容,小于 1 表示缩容。指标数值有平均值(AverageValue)、平均使用率(Utilization)、裸值(Value)三种类型,每种类型的数值都有对应的算法。以下几点值得注意:如果系数有小数点,统一进一;系数如果未达到某个容忍值,HPA 认为变化太小,会忽略这次变化,容忍值默认为 0.1。
HPA 扩容算法是一个非常保守的算法。如果出现获取不到指标的情况,扩容时算最小值,缩容时算最大值;如果需要计算平均值,出现 pod 没准备好的情况,平均数的分母不计入该 pod。
一个 HPA 支持多个指标的监控,HPA 会循环获取所有的指标,并计算期望的 pod 数量,并从期望结果中获得最大的 pod 数量作为最终的伸缩的 pod 数量。一个伸缩对象在 k8s 中允许对应多个 HPA,但是只是 k8s 不会报错而已,事实上 HPA 彼此不知道自己监控的是同一个伸缩对象,在这个伸缩对象中的 pod 会被多个 HPA 无意义地来回修改 pod 数量,给系统增加消耗,如果想要指定多个监控指标,可以如上述所说,在一个 HPA 中添加多个监控指标。
4. 检查最终的 pod 数量是否在 HPA 设定的 pod 数量范围的区间,如果超过最大值或不足最小值都会修改为最大值或最小值。然后向 k8s 发出请求,修改伸缩对象的子对象 scale 的 pod 数量,结束一个 HPA 的检查,获取下一个 HPA,完成一个伸缩流程。
HPA 的应用场景
HPA 的特性结合第三方的监控应用,使得部署在 HPA 伸缩对象(statefulSet、replicaController、replicaSet)上的服务有了非常灵活的自适应能力,能够在一定限度内复制多个副本来应对某个指标的急剧飙升,也可以在某个指标较小的情况下删除副本来让出计算资源给其他更需要资源的应用使用,维持整个系统的稳定。非常适合于一些流量波动大,机器资源吃紧,服务数量多的业务场景,如:电商服务、抢票服务、金融服务等。
k8s-prometheus-adapter
前文说到,许多监控系统通过 adapter 实现了接口,给 HPA 提供指标数据。在这里我们具体介绍一下 prometheus 监控系统的 adapter。
prometheus 是一个知名开源监控系统,具有数据维度多,存储高效,使用便捷等特点。用户可以通过丰富的表达式和内置函数,定制自己所需要的监控数据。
prometheus-adapter 在 prometheus 和 api-server 中起到了适配者的作用。prometheus-adapter 接受从 HPA 中发来,通过 apiserver aggregator 中转的指标查询请求,然后根据内容发送相应的请求给 prometheus 拿到指标数据,经过处理后返回给 HPA 使用。prometheus 可以同时实现 metrics.k8s.io、custom.metrics.k8s.io、 external.metrics.k8s.io 三种 api 接口,代替 k8s 自己的 matrics-server,提供指标数据服务。
prometheus-adapter 部署能否成功的关键在于配置文件是否正确。配置文件中可以设定需要的指标以及对指标的处理方式,以下是一份简单的配置文件,加上注释以稍做解释。
# 指标规则,可以多个规则共存,上一个规则的结果会传给下一个规则
rules:
# 计算指标数据的表达式
- metricsQuery: sum(rate( .Series { .LabelMatchers}[5m])) by (.GroupBy)
# 指标重命名,支持正则表达式。这里表示删除指标名字中的 _seconds_total
name:
as:
matches: (.*)_seconds_total$
# 指标与 k8s 资源通过标签关联,这里将指标通过标签与 k8s 的 namspace 和 pod 相互关联
resources:
overrides:
namespace:
resource: namespace
pod:
resource: pod
# 过滤指标条件
seriesFilters: []
# 指标查询表达式,可以根据标签等条件,筛选特定的指标
seriesQuery: {namespace!= ,pod!=}
metricsQuery 字段会在 k8s 请求时执行,其中,“”“”是 go 的模板语法,Series 表示指标名称,LabelMatchers 表示指标与 k8s 对象名称匹配的标签键值对,GroupBy 表示指标数值归并的标签名。
不太好理解,这里截取官方文档中的一个例子来进行说明,看了就应该明白了:
For instance, suppose we had a series http_requests_total (exposed ashttp_requests_per_second in the API) with labels service, pod,ingress, namespace, and verb. The first four correspond to Kubernetes resources. Then, if someone requested the metric pods/http_request_per_second for the pods pod1 and pod2 in the somens namespace, we’d have:
- Series: http_requests_total
- LabelMatchers: pod=~\ pod1|pod2 ,namespace= somens
- GroupBy: pod
resources 字段是 k8s 资源对象与指标关联的重要字段,本质上是根据指标的标签值与 k8s 资源对象名称进行匹配,resources 字段告诉系统,应该用指标的哪个标签的标签值来匹配 k8s 资源对象名称。有两个方法关联资源,一种是通过 overrides,将特定的标签与 k8s 资源对象绑定起来,当 k8s 请求指标的时候,会将资源对象名称与这个特定的标签值进行比较,来分辨指标具体是哪个对象的;另一种是 template,通过 go 语言模板语法将 k8s 资源对象名转化成标签名,进行匹配。
第二种方法,不太好理解,同样截取官方文档中的一个例子来进行说明:
# any label `kube_ group _ resource ` becomes group . resource in Kubernetes
resources:
template: kube_ .Group _ .Resource
部署一个监控自定义指标的 HPA
1. 部署 prometheus 应用,使其正常工作。可以使用官方的 helm 包快捷部署,之后的应用也基本以 helm 包的方式部署,不再赘述。
2. 部署需要伸缩的应用。这里我选择了一个简单的 nginx 服务,部署为 deployment 作为伸缩对象。
3. 在应用的命名空间下,部署提供自定义指标的应用。这里我选择了官方的 prometheus-node-exporter,并以 nodeport 的方式暴露数据端口,作为自定义指标数据的来源。这个应用会以 daemonSet 的方式运行在 k8s 集群的每个 node 上,并对外开放在自己 node 上获取到的指标。
在 prometheus 的界面上已经可以看到 node-exporter 暴露出来的指标了
4. 部署 prometheus-adapter 应用。在 helm 包的 values 中修改其配置文件,配置文件如下
resources:
template: .Resource
seriesFilters: []
seriesQuery: {namespace!= ,pod!=}
- metricsQuery: sum(rate( .Series { .LabelMatchers}[5m])) by (.GroupBy)
name:
as:
matches: (.*)_total$
resources:
template: .Resource
seriesFilters:
- isNot: (.*)_seconds_total$
seriesQuery: {namespace!= ,pod!=}
- metricsQuery: sum(.Series { .LabelMatchers}) by (.GroupBy)
name:
as:
matches: (.*)$
resources:
template: .Resource
seriesFilters:
- isNot: (.*)_total$
seriesQuery: {namespace!= ,pod!=}
上述配置文件将 secondstotal 和_total 结尾的指标用 prometheus 的内置函数进行了速率计算,并去掉对应的后缀作为指标名称。
我们在 k8s 中利用 kubectl 查看指标是否能够获得到指标
kubectl get –raw /apis/custom.metrics.k8s.io/v1beta1/
你会看到所有的你能够获得的指标名称,但是名字和数据已经和原来的指标有所不同了,因为我们在 adapter 的配置文件中做了一定程度的修改。
然后我们获取一下 node_cpu 这个指标,看看是否能够正确地显示出来
kubectl get –raw /apis/custom.metrics.k8s.io/v1beta1/namespaces/my-nginx/pods/*/node_cpu | jq
这个命令能够显示 my-nginx 这个 namspace 下的所有 pod 的 node_cpu 指标的数据,结果如下
{
kind : MetricValueList ,
apiVersion : custom.metrics.k8s.io/v1beta1 ,
metadata : {
selfLink : /apis/custom.metrics.k8s.io/v1beta1/namespaces/my-nginx/pods/%2A/node_cpu
},
items : [
{
describedObject : {
kind : Pod ,
namespace : my-nginx ,
name : prometheus-node-exporter-b25zl ,
apiVersion : /v1
},
metricName : node_cpu ,
timestamp : 2019-10-29T03:33:47Z ,
value : 3822m
}
]
}
ok,到这里,说明所有的组件工作正常,hpa 能够顺利地得到这个指标。需要注意的是 HPA 和监控对象,伸缩对象一定要部署在同一个命名空间下,不然会获取不到相应的指标。
5. 部署 hpa,其 yaml 文件如下
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: hpa-asdfvs
namespace: my-nginx
spec:
scaleTargetRef:
apiVersion: apps/v1beta1
kind: Deployment
name: my-nginx
minReplicas: 1
maxReplicas: 10
metrics:
- type: Object
object:
metric:
name: node_cpu
describedObject:
apiVersion: v1
kind: Pod
name: prometheus-node-exporter-b25zl
target:
type: Value
value: 9805m
我们将根据 prometheus-node-exporter 这个 pod 的 node_cpu 这个指标来动态伸缩我们的 nginx 应用。
我们来获取一下这个 hpa
kubectl get horizontalPodAutoscaler -n my-nginx hpa-asdfvs -oyaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
annotations:
autoscaling.alpha.kubernetes.io/conditions: [{ type : AbleToScale , status : True , lastTransitionTime : 2019-10-29T02:54:50Z , reason : ReadyForNewScale , message : recommended
size matches current size },{ type : ScalingActive , status : True , lastTransitionTime : 2019-10-29T03:05:24Z , reason : ValidMetricFound , message : the
HPA was able to successfully calculate a replica count from Pod metric node_cpu },{ type : ScalingLimited , status : False , lastTransitionTime : 2019-10-29T02:54:50Z , reason : DesiredWithinRange , message : the
desired count is within the acceptable range }]
autoscaling.alpha.kubernetes.io/current-metrics: [{type : Object , object :{ target :{ kind : Pod , name : prometheus-node-exporter-b25zl , apiVersion : v1}, metricName : node_cpu , currentValue : 3822m }}]
autoscaling.alpha.kubernetes.io/metrics: [{type : Object , object :{ target :{ kind : Pod , name : prometheus-node-exporter-b25zl , apiVersion : v1}, metricName : node_cpu , targetValue : 9805m }}]
kubectl.kubernetes.io/last-applied-configuration: |
{apiVersion : autoscaling/v2beta2 , kind : HorizontalPodAutoscaler , metadata :{ annotations :{}, name : hpa-asdfvs , namespace : my-nginx }, spec :{maxReplicas :10, metrics :[{ object :{ describedObject :{ apiVersion : v1 , kind : Pod , name : prometheus-node-exporter-b25zl}, metric :{name : node_cpu}, target :{type : Value , value : 9805m}}, type : Object }], minReplicas :1, scaleTargetRef :{apiVersion : apps/v1beta1 , kind : Deployment , name : my-nginx}}}
creationTimestamp: 2019-10-29T02:54:45Z
name: hpa-asdfvs
namespace: my-nginx
resourceVersion: 164701
selfLink: /apis/autoscaling/v1/namespaces/my-nginx/horizontalpodautoscalers/hpa-asdfvs
uid: 76fa6a19-f9f7-11e9-8930-0242c5ccd054
spec:
maxReplicas: 10
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1beta1
kind: Deployment
name: my-nginx
status:
currentReplicas: 1
desiredReplicas: 1
lastScaleTime: 2019-10-29T03:06:10Z
可以看到 hpa 以 annotation 的方式在 v1 版本工作,并将 matrics 字段写入了 annotation 中。在 annotation 的 condition 字段中,我们清楚地看到 HPA 已经获取到了这个指标。之后我们可以尝试降低 target 值来让 pod 扩展,或者增加 target 值来使 pod 缩减。
“监控自定义指标的 HPA 怎么部署”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!