2025-12-29

Kubernetes 自动扩缩容:HPA、VPA 和 Cluster Autoscaler 的边界

把 requests 写对、HPA 行为调稳、VPA 做推荐、CA 能补容量,让扩缩容可预测而不是“抽风”。

扩缩容是一套“系统的系统”。如果你觉得它不稳,常见原因是:

  • requests 不准(分母错)
  • 多个控制器在打架(HPA/VPA/发布/surge 同时发生)
  • 集群容量层(Cluster Autoscaler/节点池)跟不上

这篇 tips 给一个可落地的稳定扩缩容思路。

三层扩缩容:先搞清楚谁负责什么

  1. HPA(Horizontal Pod Autoscaler):改副本数(replicas)
  2. VPA(Vertical Pod Autoscaler):改/推荐 requests(有些模式也能自动改)
  3. Cluster Autoscaler:改节点数(加/减节点)

想要稳定,需要三层对齐:指标、requests、容量与启动时间。

Step 0:requests 是地基(不写或写错,一切都不准)

很多扩缩容逻辑都以 requests 为基础:

  • HPA 的 CPU utilization 常用:当前 CPU / requests.cpu
  • 调度器靠 requests 放置 Pod
  • Cluster Autoscaler 看到 Pod Pending 才会补节点(Pending 常由 requests 触发)

因此第一步永远是:所有容器都要有合理 requests。

HPA 基础例子(CPU 利用率)

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api
  namespace: app
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 3
  maxReplicas: 30
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60

含义:

  • 平均 CPU 接近 requests 的 60% 时保持稳定
  • 高于 60% 倾向扩容,低于 60% 倾向缩容

但注意:如果 requests 不准,这个“60%”没有意义。

防止抖动:stabilization window 与 scaling policy

HPA v2 支持行为配置,用来避免“上上下下”:

behavior:
  scaleUp:
    stabilizationWindowSeconds: 0
    policies:
      - type: Percent
        value: 100
        periodSeconds: 60
  scaleDown:
    stabilizationWindowSeconds: 300
    policies:
      - type: Percent
        value: 20
        periodSeconds: 60

思路是:

  • 扩容尽量快(应对突发)
  • 缩容慢一点(避免流量小波动导致频繁缩容)

指标选择:CPU 不是万能

CPU 利用率适合:

  • 典型无状态 Web/API

但对这些类型往往不准:

  • 队列 worker(更适合 backlog/lag)
  • 内存型服务(CPU 低但内存持续升)
  • I/O 型服务(瓶颈不在 CPU)

更靠谱的做法是选择贴近业务负载的指标:

  • 队列深度、消费滞后
  • RPS/并发连接数
  • 关键路径延迟(谨慎,避免反馈环)

结论:

用“能代表负载”的指标扩容,而不是只看资源消耗。

冷启动与 readiness:扩了也不一定立刻有用

扩容增 Pod,但 Pod 变成可用需要时间:

  • 拉镜像
  • 启动(JVM warmup、迁移、缓存)
  • readiness 通过

如果启动慢,HPA 扩容再快也救不了峰值。

你可能需要:

  • 提高 minReplicas
  • 提前预热镜像(节点缓存)
  • 对启动慢服务加 startupProbe
  • 合理的 scaleUp policy

Cluster Autoscaler:容量层的关键

HPA 扩容后,如果节点不够,Pod 会 Pending。Cluster Autoscaler 需要能识别并补节点。

如果 CA 不工作,常见原因:

  • affinity/nodeSelector 让 Pod 只能去不存在的节点池
  • requests 太大,没有任何节点规格能容纳
  • 节点池 max size/配额到顶
  • PDB/约束导致缩容逻辑受限(与 scale-down 相关)

排查 Pending:

kubectl get pod -n <ns> | rg -n "Pending"
kubectl describe pod -n <ns> <pod> | rg -n "FailedScheduling|Insufficient"

VPA:即使只做推荐也很有价值

当前 VPA 常见模式包括:

  • Off:只生成推荐,不修改 Pod
  • Initial:只在 Pod 创建时设置 requests
  • Recreate:通过重建 Pod 应用更新
  • InPlaceOrRecreate:优先原地调整,失败时重建,需要集群支持原地资源调整
  • InPlace:只尝试原地调整,不主动驱逐,需要对应 Feature Gate

Auto 已弃用,应改成明确的更新模式。

