深色模式
Pod 中断预算 PDB 与可用性
摘要:本文面向负责集群维护与高可用的 SRE,讲解 PodDisruptionBudget(PDB)如何限制自愿中断的并发数量,以及它与节点 drain、可用性之间的权衡。覆盖 Kubernetes v1.28+(
policy/v1稳定)。
适用版本与前提
- Kubernetes:v1.28+(
PodDisruptionBudget的policy/v1自 v1.21 稳定;UnhealthyPodEvictionPolicy自 v1.31 稳定并锁定) - 工具:
kubectl - 前提:理解 Deployment/StatefulSet 与节点维护流程
背景与问题
集群需要滚动升级内核、替换节点、缩容——这些会导致 Pod 被主动驱逐,称为自愿中断(voluntary disruption)。如果没有约束,一次性 drain 一个节点可能瞬间摘掉你的多副本服务半数实例,造成可用性骤降甚至击穿。PDB 就是用来给“同一组 Pod 在任意时刻最多能被中断几个”设上限的保险。
注意
PDB 只能挡自愿中断(drain、驱逐 API 触发的缩容)。它对非自愿中断无能为力:节点物理宕机、kubelet 失联、硬件故障、资源耗尽 OOM 等导致的不可用,PDB 一个都拦不住。不要把 PDB 当成“高可用保证”。
核心字段
yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: zk-pdb
spec:
maxUnavailable: 1
selector:
matchLabels:
app: zookeeper1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
.spec.selector:必填,标注受保护的 Pod 集合(应与被保护控制器的 selector 一致)。.spec.minAvailable:中断后仍必须保持可用的 Pod 数(绝对值或百分比)。.spec.maxUnavailable:允许同时不可用的 Pod 数(绝对值或百分比)。两者只能选其一。
maxUnavailable 通常更推荐:它能随控制器副本数变化自动适配,无需改 PDB 数值。
版本相关
policy/v1 中空 selector 会匹配命名空间内所有 Pod(与已移除的 policy/v1beta1 行为相反,后者匹配零个)。UnhealthyPodEvictionPolicy 自 v1.31 起稳定且无法关闭,用于控制对未 Ready Pod 的驱逐策略。
选用哪个值
| 场景 | 建议 |
|---|---|
| 无状态前端(容忍少量降容) | minAvailable: 90% 或 maxUnavailable: 10% |
| 多实例有状态(etcd/ZK,需保 quorum) | maxUnavailable: 1,或 minAvailable: quorum 大小 |
| 单实例有状态(不可中断) | maxUnavailable: 0(但 drain 会卡住,需线下协调后临时删 PDB) |
非健康 Pod 驱逐策略
UnhealthyPodEvictionPolicy 决定“Running 但还没 Ready”的 Pod 能否被驱逐:
IfHealthyBudget(默认):仅当整体未突破预算时才允许驱逐未 Ready Pod。问题是若应用卡在CrashLoopBackOff,drain 会被它永久阻塞。AlwaysAllow:未 Ready 的 Running Pod 无论如何可被驱逐,便于管理员清理“捣乱”的、受 PDB 保护却不健康的应用。
生产危险
设 maxUnavailable: 0 或 minAvailable: 100% 等于“零自愿中断”。此时 kubectl drain 永远无法完成,节点维护会卡死。单实例关键应用若用此策略,必须在线下协调(先删 PDB、维护、再重建 PDB),并明确告知运维流程。
生产实践
- PDB selector 与控制器 selector 精确一致:避免重叠 selector(多个 PDB 覆盖同一 Pod 时驱逐 API 会拒绝,导致 drain 卡住)。
- 任意工作负载的限制:对自定义控制器或无控制器的裸 Pod,只能用
minAvailable且只能用整数(不能用百分比),因为集群无法推导总数。 - 结合节点维护流程:drain 前先确认 PDB 不会卡住;对关键有状态服务提前规划 quorum 安全窗口。
- 用
UnhealthyPodEvictionPolicy: AlwaysAllow缓解因不健康 Pod 导致的 drain 死锁(v1.31+)。
建议
查看 PDB 状态:kubectl get pdb <name> -o yaml 看 .status.currentHealthy、.status.desiredHealthy、.status.disruptionsAllowed,可直观判断当前还能容忍多少中断。
故障排查
| 现象 | 原因 | 处理 |
|---|---|---|
kubectl drain 卡住 | PDB 不允许再驱逐(已达上限/0) | 查 kubectl get pdb 的 disruptionsAllowed |
| drain 被不健康 Pod 阻塞 | 默认 IfHealthyBudget + CrashLoop | 改 AlwaysAllow 或修复 Pod |
| 多个 PDB 报冲突 | selector 重叠 | 拆分/收敛 selector |
| PDB 不生效 | 用了已移除的 policy/v1beta1 或 selector 不匹配 | 改用 policy/v1,核对 label |
常见坑
- 误以为 PDB 防宕机——它只防“主动驱逐”,节点挂了它帮不上忙(真正的高可用靠副本数 + 跨可用区)。
- 百分比
maxUnavailable在副本数为 1 时仍允许 100% 不可用(向上取整),单副本别指望它。 - 忘记给 StatefulSet/Deployment 配 PDB,节点维护时副本被一次性大量摘走。
替代方案与权衡
- 跨可用区分布副本(topologySpreadConstraints)+ PDB 组合,是节点/可用区维护期保持可用的标准做法。
- 对于不能中断的单实例,PDB 不是答案;正确做法是线下维护流程 + 可能的主备切换。
FAQ
Q:PDB 能保证 Pod 一直可用吗? A:不能。它只限制自愿中断的并发度,对节点故障等非自愿中断无效,也不能保证“绝对不下线”。
Q:minAvailable 和 maxUnavailable 能同时用吗? A:不能,单个 PDB 中只能指定其一。
参考资料
- Specifying a Disruption Budget for your Application - Kubernetes 官方文档,访问日期:2026-10-08。
- Pod Disruptions 概念 - Kubernetes 官方文档,访问日期:2026-10-08。
- PodDisruptionBudget API (policy/v1) - Kubernetes 官方文档,访问日期:2026-10-08。