Kubernetes PodDisruptionBudget Generator
Build a PodDisruptionBudget and find out whether it can actually be satisfied. Give it your replica count and it works out how many pods are evictable, and says so plainly when the answer is none.
poddisruptionbudget.yaml
updates as you type Common mistakes
These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.
Setting minAvailable equal to the replica count
No pod can ever be evicted, so a node drain hangs indefinitely and the cluster cannot be upgraded.
Instead:Leave at least one pod of headroom, or use maxUnavailable: 1.
Creating a PDB for a single-replica deployment
minAvailable: 1 on one replica blocks every voluntary eviction permanently.
Instead:Scale to two, or accept the disruption and skip the PDB.
Expecting a PDB to prevent all disruption
It only covers voluntary evictions. A node failure, an OOM kill or a delete ignores it entirely.
Instead:It is a drain guard, not an availability guarantee.
What a PodDisruptionBudget does, and what it does not
A PDB constrains voluntary disruption only. That means the eviction API, which is what kubectl drain and the cluster autoscaler use. A node crashing, a kubelet dying or a container being OOMKilled ignores it entirely. It is an upgrade-safety object, not an availability guarantee, and reading it as the latter is how people end up with one that cannot be satisfied.
The deadlock: a budget nothing can ever satisfy
If the budget requires every replica to stay up, no pod can ever be evicted, so no node running one can ever be drained. kubectl drain does not fail: it retries, indefinitely, printing that it cannot evict. A cluster upgrade stops on that node and a scale-down never completes. The object applies cleanly and the problem surfaces weeks later, to somebody else.
replicas: 3, minAvailable: 3 -> 0 evictable
replicas: 3, maxUnavailable: 0 -> 0 evictable
replicas: 1, minAvailable: 1 -> 0 evictable
kubectl drain node-1
evicting pod default/api-7d9f
error when evicting pod "api-7d9f" (will retry):
Cannot evict pod as it would violate the budget.
... forever Percentages round towards availability, both ways
minAvailable percentages round up and maxUnavailable percentages round down. Both directions make the budget stricter than the arithmetic suggests, which is the safe choice and a surprise if you sized it by dividing.
replicas: 3
minAvailable: 50% -> ceil(1.5) = 2 must stay up
so only 1 may be evicted
maxUnavailable: 50% -> floor(1.5) = 1 may go down
same result, different route
replicas: 4
minAvailable: 75% -> ceil(3) = 3 must stay up A crash-looping pod can block its own replacement
By default a pod that is running but not Ready cannot be evicted while the budget is unmet, because evicting it would take the count further below the minimum. So a workload stuck in CrashLoopBackOff wedges the drain of the node it is on, which is exactly the moment you want to move it. unhealthyPodEvictionPolicy: AlwaysAllow fixes this, and needs Kubernetes 1.27.
spec:
minAvailable: 2
unhealthyPodEvictionPolicy: AlwaysAllow
# IfHealthyBudget (the default):
# unready pods are protected too, so a broken
# deployment blocks node maintenance
# AlwaysAllow:
# unready pods can always be evicted, because
# they were not serving traffic anyway It matches pod labels, and an empty selector is not empty
The selector must match spec.template.metadata.labels on the workload, not the Deployment's own metadata.labels, which are usually written to look identical. A PDB matching nothing is created without complaint and protects nothing. An empty selector is the opposite problem: under policy/v1 it matches every pod in the namespace, where under the old policy/v1beta1 it matched none.
kubectl get pdb
NAME MIN AVAILABLE ALLOWED DISRUPTIONS AGE
api-pdb 2 0 5m
^ this is the number
that tells you it is
about to block a drain
# ALLOWED DISRUPTIONS of 0 on a healthy workload
# means the budget is already unsatisfiable.