Bound Voluntary Disruptions with Kubernetes PodDisruptionBudgets
Use one PodDisruptionBudget per deployment to limit how many pods can be unavailable during node drains and upgrades, then validate with kubectl.
07 Dec 2025, 12:00 UTC

Decision: bound voluntary evictions before you drain a node
When a node is cordoned and drained for maintenance or a cluster upgrade, Kubernetes evicts the pods running on it. If your deployment has several replicas on that node, they can all be evicted at the same time. A service expecting five replicas might briefly run on two, or fall below the number your load balancer requires.
The practical takeaway is to create one PodDisruptionBudget (PDB) per deployment. A PDB is a cluster object that limits voluntary disruptions—evictions started by an operator, automation, or a drain command. It does not protect against pod crashes, node failures, or zone outages.
Constraints before you apply a PDB
- Scope one PDB per deployment or selector. Overlapping PDBs can conflict and block each other.
- Choose
minAvailableormaxUnavailable, not both. - PDBs apply to voluntary evictions only. Involuntary loss, such as a node crash, is handled by replication and rescheduling, not by a PDB.
- This guide assumes Kubernetes 1.21 or later, where
policy/v1PodDisruptionBudget is generally available.
Supported options compared
| Option | What it bounds | Best suited for | Main risk |
|---|---|---|---|
| No PDB | No availability guarantee during drains | Workloads with ample spare replicas | Multiple pods can be evicted simultaneously |
minAvailable: N | At least N healthy pods stay available | Availability-critical services | Can block drains when replicas are scarce |
maxUnavailable: M | At most M pods are unavailable at once | Maintenance windows where brief reduction is acceptable | Allows more simultaneous unavailability than minAvailable |
Trade-offs
minAvailable favors availability. If you set it to two on a three-replica deployment, only one pod may be evicted at a time. The drain waits until a replacement is healthy before proceeding, which can stall node upgrades if capacity is tight.
maxUnavailable favors maintenance speed. Setting it to one on the same deployment also allows only one eviction at a time, but the semantic difference matters when replicas scale down: minAvailable tracks an absolute healthy count, while maxUnavailable tracks a ceiling on disruption.
Neither replaces readiness probes, graceful termination, or multi-zone placement. A PDB does not stop a pod from crashing, and it does not keep traffic flowing if the remaining pods are not ready.
Implementation: apply a PDB for a web deployment
This example bounds voluntary evictions for a deployment labeled app: web. Save it as web-pdb.yaml.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
namespace: default
spec:
minAvailable: 2
selector:
matchLabels:
app: web
Apply it from a workstation or CI runner with a valid kubeconfig:
kubectl apply -f web-pdb.yaml
Required permission: create or update poddisruptionbudgets in the target namespace. Cluster-admin is not required for a namespaced PDB, but draining a node usually is.
Validation: inspect the budget, then test a controlled drain
Check that the controller accepted the budget:
kubectl get pdb web-pdb -n default -o wide
Expected checks: ALLOWED-DISRUPTIONS should show the number of pods that may be evicted under the budget, and the healthy count should match your deployment's current replicas. If ALLOWED-DISRUPTIONS is zero, the PDB is blocking all voluntary evictions.
Inspect conditions and controller events:
kubectl describe pdb web-pdb -n default
Before draining, confirm the service endpoint count:
kubectl get endpoints web -n default
Choose a non-critical node and drain it. Replace <node-name> with the actual node:
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data --grace-period=30
Where to run: a machine with cluster-admin or node-drain permissions. Risk: the command evicts pods and marks the node unschedulable. If the PDB blocks the eviction, the drain command will wait or fail rather than violate the budget.
During the drain, verify that ready endpoints do not drop below your application's minimum. After the node is empty, bring it back:
kubectl uncordon <node-name>
uncordon is the recovery step: it allows the scheduler to place new pods on the node again. It does not undo evictions that already completed.
Limitations and how to check the result
- PDBs do not protect against node crashes, pod crashes, or zone outages. Pair them with replicas spread across zones and readiness probes.
- Setting
minAvailableequal to the replica count blocks every voluntary eviction and can stall cluster upgrades. - Eviction is not deletion. An evicted pod can remain in
Terminatinguntil its graceful termination period ends. Checkkubectl get endpoints, not just pod count, to confirm traffic capacity. - Cluster autoscaler scale-in may remove nodes even when PDBs exist, depending on your cloud provider integration. Verify autoscaler behavior before relying on PDBs during scale-in.
Practical result check: after the drain and uncordon, run kubectl get pdb web-pdb -n default -o wide again. The disruption budget should still show the same allowed disruptions, and the deployment should have returned to its desired replica count across schedulable nodes.
Rollback
Applying a PDB changes cluster state. If it blocks necessary maintenance, remove it:
kubectl delete pdb web-pdb -n default
Then drain or upgrade the node as needed, and reapply a less restrictive budget after reviewing replica counts and zone spread.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.