KubernetesXXXIV · PodDisruptionBudgetsPodDisruptionBudgets
maxUnavailable — the ceiling on unavailable Pods
What you'll learn
- Specify a maxUnavailable PDB with integer or percentage values
- Calculate the PDB effect for a given replica count
- Identify the failure modes of a too-restrictive maxUnavailable
- Design a maxUnavailable that allows the drain while protecting the workload
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
The maxUnavailable field is the PDB’s ceiling on the
number of Pods that can be unavailable at any time. The
eviction is rejected if the eviction would increase the
unavailable Pods above the ceiling. This lesson walks
the field’s semantics, the integer and percentage
values, the eviction logic, and the design patterns.
The maxUnavailable field
flowchart TD
A["Deployment with 5 replicas"] --> B{"maxUnavailable: 1"}
B --> C["Available: 5, Unavailable: 0"]
C -->|Evict 1| D["Available: 4, Unavailable: 1"]
D -->|Evict 1 more| E["Unavailable: 2"]
E -->|REJECTED| F["2 greater than 1"]
The PDB’s maxUnavailable field:
The PDB’s maxUnavailable field:
spec:
maxUnavailable: 1
The field is the maximum number of Pods that can be unavailable at any time. The eviction is rejected if the eviction would increase the unavailable Pods above the field.
The field is an integer or a percentage string:
spec:
maxUnavailable: 1 # absolute number
maxUnavailable: "20%" # percentage of the replica count
The percentage is computed against the PDB’s
expectedPods. The PDB’s expectedPods is the total
number of Pods that the PDB applies to.
The maxUnavailable’s semantics
The maxUnavailable field is the ceiling on the unavailable Pods. The unavailable Pods are the Pods that are not running (Pending, Failed, evicted).
For a Deployment with 5 replicas:
maxUnavailable: 1
expectedPods: 5
availablePods: 5
unavailablePods: 0
disruptionsAllowed: 1 (min(unavailablePods, maxUnavailable))
After evicting 1 Pod:
unavailablePods: 1
disruptionsAllowed: 0 (1 - 1)
After evicting 1 more Pod:
eviction rejected (2 > 1)
The disruptionsAllowed is the number of Pods that
can be evicted. The disruptionsAllowed is the
smaller of the unavailable Pods and the maxUnavailable.
The maxUnavailable’s calculation
The maxUnavailable’s calculation:
disruptionsAllowed = max(0, min(unavailablePods, maxUnavailable))
The disruptionsAllowed is the number of Pods that
can be evicted without violating the PDB. The
disruptionsAllowed is zero when the unavailable Pods
is at the maxUnavailable.
The PDB’s controller recalculates the disruptionsAllowed
on every Pod status change. The recalculation is the
PDB’s protection.
The maxUnavailable’s percentage value
The maxUnavailable’s percentage value:
spec:
maxUnavailable: "20%"
The percentage is computed against the expectedPods:
maxUnavailable (absolute) = ceiling(expectedPods * 20 / 100)
For 5 replicas and 20%: maxUnavailable = ceiling(1.0) = 1.
The percentage is rounded up. The PDB’s maxUnavailable
is the ceiling of the percentage.
The percentage is the cluster’s protection against the
workload’s scale. A Deployment with 10 replicas and
maxUnavailable: 20% has maxUnavailable: 2. The
eviction is allowed until 2 Pods are unavailable.
The maxUnavailable’s failure modes
The maxUnavailable’s failure modes:
| Failure | Symptom | Root cause |
|---|---|---|
| Drain rejects | PDB rejects eviction | maxUnavailable too low |
| Eviction rejected | PDB rejects eviction | maxUnavailable too low |
| PDB not enforced | maxUnavailable is not applied | PDB missing, selector wrong |
The diagnostic:
# Substitute your own value before running:
PDB=checkout-api-pdb
kubectl describe pdb "$PDB"
The PDB’s status shows the current state. The fix is to investigate the PDB’s configuration.
The maxUnavailable’s design
The maxUnavailable’s design should be:
- Permissive enough to allow the drain. The
maxUnavailableshould be one. - Restrictive enough to protect the workload. The
maxUnavailableshould be the maximum number of Pods that can be unavailable.
For a Deployment with 3 replicas:
spec:
maxUnavailable: 1
The maxUnavailable: 1 allows 1 Pod to be evicted. The
drain is allowed; the workload is protected.
For a Deployment with 5 replicas:
spec:
maxUnavailable: 1
The maxUnavailable: 1 allows 1 Pod to be evicted. The
ceiling does not scale with the replica count, so a
5-replica drain still proceeds one Pod at a time.
The maxUnavailable’s design is the operator’s responsibility. The production rule is to design the maxUnavailable to allow the drain while protecting the workload.
The maxUnavailable’s anti-patterns
The maxUnavailable’s anti-patterns:
- maxUnavailable: 0. The
maxUnavailablethat requires no Pods to be unavailable is a PDB that blocks the drain. - maxUnavailable: 100%. The
maxUnavailablethat allows all Pods to be unavailable is a PDB that does not protect the workload. - maxUnavailable: 1. The standard pattern. The PDB allows the drain.
The maxUnavailable’s design is the operator’s
responsibility. A maxUnavailable: 0 and a
minAvailable: 100% are the same PDB written two ways;
both hold ALLOWED DISRUPTIONS at 0.
The minAvailable vs maxUnavailable choice
The choice between minAvailable and maxUnavailable:
| Field | Use case |
|---|---|
minAvailable | The workload’s minimum number of Pods is fixed (e.g., 3 replicas) |
maxUnavailable | The workload’s maximum number of unavailable Pods is fixed (e.g., 1) |
The minAvailable is the floor; the maxUnavailable
is the ceiling. The two are semantically equivalent
when the replica count is fixed.
The production rule is to choose the field that matches
the workload’s redundancy model. A workload that is
designed to be 3-of-5 might use minAvailable: 3. A
workload that is designed to lose 1 might use
maxUnavailable: 1.
The maxUnavailable’s interaction with the deployment
The maxUnavailable’s interaction with the deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: billing
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
selector:
matchLabels:
app: billing
template:
metadata:
labels:
app: billing
spec:
containers:
- name: billing
image: registry.example.com/billing:1.0.0
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: billing-pdb
spec:
maxUnavailable: 1
selector:
matchLabels:
app: billing
The PDB’s selector matches the Deployment’s Pods. The
PDB’s maxUnavailable: 1 matches the Deployment’s
maxUnavailable: 1.
The maxUnavailable’s monitoring
The maxUnavailable’s monitoring:
kubectl get pdb -A
The output shows the PDB’s status. The PDB’s status shows the current allowed disruptions.
The PDB’s metrics:
promtool query instant http://prometheus:9090 \
'kube_poddisruptionbudget_status{condition="Disallowed"}'
The metric returns the number of Pods that cannot be evicted. The operator should monitor the metric and alert on the threshold.
Quiz
Knowledge check · 4 questions
Q1. When is `maxUnavailable` a better choice than `minAvailable` in a PDB?
Q2. `minAvailable` and `maxUnavailable` are alternatives; a single PDB sets one or the other.
Q3. Unblock a fleet-wide node rotation stopped by a ceiling that permits no disruption at all.
A rotation of all 60 nodes stalled on the first one. `kubectl drain node-1 --ignore-daemonsets` loops on `ingress-nginx/ingress-nginx-controller-5c9d8-k4wpt` with `Cannot evict pod as it would violate the pod's disruption budget.` `kubectl get pdb -n ingress-nginx` shows `ingress-nginx MAX UNAVAILABLE 0 ALLOWED DISRUPTIONS 0 EXPECTED PODS 6 CURRENT HEALTHY 6`. All six controller Pods are Ready and serving. The PDB was written during an incident review with the note that the ingress must never lose a replica.
Q4. For a Deployment with 12 replicas and a PDB of `maxUnavailable: "25%"`, what value does the controller compute and what is `desiredHealthy`, and what does `maxUnavailable: 0` mean for eviction?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- The maxUnavailable is the ceiling on the unavailable Pods. The eviction is rejected if the eviction would increase the unavailable Pods above the ceiling.
- Set the maxUnavailable to one. The PDB allows the drain while protecting the workload.
- Choose the field that matches the workload’s
redundancy model. The
minAvailableis the floor; themaxUnavailableis the ceiling. - Audit the PDB at every release. The PDB’s configuration should be version-controlled; the audit catches the failures.
- Monitor the PDB’s status. The PDB’s
disruptionsAllowedis the operator’s primary signal. - Document the PDB’s intent. A PDB that does not have a documented intent is a PDB that does not protect the workload.
- Test the PDB in non-production. A staging cluster that mirrors production is the right place to test the PDB.