Kubernetes drain 被 PDB 阻止:单副本与零中断预算无法自动腾出节点
kubectl drain 因单副本与零中断预算反复被拒绝时,核对 PDB 状态与就绪副本,选择受支持的冗余或停机流程,保留健康与不健康 Pod 的驱逐区别。
执行节点维护时,kubectl drain 不断重试,报 Cannot evict pod as it would violate the pod's disruption budget。应用只有一个就绪副本,PDB 却要求至少一个始终可用,或者规定 maxUnavailable: 0,那么这次驱逐就没有可用预算。
先核对实际匹配的 PDB 与就绪状态,再决定增加可用副本,还是接受一次计划停机。PDB 限制驱逐请求,不会为了 drain 自动创建备用 Pod;Deployment 的滚动更新策略也不能直接代替这个步骤。
查看预算保护的到底是哪批 Pod
以下为只读检查示例,命名空间、预算名与标签条件需换成实际值:
kubectl get pdb -n team-app
kubectl get pdb example-api -n team-app -o yaml
kubectl get pods -n team-app -l 'app=example-api' -o wide
kubectl get deployment example-api -n team-app -o yaml
对照 PDB 的完整 selector、控制器副本数、Pod 的 Ready 条件与所在节点。status.currentHealthy 是当前健康数量,desiredHealthy 是要求保留的健康数量,disruptionsAllowed 是当前允许的中断数量。配置刚变化时,还要等待控制器处理,核对状态是否对应当前 generation。
一个 Running 的 Pod 不一定已就绪,新副本尚未 Ready 时不能当作已有冗余。若预算选择了多余的应用、遗漏了目标 Pod,或与预期控制器的范围不一致,应先修正选择条件;不能为了让数值变大,把无关 Pod 加入同一预算。
本文采用 policy/v1 PDB。该版本的空 selector 会选择命名空间中的所有 Pod,与旧 policy/v1beta1 的空选择器行为不同,复制旧配置前要核对 API 版本。
单副本必须先选择可用性目标
只有一个健康副本时,minAvailable: 1 要求驱逐后仍有一个健康副本,因此不允许驱逐。增加一个副本,并等待它在可用节点上就绪,才可能为这个预算留出空间。
但增加副本前,要确认应用允许同时运行多个实例,且有足够资源与可挂载的存储。单写者、持有排他卷或无法并行执行的任务,不能为了 drain 直接扩成两个实例。如果新副本仍 Pending 或启动失败,先解决实际资源、存储或应用条件,不能继续驱逐唯一可用实例。
对于支持并行副本的无状态 Deployment,可以按已审定的副本配置增加冗余,并确保仍有允许中断的预算。以下是保护至少一个健康副本的 PDB 片段示例,不是扩容命令,也不适用于所有应用:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: example-api
namespace: team-app
spec:
minAvailable: 1
selector:
matchLabels:
app: example-api
如果当前使用的是 maxUnavailable: 0,即使扩容也仍不允许健康副本被中断。需要结合业务目标重新评估预算,例如是否允许一个实例暂时不可用,而不是只增加副本后重复原来的 drain。PDB 中只能选 minAvailable 或 maxUnavailable 一种约束,不要把两者一起填进示例。
不允许并行时,安排明确的停机窗口
单实例应用若没有可行的接管方式,要在维护前让负责人确认允许中断,保存原 PDB、工作负载与数据恢复安排,随后按变更流程临时放宽或移除相应预算。这样做会允许这段时间内的自愿中断,并不提供无停机保证;维护完成后应恢复审定预算。
如果 PDB 由 Helm、Operator 或其他配置管理器生成,手动改动可能被下一次协调覆盖。应找到真正的管理入口修改,避免一边删预算、一边被控制器重新创建。多实例有状态应用则需按应用的仲裁和副本安全要求设定,不能照搬无状态服务的“至少一个”。
不要把 kubectl delete pod、--disable-eviction 或删除全部 PDB 当作普通排查步骤。直接删除会绕过预算检查;drain --force 主要处理无控制器等条件,也不是解除 PDB 限制的开关。绕过保护可能使唯一实例中断,或让有状态集群跌破仲裁数量。
不健康 Pod 与健康副本是两个分支
若节点上阻塞的是 Running 但未 Ready 的 Pod,现代集群可评估 unhealthyPodEvictionPolicy: AlwaysAllow。该能力从 Kubernetes 1.31 起稳定,较旧版本需核对可用性。它允许某些不健康 Pod 在健康预算不足时也被驱逐,可能终止原本尚有机会恢复的实例,应按应用恢复能力决定。
这个选项不会允许随意驱逐一个健康的单副本 Pod,也不会自动使其他副本就绪。先确定阻塞 Pod 的状态,再判断是否适用,不把所有零预算都改成 AlwaysAllow。
重新维护前,核对实际预算已允许计划中的驱逐,或停机窗口与恢复方案已确认。drain 完成后检查应用副本、存储与业务入口;维护取消或节点恢复可用时,按节点运维流程决定是否 uncordon,使其重新可调度。恢复副本数或预算之前,也要确认没有把刚建立的可用冗余提前撤掉。


