Pod Disruption Budget in Kubernetes: plan maintenance without dropping availability


We had a stateful application that needed at least two replicas to serve traffic safely. During maintenance windows, we would drain nodes, patch kernels, or reboot worker nodes. In the middle of those operations, Kubernetes sometimes terminated both replicas at once or treated an eviction as if it were normal scaling. The result was intermittent downtime and failed deployments.
That changed when I introduced a PDB and started treating voluntary disruptions as a first-class part of our deployment strategy.
My app was deployed with a normal Deployment and a service selector. I relied on replica counts and maxUnavailable from my rolling update strategy.
The problem was this:
In short, Kubernetes was doing its job, but I had not told it which disruptions were safe.
I would run kubectl drain node-1 --ignore-daemonsets --delete-emptydir-data and assume the rest of the deployment would stay healthy.
Instead:
node-1node-2This is exactly what Pod Disruption Budget prevents.
I created a PodDisruptionBudget object and attached it to my application by using the same pod labels.
Here is the manifest I used:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: webapp-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: webapp
That simple change created a cluster-level guardrail.
It also changed the way I thought about maintenance. A PDB is not a general availability promise for failures; it is a way to prepare for planned, voluntary disruptions before they happen.
PodDisruptionBudget controls voluntary disruptions:
kubectl drainIt does not block a pod from being killed by a node failure. It only protects the number of healthy pods during planned and controllable disruptions.
For lower-traffic services, I also use maxUnavailable:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: backend-pdb
spec:
maxUnavailable: 1
selector:
matchLabels:
app: backend
This says: "I can tolerate one pod being unavailable during a voluntary disruption, but no more."
You can specify either minAvailable or maxUnavailable in a PDB, but not both in the same object. The first expresses how many pods must remain healthy; the second expresses how many may be disrupted.
A PDB should be used when you want to plan for voluntary evictions ahead of time. It is a simple contract that says: “During planned maintenance, this many pods should remain available” or “this many pods may be disrupted.”
That planning is what makes disruptions predictable.
Stateless frontends
minAvailable: 90%.Single-instance stateful application
maxUnavailable: 0 and treat the PDB as a manual lock. The operator should contact the app owner before starting maintenance, delete the PDB to allow disruption, then recreate it afterwards.Some workloads are fine with temporary full downtime; for those cases, skip the PDB and handle the disruption outside Kubernetes.
After adding the PDB, the cluster started respecting a minimum availability budget for my application. The direct benefits were:
If I run kubectl drain now and the PDB cannot be honored, Kubernetes refuses the disruption until I either patch a node, scale the app, or change the PDB.
That means we avoid the worst-case scenario where two replicas are evicted at once and user traffic gets dropped.
Think of a PDB as a traffic signal for pod eviction.
It tracks two numbers:
CurrentHealthy: how many pods are currently ready and availableDesiredHealthy: how many pods must stay available according to minAvailable or maxUnavailableThe controller then computes AllowedDisruptions:
minAvailable, it guarantees that number of pods stays healthymaxUnavailable, it allows that many pods to be unavailableThe PDB is applied to the pod collection, so the values depend on the total replicas in the workload.
minAvailable with a number means exactly that many pods must stay ready.minAvailable: 90% means ceil(0.9 * replicas) pods must stay ready.maxUnavailable: 1 means exactly one pod may be disrupted at a time.maxUnavailable: 20% means floor(0.2 * replicas) pods may be unavailable.For example:
replicas = 5 minAvailable = 4 allowed disruptions = replicas - minAvailable = 5 - 4 = 1 minimum healthy pods = minAvailable = 4
Similarly
replicas = 5 maxUnavailable = 1 allowed disruptions = maxUnavailable = 1 minimum healthy pods = replicas - maxUnavailable = 5 - 1 = 4
If the cluster cannot keep enough healthy pods, voluntary evictions are blocked.
But a PDB is not a guarantee that pods will always stay up. If a node crashes, a pod is killed by OOM, or some other failure happens, the number of available pods can still drop below the budget. That is why PDB is described as protection for planned, voluntary disruption only.
Also, if you set maxUnavailable: 0 or minAvailable to 100% (or equal to the replica count), you are telling Kubernetes that you allow zero voluntary evictions. That means a node drain with one of those pods on it can hang forever until you remove or relax the budget. This is valid behavior: the drain is blocked because the PDB says the pod cannot be disrupted.
This is what makes planned maintenance safe.
kubectl get pdbAfter applying the PDB, I can inspect it with:
kubectl get pdb kubectl describe pdb webapp-pdb
A healthy PDB shows output like this:
Current Healthy: 3Desired Healthy: 2Allowed Disruptions: 1That tells you exactly whether the budget is being respected before you take an action.
Before PDB:
kubectl drain would do the right thingAfter PDB:
My team now uses PDBs as part of every critical production workload manifest. It is one of the first things we add after labels, service selectors, and resource requests.
There are a few easy ways to misconfigure PDBs:
selector so the PDB does not match the intended podsminAvailable too high for your replica countA good rule of thumb is:
minAvailable: N for critical workloads where N replicas must stay upmaxUnavailable: M for workloads where up to M pods can be offline safelyPodDisruptionBudgets are especially valuable for:
For low-priority batch jobs, a PDB may not be necessary. But for anything that must keep serving traffic while cluster ops happen, it is a powerful guardrail.
Pod Disruption Budgets are not magic, but they are the missing piece between "pods exist" and "pods stay healthy during maintenance." They turn implicit availability expectations into explicit rules that Kubernetes can enforce.
If you want your cluster to behave reliably during planned disruptions, start with a PDB, keep your selector correct, and choose the budget that matches your availability needs.
Once I did that, maintenance stopped being a gamble and became a predictable part of our deployment lifecycle.