官方文档: Pod 水平自动扩缩
Horizontal Pod Autoscaler
Pod 水平自动扩缩(Horizontal Pod AutoScaler) 可以基于 CPU 利用率,自动扩缩 RC,RS,Deployment 和 StatefulSet 中的 Pod 数量。除了 CPU 利用率,也可以基于其他应用程序提供的自定义度量指标来执行自动扩缩。Pod 自动扩缩不适用于无法扩缩的对象,比如 DaemonSet。
Pod 水平自动扩缩特性由 Kubernetes API 资源和控制器实现。资源决定了控制器的行为。控制器会周期性的调整副本控制器或 Deployment 中的副本数量,以使得 Pod 的平均 CPU 利用率与用户所设定的目标值匹配。
Pod 水平自动扩缩工作机制
Pod 水平自动扩缩器的实现是一个控制回路,由控制器管理器的 --horizontal-pod-autoscaler-sync-period
参数指定周期(默认值为 15 秒)。每个周期内,控制器管理器根据每个 HPA 定义中指定的指标查询资源利用率。控制器管理器可以从资源度量指标 API(按 Pod 统计的资源用量) 和自定义度量指标API(其他指标)获取度量值。
- 对于按 Pod 统计的资源指标(如 CPU),控制器从资源指标 API 中获取每一个 HPA 指定的 Pod 的度量值,如果设置了目标使用率,控制器获取每个 Pod 中的容器资源使用情况,并计算资源使用率。如果设置了
target
值,将直接使用原始数据(不再计算百分比)。接下来,控制器根据平均的资源使用率或原始值计算出扩缩的比例,进而计算出目标副本数。(需要注意的是,如果 Pod 某些容器不支持资源采集,那么控制器将不会使用该 Pod 的 CPU 使用率。) - 如果 Pod 使用自定义指示,控制器机制与资源指标类似,区别在于自定义指标只使用原始值,而不是使用率;
- 如果 Pod 使用对象指标和外部指标(每个指标描述一个对象信息)。这个指标将直接根据目标设定值相比较,并生成一个上面提到的扩缩比例。在
autoscaling/v2beta2
版本 API 中,这个指标也可以根据 Pod 数量平分后再计算。
算法细节
从最基本的角度看,Pod 水平自动扩缩控制器根据当前指标和期望指标来计算扩缩比例
1 | 期望副本数 = ceil[当前副本数 * (当前指标 / 期望指标)] |
例如,当前度量值为 200m,目标设定值为 100m,那么由于 200.0/100.0 == 2.0,副本数量将会翻倍。如果当前指标为 50m,副本数量将会减半,因为 50.0/100.0 == 0.5。如果计算出的扩缩比例接近 1.0(根据 –horizontal-pod-autoscaler-tolerance 参数全局配置的容忍值,默认为 0.1),将会放弃本次扩缩。
- 如果 HPA 指定的是 targetAverageValue 或 targetAverageUtilization,那么将会把指定 Pod 度量值的平均值作为 currentMetricValue。然而,在检查容忍度和决定最终扩缩值前,仍然会把那些无法获取指标的 Pod 统计进去。
- 所有被标记了删除时间戳(Pod 正在关闭过程中)的 Pod 和失败的 Pod 都会被忽略;
- 如果某个 Pod 缺失度量值,它将会被搁置,只在最终确定扩缩数量时再考虑;
- 当使用 CPU 指标来扩缩时,任何还未就绪状态的 Pod 或最近的指标度量值采集于就绪状态前的 Pod,该 Pod 也会被搁置;
由于受技术限制,HPA 控制器无法准确的知道 Pod 什么时候就绪,也就无法决定是否暂时搁置该 Pod。
--horizontal-pod-autoscaler-initial-readiness-delay
参数(默认为 30s) 用于设置 Pod 准备时间,在此时间内的 Pod 统统被认为未就绪。–horizontal-pod-autoscaler-cpu-initialization-period 参数(默认为 5分钟)用于设置 Pod 的初始化时间,在此时间内的 Pod,CPU 资源度量值将不会被采纳。
在排除掉被搁置的 Pod 后,扩缩比例就会根据 currentMerticValue/desiredMetricValue
计算出来。
如果创建 HPA 时指定了多个指标, 那么会按照每个指标分别计算扩缩副本数,取最大值进行扩缩。 如果任何一个指标无法顺利地计算出扩缩副本数(比如,通过 API 获取指标时出错), 并且可获取的指标建议缩容,那么本次扩缩会被跳过。 这表示,如果一个或多个指标给出的 desiredReplicas 值大于当前值,HPA 仍然能实现扩容。
最后,在 HPA 控制器执行扩缩操作之前,会记录扩缩建议信息。 控制器会在操作时间窗口中考虑所有的建议信息,并从中选择得分最高的建议。 这个值可通过 kube-controller-manager 服务的启动参数 --horizontal-pod-autoscaler-downscale-stabilization
进行配置, 默认值为 5 分钟。 这个配置可以让系统更为平滑地进行缩容操作,从而消除短时间内指标值快速波动产生的影响。
kubectl 对 HPA 的支持
与其他 API 资源类似,kubectl 以标准方式支持 HPA,我们可以通过 kubectl create
命令创建一个 HPA 对象,通过 kubectl get hpa
命令来获取所有 HPA 对象,通过 kubectl describe hpa
命令来查看 HPA 对象的详细信息。最后可以通过 kubectl delete hpa
命令删除对象。
此外,还有一个简便的命令 kubectl autoscale 来创建 HPA 对象,如下示例,将会为名为 foo 的 RS 创建一个 HPA 对象,当目标 CPU 使用率为 80%,副本数量配置为 2-5 之间;
1 | kubectl autoscale rs foo --min=2 --ma=5 --cpu-percent=80 |
冷却与延迟
当使用 HPA 管理一组副本扩缩时,有可能因为指标动态的变化造成副本数量频繁的变化,有时这被称为抖动
;从 v1.16 版本起,集群操作员可以调节某些 kube-controller-manager 的全局参数来缓解这个问题。
从 v1.12 开始,算法调整后,扩容操作时的延迟就没必要设置了,
--horizontal-pod-autoscaler-downscale-stabilization
: kube-controller-manager 的这个参数表示缩容冷却时间。 即自从上次缩容执行结束后,多久可以再次执行缩容,默认时间是 5 分钟(5m0s)。
对资源指标的支持
HPA 的任何目标资源都可以基于其中的 Pods 的资源用量来实现扩缩。 在定义 Pod 规约时,类似 cpu
和 memory
这类资源请求必须被设定。 这些设定值被用来确定资源利用量并被 HPA 控制器用来对目标资源完成扩缩操作。
- 要使用基于资源利用率的扩缩,可以像下面这样指定一个指标源
1 | type: Resource |
基于以上指标配置,HPA 控制器会维持扩缩目标中的 Pods 的平均资源利用率在 60%。利用率是 Pod 的但前资源用量与请求值之间的比值。
多指标支持
kubernetes 1.6 开始支持基于多个度量值进行扩缩。你可以使用 autoscaling/v2beta2
API 来为 HPA 指定多个指标。HPA 会根据每个指标计算,并生成一个扩缩建议。幅度最大的扩缩建议会被采纳。
自定义指标支持
自 Kubernetes 1.6 起,HPA 支持使用自定义指标。 你可以使用 autoscaling/v2beta2
API 为 HPA 指定用户自定义指标。 Kubernetes 会通过用户自定义指标 API 来获取相应的指标。
HPA 示例
修改 deploy nginx 的 resource 属性,内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19# kubectl edit deploy nginx # 直接使用 edit 修改 deploy;
修改以下 `resource` 部分内容
...
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: nginx
resources:
limits:
cpu: 100m
memory: 200Mi
requests:
cpu: 10m
memory: 70Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst为该 deployment 创建 HPA 资源
1
2# kubectl autoscale deploy nginx --cpu-percent=20 --min=2 --max=5
horizontalpodautoscaler.autoscaling/nginx autoscaled查看 svc 地址,新开一个窗口,模拟大量访问请求
1
2
3
4
5# kubectl get svc nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.102.0.153 <none> 80/TCP,443/TCP 2d21h
# while true;do wget -q -O- http://10.102.0.153 >/dev/null;done查看 hpa 状态以及该 deploy 的 Pod 数量变化
1
2
3
4
5
6
7
8
9
10
11# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx Deployment/nginx 485%/20% 2 5 2 25m
# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-5f7cd9bd54-8qphv 1/1 Running 0 37s
nginx-5f7cd9bd54-fnk2w 1/1 Running 0 21m
nginx-5f7cd9bd54-h6s9w 1/1 Running 0 52s
nginx-5f7cd9bd54-lk9lp 1/1 Running 0 20m
nginx-5f7cd9bd54-rjspc 1/1 Running 0 52s退出模拟访问状态,检查 HPA 的自动缩容
1
2
3
4
5
6
7
8# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx Deployment/nginx 0%/20% 2 5 2 39m
# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-5f7cd9bd54-fnk2w 1/1 Running 0 34m
nginx-5f7cd9bd54-rjspc 1/1 Running 0 13m