PDB不能防止滚动更新期间不可用,但可阻止kubectl drain等自愿中断导致的过量驱逐;minAvailable与maxUnavailable互斥,因二者语义等价且API层强制二选一以避免冲突。

直接说结论:PDB 不能防止滚动更新期间的不可用,但能阻止 kubectl drain 类自愿中断导致的过量驱逐;它只在节点排空、手动删除控制器等场景生效,对 Deployment 自身的滚动更新逻辑无干预。
为什么 minAvailable 和 maxUnavailable 不能混用
PDB 的 spec 中这两个字段是互斥的,API 层会拒绝同时设置它们的请求。Kubernetes 认为「最少留几个」和「最多删几个」是同一约束的两种表达方式,强制二选一可避免语义冲突。
- 设
minAvailable: 2表示:只要当前匹配的 Pod 数 ≥ 2,驱逐就允许继续;若只剩 1 个,kubectl drain就会卡住并报错Cannot evict pod as it would violate the disruption budget - 设
maxUnavailable: "25%"表示:允许最多 25% 的 Pod 同时不可用;若副本数是 4,则最多 1 个被驱逐;若副本数变为 3,该值会动态向下取整为 0(即不允许任何驱逐) - 百分比写法必须带引号,否则 YAML 解析器可能误判为浮点数 ——
maxUnavailable: 25%是非法的,正确写法是maxUnavailable: "25%"
Python Client 创建 PDB 时最常踩的三个坑
用 kubernetes.client.PolicyV1Api 创建 PDB 时,错误往往不出现在逻辑上,而出现在元数据或版本细节里。
-
api_version必须是"policy/v1":Kubernetes 1.21+ 已废弃policy/v1beta1,用错会导致404 Not Found或Invalid value: "policy/v1beta1" -
selector必须严格匹配目标 Deployment 的.spec.selector.match_labels:漏掉一个 label、大小写不一致、或用了match_expressions(PDB 不支持),都会让 PDB “看不见”任何 Pod,status.currentHealthy始终为 0 - 命名空间不能靠默认:即使你在
defaultnamespace 下运行脚本,也必须显式传入namespace="default"到create_namespaced_pod_disruption_budget(),否则会抛TypeError: create_namespaced_pod_disruption_budget() missing 1 required positional argument: 'namespace'
kubectl drain 卡住时,怎么快速定位是不是 PDB 拦截的
当 kubectl drain node-xx 长时间挂起,第一反应不该是重启命令,而是查 PDB 状态和实际 Pod 分布。
- 运行
kubectl get pdb -A -o wide,确认是否有 PDB 覆盖该节点上的 Pod 标签;注意SELECTOR列是否匹配 - 运行
kubectl get pods -A --field-selector spec.nodeName=node-xx,统计该节点上实际运行的、带匹配 label 的 Pod 数 - 运行
kubectl describe pdb <name> -n <ns></ns></name>,重点看Status区域:currentHealthy(当前健康数)、desiredHealthy(按预算算出的最小需求数)、disruptionsAllowed(当前还能驱逐几个)—— 如果disruptionsAllowed是 0,就是它拦的 - 临时绕过(仅调试):加
--ignore-daemonsets --delete-emptydir-data参数,但注意这不绕过 PDB;真要跳过得加--force,不过这会无视所有 PDB,生产环境禁用
真正容易被忽略的是:PDB 对 Pod 的“健康”判断依赖于 Ready condition。如果应用容器启动了但 readiness probe 还没通过,那个 Pod 就不算 currentHealthy,会被计入不可用数 —— 所以别只盯 replica 数,得确保 readiness probe 设置合理且稳定。


