建议路径:

  1. 先用 Off 观察推荐并校正 requests
  2. 再用 Initial 降低运行中变更风险
  3. 集群支持原地调整后,再评估 InPlaceOrRecreate 或 InPlace

HPA + VPA 一起用:避免打架

如果 HPA 以 CPU utilization 扩容,而 VPA 频繁改 CPU requests:

  • 分母变了,HPA 会突然改变判断
  • 容易产生“看起来负载没变,但副本数在变”的现象

实践上常见组合:

  • HPA 用 CPU 或业务指标控制副本数
  • VPA 用来推荐/调整 内存 requests(或以 Initial 模式周期性更新)

内存扩缩容要谨慎

HPA 也能按内存指标扩缩,但内存通常是滞后指标:

  • 缓存增长导致内存上升,但扩容并不一定能立刻缓解
  • 缩容后缓存重建反而变慢

如果确实要用内存指标:

  • requests.memory 必须贴近真实峰值,否则百分比目标没有意义
  • 缩容窗口拉长,避免缓存刚重建就被缩容
  • 把内存当成保护性指标,而不是唯一扩容信号

更常见的稳妥方式:

  • HPA 按 CPU/RPS 扩容
  • VPA 优化内存 requests
  • 缩容保守(长 stabilization window)

队列和流任务:按业务积压扩容

队列驱动的 Pod,CPU 利用率通常不能反映真实压力。优先观察:

  • 未处理消息数或队列深度
  • consumer lag 或消费组滞后
  • 每个消费者平均处理时长

KEDA 这类事件驱动方案适合按积压扩容,也能在业务允许时缩到 0。核心在于选择能反映业务负载的指标。

分阶段上线

  1. 为应用容器、sidecar 和 initContainer 补齐合理的 requests。
  2. 先启用 HPA,目标值保守,缩容速度放慢。
  3. 用压测或真实峰值记录 Pod 从创建到 Ready 的时间线。
  4. 确认 Cluster Autoscaler 能补节点,节点池配额和调度约束没有卡点。
  5. 最后启用 VPA 推荐,根据稳定窗口逐步校正 requests。

排障:HPA/指标为什么不工作

看 HPA 状态:

kubectl get hpa -n <ns>
kubectl describe hpa -n <ns> <hpa>

常见提示:

  • 无法获取指标(metrics pipeline 问题)
  • 缺 requests(HPA 无法计算 utilization)
  • 频繁 scale events(需要 behavior 调整或指标换更贴近负载)

指标管道

HPA 读不到指标就不会工作。分别确认:

  • 资源指标:metrics-server 已安装,kubectl top pod 能返回数据。
  • 自定义/外部指标:Prometheus adapter 或其他指标适配器暴露了 HPA 引用的指标名。

Requests 与 QoS

requests 缺失或严重偏大,都会让扩缩容失真。检查 Deployment、initContainer 和 sidecar 的每一段资源配置。

上线前先做一次扩容演练

自动扩缩容“看起来正常”直到第一次真实高峰。生产前至少确认:

  • 增加 Pod 需要多久:镜像拉取、启动、readiness。
  • 增加节点需要多久:Cluster Autoscaler、节点池供应、网络挂载。
  • 服务在容量爬坡期是否还能承接部分流量。

如果节点供应要 3-5 分钟,可能需要提高 minReplicas、预热节点池,或加快 scaleUp 策略。稳定的扩缩容需要同时对齐启动时间、指标延迟和容量供应。

上线前自检

  • requests 对齐真实负载(别拍脑袋)
  • HPA 缩容保守,避免抖动
  • 指标链路可靠(metrics-server/adapter)
  • Cluster Autoscaler 能满足调度约束并有容量余量
  • 用 VPA 推荐持续修正 requests

常见问题

Q: HPA 和 VPA 怎么选?

A: HPA 负责副本数,VPA 负责 requests 的校准。两者可以用于同一工作负载,但如果 HPA 按 CPU utilization 扩容,就不要让 VPA 频繁修改 CPU requests;可先使用 VPA Off 或只调整内存。

Q: 为什么 HPA 会抖动?

A: 指标延迟和激进策略会导致反复伸缩。加 stabilization window、放慢 scale down,并调准目标值。

Q: 一定要装 metrics-server 吗?

A: CPU/内存的 HPA 需要 metrics-server;自定义指标需要指标管道(如 Prometheus + adapter)。

参考链接