官网链接:自动扩缩原理
官网链接:自动扩缩演练
Kubernetes自动扩缩容有HPA(Horizontal Pod Autoscaler)和VPA(Vertical Pod AutoScaler)两种
| 维度 |
HPA(Horizontal Pod Autoscaler) |
VPA(Vertical Pod Autoscaler) |
| 核心行为 |
水平扩缩容:根据指标调整 Pod 副本数(scale 子资源) |
垂直扩缩容:根据历史使用自动调整 Pod 的 CPU/内存 requests/limits |
| 扩缩对象 |
实现 scale 子资源的资源:Deployment、StatefulSet、ReplicaSet、ReplicationController 等 |
支持通过标签选择器匹配 Pod 的控制器:Deployment、StatefulSet,以及部分场景下的 DaemonSet |
| 是否支持 DaemonSet |
明确不支持:官方文档写明 “Horizontal pod autoscaling does not apply to objects that can’t be scaled (for example: a DaemonSet).” |
支持:VPA Spec 中注释明确写到可以针对 DaemonSet 等控制器,通过控制器 spec 获取 Pod 集合 |
| API 版本 & 稳定性 |
autoscaling/v2(稳定 API),属于 Kubernetes 核心 API |
autoscaling.k8s.io/v1(稳定 API),但需要单独安装 VPA CRD 与控制器 |
| 触发指标 |
CPU/内存利用率、自定义指标、外部指标等 |
依赖 Metrics Server(metrics.k8s.io)获取 Pod 的 CPU/内存使用历史 |
| 更新方式 |
修改副本数,不会改变单个 Pod 的资源配置 |
修改 Pod 的 requests/limits;支持多种更新模式 |
| 更新模式 |
无“模式”概念;只负责扩缩副本数 |
支持 4 种更新模式:Off / Initial / Recreate / InPlaceOrRecreate,Auto 已废弃 |
| 是否需要重启 Pod |
不需要,只改副本数 |
旧模式:Recreate 会驱逐 Pod(重建);新模式:InPlaceOrRecreate 在集群支持时可以 原地更新,不重启容器 |
| 典型场景 |
无状态服务、Web/API、可水平扩展的业务应用 |
适合资源需求波动大、难以手动调优的应用;包括无状态和很多有状态应用 |
| 优点 |
模型简单、成熟度高、适合水平扩展的业务;不改变 Pod 规格 |
自动“修 request/limit”,提升资源利用率、减少 OOM;配合 InPlaceOrRecreate 可减少中断 |
| 缺点 / 限制 |
需要业务本身可水平扩展;对资源设置不合理的问题无能为力 |
历史上会频繁驱逐 Pod,对有状态服务要谨慎;需要 Metrics Server;部分平台/版本对原地更新支持有限;可与HPA共用,但要避免同指标互相打架:官方建议避免HPA与VPA同时基于CPU/内存等相同指标扩缩 |
HPA原理
- 获取指标:在每个时间段内(间隔由 kube-controller-manager 的 –horizontal-pod-autoscaler-sync-period 参数设置,默认间隔为15秒),控制器管理器都会根据每个HorizontalPodAutoscaler定义中指定的指标查询资源利用率。 控制器管理器找到由scaleTargetRef定义的目标资源,然后根据目标资源的 .spec.selector 标签选择 Pod,并从资源指标 API(针对每个 Pod 的资源指标)或自定义指标获取指标 API(适用于所有其他指标)
- 计算目标副本数:期望副本数=ceil(当前副本数×(当前指标/期望指标))。当前3个Pod,CPU使用率60%,目标CPU使用率50%
期望副本数 = ceil[3 × (60/50)] = 4个Pod。如果比率足够接近1.0(在可配置的容差范围内,默认为 0.1),则控制平面会跳过扩缩操作
- 调整Deployment/StatefulSet副本数
HPA拥有副本数最终控制权
HPA 扩缩容方式
- 基于 CPU 的自动扩缩容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: cpu-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2 # 最小副本数
maxReplicas: 10 # 最大副本数
metrics:
- type: Resource
resource:
name: cpu # 基于 CPU 的自动扩缩容
target:
type: Utilization # 使用率类型
averageUtilization: 50 # 目标CPU使用率50%
|
- 基于内存的自动扩缩容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: memory-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70 # 目标内存使用率70%
|
- 基于自定义指标的扩缩容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: custom-metric-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Pods
pods:
metric:
name: requests_per_second # 自定义指标名称
target:
type: AverageValue
averageValue: 1000 # 每个Pod目标请求数1000/s
|
- 多指标组合扩散容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: multi-metric-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70
behavior: # 扩缩容行为控制
scaleDown:
stabilizationWindowSeconds: 300 # 缩容冷却时间5分钟
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100
periodSeconds: 15
|
K8s集群搭建以及镜像源配置
搭建好一套k8s集群,可以参考我写的这篇教程:搭建k8s集群
k8s官方的镜像站在国内是拉不下来的,有几种方法解决:
- 在拉取镜像的虚拟机/服务器上科学上网
- 配置k8s的镜像源,目前国内只有阿里云支持改版后的k8s镜像源(registry.k8s.io)。
- 需要拉取镜像的时候,指定拉取策略为本地拉取(
imagePullPolicy:Never),每次需要拉取镜像前都手动拉取/上传一份镜像到服务器上再导入镜像
这里给出阿里云镜像源的配置教程:
旧版的k8s直接修改/etc/containerd/config.toml里的mirror信息,添加上阿里云的镜像站就行。但是新版的不支持inline或者说暂时兼容,未来不支持。所以这里就只给出新版k8s镜像源配置教程。
修改/etc/containerd/config.yaml,填入下列信息(如果你已经有了config.yaml且这个配置文件是从containerd默认配置里生成的,那直接备份,然后使用下面的内容)。sudo vim /etc/containerd/config.yaml
1
2
3
4
5
6
7
8
9
10
|
version = 2
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
|
创建/etc/containerd/certs.d目录,在这个目录填入docker.io和registry.k8s.io的镜像源。
注意:k8s里修改镜像源之后,使用kubectl describe pod <pod_name> 查看时还是显示的docker.io和registry.k8s.io。配置镜像源只物理修改从哪里修改,不改镜像拉取的逻辑源。所以改好镜像源之后也不太好验证成功,随便拉个镜像sudo crictl pull nginx:1.14.2,能拉下来就是成了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# Docker Hub 加速
sudo mkdir -p /etc/containerd/certs.d/docker.io
sudo tee /etc/containerd/certs.d/docker.io/hosts.toml << 'EOF'
server = "https://registry-1.docker.io"
[host."https://docker.m.daocloud.io"]
capabilities = ["pull", "resolve"]
EOF
# K8s 镜像加速
sudo mkdir -p /etc/containerd/certs.d/registry.k8s.io
sudo tee /etc/containerd/certs.d/registry.k8s.io/hosts.toml << 'EOF'
server = "https://registry.k8s.io"
[host."https://k8s.nju.edu.cn"]
capabilities = ["pull", "resolve"]
[host."https://registry.cn-hangzhou.aliyuncs.com/google_containers"]
capabilities = ["pull", "resolve"]
EOF
|
到这里,镜像源就配置好了,如果不出意外,文件目录应该是下面这样:
1
2
3
4
5
6
7
|
rust@k8s1:/etc/containerd$ ll
总计 28
drwxr-xr-x 3 root root 4096 2月 4 10:31 ./
drwxr-xr-x 144 root root 12288 2月 2 17:01 ../
drwxr-xr-x 4 root root 4096 2月 2 16:44 certs.d/
-rw-r--r-- 1 root root 423 2月 2 19:02 config.toml
-rw-r--r-- 1 root root 886 12月 19 02:48 config.toml.dpkg-dist
|
修改完配置文件后需要重启containerd:
1
2
|
sudo systemctl restart containerd
sudo systemctl status containerd
|
HPA实操案例:Web应用CPU自动扩缩容
创建测试应用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.25
ports:
- containerPort: 80
# 核心修改:启动时运行CPU密集型任务
command: ["/bin/sh", "-c"]
args:
- |
# 启动 Nginx
nginx -g 'daemon off;' &
# 启动 CPU 压力生成器 (计算哈希值)
# 这个循环会尽可能多地占用 CPU
while true; do
dd if=/dev/urandom bs=1M count=1 2>/dev/null | sha256sum > /dev/null
done
resources:
requests:
cpu: 200m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
|
创建HPA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
|
1
2
3
4
5
6
7
8
9
10
|
vim hpa.yaml
kubectl apply -f hpa.yaml
# 查看HPA状态
kubectl get hpa
kubectl describe hpa web-hpa
rust@k8s1:~/k8s_try$ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
web-hpa Deployment/web-app cpu: 0%/50% 2 10 2 26s
|
观察扩容
开一个终端,应用web-app.yaml,再开两个终端,监测HPA状态和Pod数据。
1
2
3
4
5
6
7
8
9
10
11
|
# 应用web-app,自带压力测试(后台循环计算sha256)
kubectl apply -f web-app.yaml
# 监控HPA状态
watch kubectl get hpa
# 监控Pod数量
watch kubectl get pods -l app=web
# 查看详细事件
kubectl describe hpa web-hpa
|
日志情况,观察hpa终端里CPU占用量迅速超过50%,观察pod数量终端里可以看到web-app由刚开始的2个迅速涨到hpa yaml文件里设置的最大副本数10个。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
# 监控HPA状态的终端
rust@k8s1:~$ watch kubectl get hpa
Every 2.0s: kubectl get hpa k8s1: Sat Feb 14 15:18:44 2026
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
web-hpa Deployment/web-app cpu: 250%/50% 2 10 4 82s
# 监控Pod数量的终端
rust@k8s1:~watch kubectl get pods -l app=webeb
Every 2.0s: kubectl get pods -l app=web k8s1: Sat Feb 14 15:19:06 2026
NAME READY STATUS RESTARTS AGE
web-app-7599649b66-2z7vs 1/1 Running 0 46s
web-app-7599649b66-9lchb 1/1 Running 0 31s
web-app-7599649b66-glvb6 1/1 Running 0 16s
web-app-7599649b66-hl2rn 1/1 Running 0 74s
web-app-7599649b66-l78rq 1/1 Running 0 46s
web-app-7599649b66-q4jzl 1/1 Running 0 74s
web-app-7599649b66-qntwr 1/1 Running 0 31s
web-app-7599649b66-qp4sf 1/1 Running 0 31s
web-app-7599649b66-srlk2 1/1 Running 0 31s
web-app-7599649b66-tr5pj 1/1 Running 0 16s
|
HPA参数介绍
扩缩策略
可以在规约的 behavior 部分中指定一个或多个扩缩策略。当指定多个策略时, 允许最大更改量的策略是默认选择的策略。
1
2
3
4
5
6
7
8
9
|
behavior:
scaleDown:
policies:
- type: Pods
value: 4
periodSeconds: 60
- type: Percent
value: 10
periodSeconds: 60
|
periodSeconds 表示在过去的多长时间内要求策略值为真。periodSeconds可以设置的最大值为 1800(半小时)。第一个策略(Pods)允许在一分钟内最多缩容4个副本。第二个策略(Percent)允许在一分钟内最多缩容当前副本个数的百分之十。
存在多个扩缩容策略时,默认选择容许更大程度作出变更的策略。可以指定扩缩方向的selectPolicy字段来更改策略选择。通过设置 Min 的值,它将选择副本数变化最小的策略。将该值设置为Disabled将完全禁用该方向的扩缩。
稳定窗口
1
2
3
|
behavior:
scaleDown:
stabilizationWindowSeconds: 300
|
当用于扩缩的指标不断波动时,稳定窗口用于限制副本计数的波动。当指标显示目标应该缩容时,自动扩缩算法使用此窗口来推断先前的期望状态,并避免对工作负载规模进行不必要的更改。在上面的例子中,过去 5 分钟的所有期望状态都会被考虑。
容忍阈值
tolerance字段用于配置指标波动的阈值,避免自动扩缩器因小幅变化而触发扩缩容操作。
该容忍阈值指的是在期望指标值附近的一个波动范围,在这个范围内不会触发扩缩容操作。
1
2
3
|
behavior:
scaleUp:
tolerance: 0.05 # 5% 容忍度用于扩容
|
在这种配置下,只有当内存使用量比目标值高出5%时,HPA 算法才会考虑进行扩容。
如果未设置该字段,HPA 将使用集群范围内默认的 10% 容忍阈值。
可以通过kube-controller-manager的--horizontal-pod-autoscaler-tolerance命令行参数,分别调整扩容和缩容的默认容忍阈值。
默认行为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 100
periodSeconds: 15
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
|
用于缩小稳定窗口的时间为 300 秒(或是 –horizontal-pod-autoscaler-downscale-stabilization 命令行选项设定值)。 只有一种缩容的策略,允许100%删除当前运行的副本,这意味着扩缩目标可以缩小到允许的最小副本数。对于扩容,没有稳定窗口。当指标显示目标应该扩容时,目标会立即扩容。 扩容策略有两种,每15秒最多添加4个Pod、每15s最多添加100%当前运行的副本数,直到HPA达到稳定状态。
示例yaml文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: production-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: production-app
minReplicas: 5
maxReplicas: 50
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
behavior:
scaleDown:
stabilizationWindowSeconds: 600 # 缩容前等待10分钟
policies:
- type: Percent
value: 10 # 每次最多缩容10%
periodSeconds: 60
- type: Pods
value: 5 # 或者最多缩容5个Pod
periodSeconds: 60
selectPolicy: Min # 选择限制更严格的缩容策略
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100 # 可以快速扩容到100%
periodSeconds: 15
- type: Pods
value: 10 # 或者每次扩容10个Pod
periodSeconds: 15
selectPolicy: Max # 选择扩容更积极的策略
|
VPA原理
VPA(Vertical Pod Autoscaler):垂直Pod自动扩缩容,根据容器的实际资源使用情况自动调整且其CPU和内存请求与限制。
不同于HPA调整Pod副本数,VPA是"垂直"调整单个Pod的资源规格。
VPA有四种更新模式:
- off:VPA仅计算并存储资源推荐值(Target/Lower/Upper Bound),不会修改任何Pod的资源请求或限制。Pod不重启。
- Initial:VPA仅对新创建的Pod应用推荐的资源值。已运行的Pod不受影响,依赖VPA Admission Controler(准入控制器)。
在Pod创建时注入推荐值。适用于Deployment/StatefulSet滚动更新时自动应用新配置,避免服务中断。现有的Pod不重启,新Pod用新配置。
- Recreate:主动驱逐(evict)现有Pod,由控制器(如Deployment)重建。一定会导致Pod重启
- InplaceOrRecreate:v1.27引入,如果节点支持inplace Resize,直接更新Pod资源,容器不重启。如果不支持(旧版本),自动回退到驱逐重建(Recreate),目标实现零中断垂直扩缩容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: my-app-deployment
updatePolicy:
updateMode: InplaceOrRecreate
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed:
cpu: "100m"
memory: "50Mi"
maxAllowed:
cpu: "2"
memory: "4Gi"
controlledResources: ["cpu", "memory"]
|