操作场景
实例(Pod)自动扩缩容功能(Horizontal Pod Autoscaler,HPA)可以根据目标实例 CPU 利用率的平均值等指标自动扩展、缩减服务的 Pod 数量
工作原理
HPA 后台组件会每隔15秒向腾讯云云监控拉取容器和 Pod 的监控指标,然后根据当前指标数据、当前副本数和该指标目标值进行计算,计算所得结果作为服务的期望副本数。当期望副本数与当前副本数不一致时,HPA 会触发 Deployment 进行 Pod 副本数量调整,从而达到自动伸缩的目的。 以 CPU 利用率为例,假设当前有2个实例, 平均 CPU 利用率(当前指标数据)为90%,自动伸缩设置的目标 CPU 为60%, 则自动调整实例数量为:90% × 2 / 60% = 3个。
注意:
如果用户设置了多个弹性伸缩指标,HPA 会依据各个指标,分别计算出目标副本数,取最大值进行扩缩容操作。
Pod 水平自动扩缩原理:https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale/
注意事项
- 当指标类型选择为 CPU 利用率(占 Request)时,必须为容器设置 CPU Request。
- 策略指标目标设置合理,例如设置70%给容器和应用,预留30%的余量。
- 保持 Pod 和 Node 健康(避免 Pod 频繁重建)。
- 保证用户请求的负载均衡稳定运行。
- HPA 在计算目标副本数时会有一个10%的波动因子。如果在波动范围内,HPA 并不会调整副本数目。
- 如果服务对应的 Deployment.spec.replicas 值为0,HPA 将不起作用。
- 如果对单个 Deployment 同时绑定多个 HPA ,则创建的 HPA 会同时生效,会造成工作负载的副本重复扩缩。
演练
运行 php-apache 服务器并暴露服务
为了演示 Horizontal Pod Autoscaler,我们将使用一个基于 php-apache 镜像的 定制 Docker 镜像。Dockerfile 内容如下:
FROM php:5-apache
COPY index.php /var/www/html/index.php
RUN chmod a+rx index.php
该文件定义了一个 index.php 页面来执行一些 CPU 密集型计算:
<?php
$x = 0.0001;
for ($i = 0; $i <= 1000000; $i++) {
$x += sqrt($x);
}
echo "OK!";
?>
#镜像构建
docker build -t tcr-chen.tencentcloudcr.com/docker/hpa-example .
使用下面的配置启动一个 Deployment 来运行这个镜像并暴露一个服务:
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
replicas: 1
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: tcr-chen.tencentcloudcr.com/docker/hpa-example:latest
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
创建 Horizontal Pod Autoscaler
现在,php-apache 服务器已经运行,我们将通过 kubectl autoscale 命令创建 Horizontal Pod Autoscaler。 以下命令将创建一个 Horizontal Pod Autoscaler 用于控制我们上一步骤中创建的 Deployment,使 Pod 的副本数量维持在 1 到 10 之间。 大致来说,HPA 将(通过 Deployment)增加或者减少 Pod 副本的数量以保持所有 Pod 的平均 CPU 利用率在 50% 左右(由于每个 Pod 请求 200 毫核的 CPU,这意味着平均 CPU 用量为 100 毫核)
[root@VM-0-17-tlinux ~/hpa/php-apache]# kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache autoscaled
我们可以通过以下命令查看 Autoscaler 的状态:
[root@VM-0-17-tlinux ~/hpa/php-apache]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache 0%/50% 1 10 1 2m21s
请注意当前的 CPU 利用率是 0%,这是由于我们尚未发送任何请求到服务器 (CURRENT 列显示了相应 Deployment 所控制的所有 Pod 的平均 CPU 利用率)
增加负载
我们将看到 Autoscaler 如何对增加负载作出反应。 我们将启动一个容器,并通过一个循环向 php-apache 服务器发送无限的查询请求 (请在另一个终端中运行以下命令)
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
一分钟时间左右之后,通过以下命令,我们可以看到 CPU 负载升高了:
[root@VM-0-17-tlinux ~/hpa/php-apache]# kubectl get hpa -w
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache 249%/50% 1 10 5 8m4s
这时,由于请求增多,CPU 利用率已经升至请求值的 249%。 可以看到,Deployment 的副本数量已经增长到了 5:
[root@VM-0-17-tlinux ~/hpa/php-apache]# kubectl get hpa -w
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache 16%/50% 1 10 8 19m
说明: 有时最终副本的数量可能需要几分钟才能稳定下来。由于环境的差异, 不同环境中最终的副本数量可能与本示例中的数量不同
停止负载
我们将通过停止负载来结束我们的示例。
在我们创建 busybox 容器的终端中,输入<Ctrl> + C 来终止负载的产生。
然后我们可以再次检查负载状态(等待几分钟时间):

根据不同业务场景调节 HPA 扩缩容灵敏度
使用场景
在 K8S 1.18之前,HPA 扩缩容无法调整灵敏度:
- 对于缩容,由
kube-controller-manager的--horizontal-pod-autoscaler-downscale-stabilization-window参数控制缩容时间窗口,默认为5分钟,即负载减小后至少需要5分钟后才开始缩容。 - 对于扩容,由 hpa controller 固定的算法、硬编码的常量因子来控制扩容速度,无法自定义。
K8S 设计逻辑导致用户无法自定义 HPA 的扩缩容灵敏度,不同的业务场景对于扩缩容灵敏度要求并不一样,例如:
- 对于有流量突发的关键业务,需要快速扩容(防止流量瓶颈)、缓慢缩容(防止另一个流量高峰)。
- 对于需要处理大量数据的离线业务,在处理高峰期时应尽快扩容以减少处理时间,高峰期后应尽快缩容以节约成本。
- 对于处理常规数据、网络流量的业务,需要以正常速度扩大和缩小规模,以减少抖动。
K8S 1.18在 HPA Spec 下新增了 behavior 字段,该字段提供 scaleUp 和 scaleDown 两个字段分别控制扩容和缩容行为
示例1:快速扩容
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
labels:
qcloud-app: hpa-php-apache
name: hpa-php-apache
namespace: default
spec:
maxReplicas: 1000
metrics:
- pods:
metricName: k8s_pod_rate_cpu_core_used_limit
targetAverageValue: "80"
type: Pods
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
behavior:
scaleUp:
policies:
- type: Percent
value: 300
periodSeconds: 15
ke控制台通过v2beta1的接口去获取的,因此展示的是v2beta1版本;kubectl 命令默认用的是v1的版本去获取的这个资源对象信息,所以展示的v1
解决:执行这个命令:
kubectl edit HorizontalPodAutoscaler.v2beta2.autoscaling/
kubectl get HorizontalPodAutoscaler.v2beta2.autoscaling/
kubectl get HorizontalPodAutoscaler.v2beta2.autoscaling/php-apache -o yaml
#######
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: default
spec:
behavior:
scaleDown:
policies:
- periodSeconds: 15
type: Percent
value: 100
selectPolicy: Max
stabilizationWindowSeconds: null
scaleUp:
policies:
- periodSeconds: 15
type: Percent
value: 300
selectPolicy: Max
stabilizationWindowSeconds: 0
maxReplicas: 10
metrics:
- resource:
name: cpu
target:
averageUtilization: 50
type: Utilization
type: Resource
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
