CFN Cloud
Cloud Future New Life
en zh
2025-12-29 · 0 次浏览

Kubernetes Tips:用 PDB + Surge/Unavailable 做更稳的发布

把 Deployment 滚动升级参数与 PodDisruptionBudget 配合起来,降低发布与节点维护带来的可用性风险。

很多“例行发布变事故”的根因并不是某个单点 bug,而是以下几个参数之间的假设不一致:

  • 发布时允许同时下线多少 Pod(Deployment rollingUpdate)
  • 维护/驱逐时允许同时被赶走多少 Pod(PDB)
  • 实际副本数与容量是否足够(请求资源、节点池 headroom)
  • readiness 与优雅下线是否可靠(摘流量是否及时)

这篇 tips 给你一个可落地的组合策略。

Deployment rollingUpdate:最常用的两个旋钮

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 25%
    maxUnavailable: 0

含义:

  • maxSurge:升级时允许额外创建多少新 Pod(加速替换,但需要容量)
  • maxUnavailable:升级时允许不可用的 Pod 数量(越小越稳,但可能更慢)

对于必须保持可用的服务,maxUnavailable: 0 常常是一个强默认值。

PDB(PodDisruptionBudget):保护“自愿”驱逐

PDB 主要保护:

  • kubectl drain 节点
  • 平台升级/维护时的 cordon + drain
  • 一些自动化维护流程

示例:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: api

注意:PDB 只对 voluntary disruptions 生效,不对节点崩溃、网络分区、内核 OOM 这类“非自愿”故障兜底。

minAvailable 还是 maxUnavailable

  • minAvailable:副本数固定时更直观
  • maxUnavailable:比例型预算更方便(大规模服务)

经典坑:副本数太少 + PDB 太严格

如果你只有 2 个副本,同时 minAvailable: 2

  • drain 节点可能被卡住(一个都不让走)
  • 维护会很痛苦

这不是“PDB 不好”,而是你的 SLA、成本、副本数与维护策略需要对齐。

让数字变得清晰:rollout 的“数学题”

例子:8 副本,maxSurge: 25%maxUnavailable: 0

  • maxSurge 允许额外最多 2 个 Pod(25% of 8)
  • 理论上可用 Pod 维持 8 个不掉(更稳)

但这依赖两个前提:

  • 集群有容量调度出 surge Pod(requests 合理,节点池有余量)
  • readiness 真的代表“可接流量”(否则 surge 再多也没用)

如果 surge Pod 因容量不足一直 Pending,rollout 会卡住。

把副本“铺开”:否则 PDB 也救不了你

如果所有副本都落在同一个节点/同一个可用区:

  • 一个节点 drain/故障就会把你打到不可用

建议使用 topologySpreadConstraints(现代方式)或 pod anti-affinity。

例如跨可用区分布:

topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        app: api

“可用性”的另一半:优雅下线

即使 maxUnavailable: 0,你仍可能在发布时看到错误率升高,原因往往是旧 Pod 下线过快:

  • readiness 未及时失败,仍在 endpoints 里
  • 连接被强行断开(长连接/gRPC/队列 worker)
  • terminationGracePeriodSeconds 太短

实用模式:

  1. 收到 SIGTERM,服务立刻让 readiness 失败(快速摘流量)
  2. 等待 in-flight 请求完成(grace period)
  3. 再退出

和 HPA / Cluster Autoscaler 的交互

rollout 时 surge 会让 Pod 数暂时增多:

  • 如果节点有余量,发布会很顺
  • 如果没余量,Cluster Autoscaler 可能会扩节点,但节点启动需要时间

同时如果 HPA 正在因流量扩容,也会叠加 surge,造成更大的容量需求。

建议:

  • 高峰期减少发布频率或采用 canary
  • 让节点池保留一定 headroom
  • 确保 requests 准确(否则你以为有余量,实际上没有)

kubectl drain 被卡住怎么办(PDB 视角)

当 drain 时 PDB 阻止驱逐,你通常会看到:

  • drain 命令一直等待
  • 事件里提示 disruption budget 不允许

这时应检查:

  • 副本数是否足够、是否能在其他节点快速重建
  • 是否因亲和性/节点选择器太严格导致无法调度
  • readiness 是否一直不通过导致可用副本不足

进阶:当 rollingUpdate 不够稳(canary/blue-green)

某些变更风险更高:

  • 大版本升级
  • 配置大改
  • 数据库迁移

可考虑渐进交付:

  • canary:先 1% 再 10% 再 50%
  • blue/green:两套环境切流量

即使没有完整平台,也可以通过“第二个 Deployment + 流量规则”近似 canary,关键是 把爆炸半径变小

推荐组合(可直接抄的经验值)

3 副本的典型无状态 API

  • Deployment:maxUnavailable: 0maxSurge: 1
  • PDB:minAvailable: 2
  • 跨 zone 分布(spread constraints)

10+ 副本的大流量服务

  • Deployment:maxUnavailable: 10%maxSurge: 10%
  • PDB:用比例预算对齐 rollout(减少“维护卡死”)
  • 配合监控与自动回滚策略

结论

PDB + rollout 参数不是“开了就万事大吉”,它们在以下条件成立时效果最好:

  • 副本数足够
  • 副本分布在不同故障域
  • readiness/liveness/优雅下线靠谱
  • 节点容量足够(或 autoscaler 配置合理)

把这些前提补齐,发布会明显更稳。

参考链接

FAQ

Q: PDB 保护什么? A: 只保护“自愿中断”(如 drain/升级),不防节点宕机。

Q: 发布卡住怎么办? A: PDB 太严或 readiness 未就绪会阻塞发布。检查事件并调整 maxUnavailable/minAvailable

Q: surge/unavailable 怎么配? A: 保证有足够的 surge 来创建新 Pod,同时满足 PDB 的可用性约束。