Pod Disruption and Cluster Autoscaling
The idea in one sentence
Section titled “The idea in one sentence”A PodDisruptionBudget limits how many replicas of a workload can be evicted at once during a voluntary disruption — it has no power at all over an involuntary one.
Voluntary versus involuntary disruptions
Section titled “Voluntary versus involuntary disruptions”Not every Pod loss is the same kind of event, and the distinction matters for what you can actually plan around.
- Voluntary disruptions are initiated deliberately by an operator or by automation, and can therefore be controlled, delayed, or rate-limited: a
kubectl drainfor a node upgrade,kubectl cordonfollowed by a rolling replacement, or Cluster Autoscaler removing an underutilized Node. - Involuntary disruptions are things nobody scheduled: a hardware failure, a kernel panic, a Node simply disappearing. There is no budget or setting that can prevent these — by the time they happen, the Node is already gone.
A PodDisruptionBudget only ever applies to the first category.
PodDisruptionBudget: a floor under voluntary evictions
Section titled “PodDisruptionBudget: a floor under voluntary evictions”A PodDisruptionBudget (policy/v1) declares either minAvailable or maxUnavailable for a set of Pods selected by label, and any voluntary eviction path — kubectl drain, the Eviction API, Cluster Autoscaler scaling down a Node — has to respect it.
apiVersion: policy/v1kind: PodDisruptionBudgetmetadata: name: web-app-pdbspec: minAvailable: 2 selector: matchLabels: app: web-app# kubectl drain blocks an eviction that would push availability below the PDBkubectl drain node-3 --ignore-daemonsets --delete-emptydir-data
kubectl get pdb web-app-pdbWith minAvailable: 2 on a Deployment running 3 replicas of web-app, a drain can only evict one Pod at a time — it waits for a replacement to become Ready on another Node before it is allowed to evict the next one. If a hardware failure takes out a Node that had two of those three replicas at once, the PDB does nothing to stop it; it was never built to. It protects against operations choosing to remove too much at once, not against the world doing it to you.
Cluster Autoscaler: adding and removing whole Nodes
Section titled “Cluster Autoscaler: adding and removing whole Nodes”Where HPA and VPA operate on Pods, Cluster Autoscaler operates one level up, on Nodes:
- It adds a Node when Pods are stuck
Pendingbecause no existing Node has enough free capacity to schedule them. - It removes a Node when that Node is significantly underutilized and every Pod on it could be rescheduled elsewhere — but it does this by draining the Node first, respecting any PodDisruptionBudgets along the way, exactly like a manual
kubectl drainwould.
# Pods stuck here because nothing fits them is the classic trigger for Cluster Autoscaler to add a Nodekubectl get pods --field-selector=status.phase=PendingA newer alternative worth knowing about is Karpenter, which skips the fixed node-group-template model entirely and provisions right-sized Nodes directly in response to unschedulable Pods, rather than scaling predefined groups up and down.
flowchart LR
drain["kubectl drain /\nCluster Autoscaler scale-down"] --> pdb{"PodDisruptionBudget\nminAvailable satisfied?"}
pdb -->|yes| evict["Evict one Pod at a time"]
pdb -->|no, would violate| wait["Wait before evicting more"]
evict --> empty["Node fully drained"]
empty --> remove["Node removed"]