PodDisruptionBudgets with maxUnavailable set to 0 or 0%
What does ZopNight detect here?
ZopNight flags any PodDisruptionBudget on EKS, GKE or AKS whose `spec.maxUnavailable` is `0` or `0%`. The Kubernetes API reference gives 0 as the value that prevents all voluntary evictions, so a drain of any node hosting one of the selected pods never completes, whatever state the pods are in.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1748 · RC-1848 · RC-1948 |
| Category | reliability |
| Severity | high |
| Metric | spec.maxUnavailable |
| Threshold | 0 or 0% |
| Source | ZopNight |
| Permissions used | list poddisruptionbudgets.policy |
Where it applies
Zero unavailable means zero evictions
maxUnavailable sets how many selected pods may be down after an eviction. The
PodDisruptionBudget API reference
uses 0 as its own example of a value that prevents all voluntary evictions. The
disruption budget task page
confirms that 0 and 0% both require zero voluntary evictions, and that a node running one of
those pods cannot be drained: the drain simply never finishes. Kubernetes permits the setting,
but every routine operation that moves pods, from node upgrades to scale-downs, will wait on it.
The value is often written with good intent, to protect a quorum or a stateful primary. The budget cannot tell a planned upgrade from an accident, though, so it blocks both.
Listing budgets that forbid eviction
kubectl get poddisruptionbudgets -A -o json | jq -r ' .items[] | select(.spec.maxUnavailable == 0 or .spec.maxUnavailable == "0%") | "\(.metadata.namespace)/\(.metadata.name) maxUnavailable=\(.spec.maxUnavailable)"'A spec check, independent of pod health
ZopNight reads the maxUnavailable value recorded for each budget and fires when it is exactly
0 or 0%. Nothing else is weighed: not the pod count, not pod health, not the budget’s age. A
budget that uses minAvailable instead, or sets no maxUnavailable, is outside this check.
Changing the value to anything above zero clears the finding on the next evaluation.
How it relates to the other budget findings
Because this is a spec check, it catches the problem before any drain fails. The live counterpart,
PDB blocks all voluntary disruptions,
reads the status and also fires when a minAvailable budget has no room left, so a budget with
maxUnavailable: 0 and running pods usually appears in both. Budgets whose selector finds no
pods are reported by
PDB matches no pods.
An operational cost, not a billing one
No saving is calculated. The consequence is maintenance that cannot finish: node pools stuck on old versions and nodes kept alive only because their pods cannot leave.
Allowing one pod out at a time
- Decide how many replicas the application can lose briefly. For most services with three or more replicas, one is safe.
- Set
maxUnavailable: 1, or a percentage. Kubernetes rounds amaxUnavailablepercentage up, so even10%of three pods allows one eviction. - Apply the change with
kubectl applyand confirmstatus.disruptionsAllowedis now at least 1. - If the workload truly must never be evicted, document the exception and plan how its nodes will be maintained by hand.