PodDisruptionBudget 限制一组选中 Pod 通过驱逐产生的中断。它可以协助维护期间保留服务容量或法定多数,但不能保证两者必然存在。保护取决于调用者使用 Eviction API、选择器选中正确成员,以及 Ready 条件真正反映应用所需能力。只建立一份对象而不核对这些前提,并不能让维护自动安全。

允许中断多少,应来自应用的失败模型。三成员多数派系统通常需要两个正常成员,但 Pod 就绪本身不证明成员身份、数据同步或成员之间的连通性。PDB 是应用健康检查与维护流程的补充,不会理解数据库协议,也不会自动纠正已经失去同步却仍报告 Ready 的副本。

保护边界在驱逐接口

节点崩溃、网络分区和节点压力驱逐,都不会被 PDB 阻止。但已经不可用的成员仍可能减少后续维护可使用的额度。直接删除 Pod 或整个工作负载会绕过预算,工作负载控制器正常滚动更新时的删除也不受它限制。因此“主动中断”不自动等于“必然经过预算保护”,必须看实际调用路径。

正常 drain 通过驱逐请求工作,在预算阻挡时重试;选择直接删除的调用方则绕过这层保护。依赖预算之前,应确认维护工具真实行为。Deployment 与 StatefulSet 的滚动可用性由各自更新策略控制,所以要协调发布和节点维护,不能假定一份 PDB 就会把所有会影响副本的操作自动串行化。

计算之前先弄清分母

minAvailable 与 maxUnavailable 只能选择其一。三个健康副本配整数 minAvailable 二,在普通稳定状态下允许驱逐一个健康成员。maxUnavailable 一则相对于预期规模表达允许量。currentHealthy 计算符合条件的 Ready Pod,并排除正在删除或已经记录待中断的成员;只处于 Running 阶段并不够,进程在跑也可能完全没有服务能力。

expectedPods 并不总等于控制器的期望 replicas。此次核对的 Kubernetes 1.34.0 实现中,整数 minAvailable 使用选中 Pod 对象的数量;百分比 minAvailable 与 maxUnavailable 则从所属控制器取得预期规模。因此它与 StatefulSet replicas 不一致,可能来自策略类型或协调时刻,不能直接断定选择器拼错。不同字段的分母需要按实际计算路径理解。

状态额度大体是 currentHealthy 减去 desiredHealthy,再把负数限制为零,同时还有安全检查与尚未完成驱逐的记账。解释状态时,也应核对 observedGeneration 与 conditions。零只是当前决定,不是诊断结论;它可能表示刻意严格的策略、已有不可用 Pod、正在处理的驱逐,或者控制器同步出现问题。看到一个零就删预算,会跳过最关键的风险判断。

百分比向上取整。七个副本的一半要求留下四个健康成员,而一个期望副本配百分之三十 maxUnavailable,仍允许失去唯一副本。写成百分比并不自动保证小规模工作负载安全。应检查应用可能达到的最小规模,包括自动扩缩与维护变化之后的状态,而不是只在当前五个副本时算一次就永远沿用。

不健康策略改变排空行为

默认 IfHealthyBudget 下,Running 但未就绪的 Pod,在 currentHealthy 至少等于 desiredHealthy 时可以驱逐。如果应用已经低于这个门槛,该 Pod 可能阻挡排空,让它有机会恢复。预算并不是看不见它,而是根据不健康状态与整组健康数量做了保守选择。CrashLoopBackOff 或错误就绪探针因此可能让维护长时间等待。

AlwaysAllow 允许这些运行中但不健康的 Pod 不受该健康门槛限制而被驱逐,不表示健康 Pod 可以无限制删除。选择策略时要同时考虑恢复与维护,尤其要判断替代 Pod 是否也会被同一个错误探针卡住。改变不健康驱逐策略可以解除某类阻塞,却不会修复造成不健康的应用问题。

三个健康投票成员允许一次中断,是常见的保守选择。成员数量变化时,应重新计算法定多数与可用性;允许一个并不适合所有规模或成员变更协议。下一次健康成员驱逐可能需要等待替代成员真正就绪,不能只看到新 Pod 出现就继续操作,更不能忽视数据同步和重新加入集群所需时间。

坏掉的样子

最小健康数等于当前全部可用副本,可以是刻意阻止健康驱逐的设计,不一定属于配置错误。应记录维护如何获得余量。drain 很慢时,先看替代副本调度、就绪、既有中断与应用负责人的可用性要求,不要单纯因为操作卡住就移除预算,把原本需要决策的停机风险变成默默发生。

什么都没有匹配到的选择器保护不了任何东西。相反,policy/v1 中空选择器会匹配命名空间的所有 Pod,可能意外扩大范围。应把完整选择器,包括 matchExpressions,与真实标签和所属控制器对照。单独一个 expectedPods 数字,不能证明选中了正确应用;范围过窄和范围过宽都可能破坏原本的维护意图。

快速验证

在指定的只读上下文和命名空间中检查已有对象。以下原命令保持不变,本轮没有在真实集群重新运行。

kubectl get pdb -A -o custom-columns=NAME:.metadata.name,MIN:.spec.minAvailable,MAX:.spec.maxUnavailable,EXPECTED:.status.expectedPods,HEALTHY:.status.currentHealthy,ALLOWED:.status.disruptionsAllowed
kubectl get pdb zk-pdb -o jsonpath='{.spec.selector.matchLabels}{"\n"}'
kubectl get statefulset zookeeper -o jsonpath='{.spec.replicas}{"\n"}'
kubectl get pods -l app=zookeeper --field-selector=status.phase=Running --no-headers | wc -l

最后一条统计 Running Pod,不是 Ready Pod。选择器命令只显示 matchLabels,因此可能遗漏 matchExpressions。这些输出可以提供初步线索,但在判定 HEALTHY 或 EXPECTED 异常之前,需要阅读完整 PDB 与 Pod 对象。额度为零不会自动说明原因;额度为正也不证明应用层的法定多数一定能承受下一次驱逐,仍须结合真实成员健康。

来源