Skip to main content
RunBook Academy

KubernetesXXXIV · PodDisruptionBudgetsPodDisruptionBudgets

maxUnavailable — the ceiling on unavailable Pods

Advanced⏱ ~16 minkubectl

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

Not yet marked complete on this device.

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:

FailureSymptomRoot cause
Drain rejectsPDB rejects evictionmaxUnavailable too low
Eviction rejectedPDB rejects evictionmaxUnavailable too low
PDB not enforcedmaxUnavailable is not appliedPDB 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 maxUnavailable should be one.
  • Restrictive enough to protect the workload. The maxUnavailable should 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 maxUnavailable that requires no Pods to be unavailable is a PDB that blocks the drain.
  • maxUnavailable: 100%. The maxUnavailable that 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:

FieldUse case
minAvailableThe workload’s minimum number of Pods is fixed (e.g., 3 replicas)
maxUnavailableThe 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

  1. Q1. When is `maxUnavailable` a better choice than `minAvailable` in a PDB?

  2. Q2. `minAvailable` and `maxUnavailable` are alternatives; a single PDB sets one or the other.

  3. 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.

  4. 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 minAvailable is the floor; the maxUnavailable is 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 disruptionsAllowed is 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.