Add a PodDisruptionBudget
A PodDisruptionBudget caps how many pods of one application can be down at once during a voluntary disruption, such as the node drains that happen on every Kubernetes upgrade and repair. Without one, a drain can evict your last pod and take the application offline. With one, the drain waits.
Get one wrong and it fails in two directions, both only visible mid-maintenance: a budget with no slack, or one too tight to satisfy.
What a PDB does and does not protect#
A PDB protects against voluntary disruptions: node drains, and anything else that asks Kubernetes to move a pod politely. It does not protect against a node crash or hardware failure, because nothing asks permission there. So a PDB is no substitute for running enough replicas: replicas are the floor, and the PDB just meters how fast a drain works through them.
minAvailable or maxUnavailable#
Pick exactly one:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web
spec:
maxUnavailable: 1 # or: minAvailable: 2
selector:
matchLabels:
app: web
maxUnavailable: 1 lets a drain take at most one pod at a time, the right default for a horizontally scaled service. minAvailable: 2 keeps a fixed number serving no matter what. Either way, match the number to your replica count: three replicas with maxUnavailable: 1 leaves two up throughout a rolling drain. And put the pods on different nodes, or the budget has nothing to spread. See topology spread .
Why ALLOWED DISRUPTIONS reads 0#
$ kubectl get pdb -n team-web web
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
web N/A 1 1 2m
ALLOWED DISRUPTIONS is how many pods may be evicted right now. If it reads 0 when you expect 1, a pod is currently not ready, so the budget has no slack to give. A drain then waits for that pod to recover. A 0 that never climbs means a pod is stuck. Fix its readiness before the next maintenance, not during it.
When a drain hangs and will not finish#
The other symptom looks like a hang. The drain grinds through the full 180 seconds, then evicts the pod anyway, because the budget was set too tight to ever satisfy. A drain waits only as long as nodeDrainTimeoutSeconds allows, a per-pool default of 180 seconds that is raisable per pool in the Cluster topology. After that it proceeds, and the pods on that node go with it. A PDB provides an orderly, one-at-a-time move, never an indefinite block.
Warning
A single-replica application with maxUnavailable: 0 (or minAvailable: 1) tells the drain it may never evict the pod. The drain waits out the whole timeout and takes the pod regardless. A PDB cannot make one replica highly available. Run two.
Stateful and quorum applications#
For a quorum-based application such as etcd or a database with a raft group, size the PDB so a drain never breaks quorum: with three members, maxUnavailable: 1. Pair it with one-per-node placement so no single drain can reach two members at once. See Keep stateful pods safe across node replacement .
Set resource requests and limits
Why the right default on this platform is a memory limit equal to the request, no CPU limit, and Burstable QoS.
Handle graceful shutdown
Finish in-flight requests when a node is replaced instead of dropping connections, by closing the endpoint-deregistration race with preStop and SIGTERM handling.