Control Voluntary Pod Evictions with Kubernetes PodDisruptionBudgets
Use a PodDisruptionBudget to limit how many matching pods can be evicted at once during node drains and autoscaler scale-in.
16 Jul 2026, 18:23 UTC

The problem: a node drain can empty your workload
When you run kubectl drain on a node, the API server attempts to evict every pod scheduled there. If your deployment runs three replicas and all three land on that node, a routine maintenance drain can take the service offline until new pods start elsewhere. A PodDisruptionBudget (PDB) prevents that by telling the API server how many matching pods must stay available during voluntary disruptions.
Useful takeaway: a PDB does not stop pod failures, but it caps voluntary evictions so node maintenance, cluster autoscaler scale-in, and managed node upgrades cannot remove more replicas than you allow at one time.
How the budget works
A PDB is a namespace-scoped object in the policy/v1 API. It uses a label selector to find pods and either minAvailable or maxUnavailable to bound evictions:
minAvailable: the minimum number of selected pods that must remain available. Only ready, healthy pods count.maxUnavailable: the maximum number of selected pods that may be unavailable at once.
If you have three replicas and set minAvailable: 2, only one healthy pod can be evicted at a time. maxUnavailable: 1 expresses the same limit. The API server enforces this for voluntary disruptions initiated by kubectl drain, cluster autoscaler scale-in, and managed node pool upgrades. Involuntary events—kernel panics, power loss, or container runtime crashes—are not constrained.
Worked configuration
This example assumes a cluster running Kubernetes 1.21 or later, where policy/v1 is generally available. Confirm the API group is enabled:
kubectl api-versions | grep policy/v1
Run this in a terminal whose kubeconfig points to the target cluster. You need permission to create poddisruptionbudgets in the target namespace, typically granted to cluster administrators or to a service account with create access on that resource.
First, a sample deployment with three replicas:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: example.com/api:1.0
Now the PodDisruptionBudget. The selector must match the deployment’s pod labels:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-pdb
namespace: default
spec:
minAvailable: 2
selector:
matchLabels:
app: api
Apply both manifests:
kubectl apply -f deployment.yaml
kubectl apply -f pdb.yaml
To observe the effect, drain a node where one replica runs. Replace <node-name> with the actual node:
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
Required permissions: your user or service account needs the eviction subresource permission on pods, plus get and list on nodes. Without it, the drain fails with an authorization error rather than a budget error.
Expected behavior: the first eviction succeeds because two pods remain available. A second eviction for another app: api pod is rejected until a replacement pod becomes ready. You can check the current state with:
kubectl get poddisruptionbudgets -n default
kubectl describe poddisruptionbudget api-pdb -n default
Look for the ALLOWED DISRUPTIONS field and the count of healthy pods. If the budget blocks an eviction, kubectl drain pauses and reports that the PodDisruptionBudget prevents eviction. This is not a failure of the command; it is the budget working as intended.
Risk: if you set minAvailable equal to the replica count, all voluntary drains are blocked. Node repairs and autoscaler scale-in stall until you lower the budget or remove the PDB.
Limits and common mistakes
- Voluntary disruptions only. A PDB does not protect against involuntary node loss. Use multi-zone replica placement and sufficient replica headroom for that.
- Healthy pods only. A pod in
CrashLoopBackOffor stuckTerminatingmay not count as available, which tightens the effective budget and can block drains unexpectedly. - Overlapping budgets intersect. If two PDBs select the same pod, the most restrictive one governs. This can make the effective limit smaller than either manifest suggests.
- Permissive budgets are dangerous.
minAvailable: 0ormaxUnavailable: 100%permits unrestricted voluntary eviction and can empty a workload during maintenance.
Verification and rollback
After applying the PDB, confirm it is tracked by the API server:
kubectl get poddisruptionbudgets --all-namespaces
During a test drain, watch the deployment:
kubectl get deployment api -n default -w
If the drain blocks and you need to proceed with maintenance, remove the budget:
kubectl delete poddisruptionbudget api-pdb -n default
Because applying or deleting a PDB changes cluster state, this deletion is the rollback. Recreate it after maintenance completes.
Practical check: run kubectl describe poddisruptionbudget api-pdb -n default and verify ALLOWED DISRUPTIONS matches your calculation. If the number is lower than expected, inspect the selected pods for ones that are not ready.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.