K8s实践练习11_自动扩缩容

官网链接:自动扩缩原理 官网链接:自动扩缩演练

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原理

  1. 获取指标:在每个时间段内(间隔由 kube-controller-manager 的 –horizontal-pod-autoscaler-sync-period 参数设置,默认间隔为15秒),控制器管理器都会根据每个HorizontalPodAutoscaler定义中指定的指标查询资源利用率。 控制器管理器找到由scaleTargetRef定义的目标资源,然后根据目标资源的 .spec.selector 标签选择 Pod,并从资源指标 API(针对每个 Pod 的资源指标)或自定义指标获取指标 API(适用于所有其他指标)
  2. 计算目标副本数:期望副本数=ceil(当前副本数×(当前指标/期望指标))。当前3个Pod,CPU使用率60%,目标CPU使用率50% 期望副本数 = ceil[3 × (60/50)] = 4个Pod。如果比率足够接近1.0(在可配置的容差范围内,默认为 0.1),则控制平面会跳过扩缩操作
  3. 调整Deployment/StatefulSet副本数

HPA拥有副本数最终控制权

HPA 扩缩容方式

  1. 基于 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. 基于内存的自动扩缩容
 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. 基于自定义指标的扩缩容
 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. 多指标组合扩散容
 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官方的镜像站在国内是拉不下来的,有几种方法解决:

  1. 在拉取镜像的虚拟机/服务器上科学上网
  2. 配置k8s的镜像源,目前国内只有阿里云支持改版后的k8s镜像源(registry.k8s.io)。
  3. 需要拉取镜像的时候,指定拉取策略为本地拉取(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.ioregistry.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
1
vim web-app.yaml

创建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"]
网站总访客数:Loading
网站总访问量:Loading
使用 Hugo 构建
主题 StackJimmy 设计