Safe Rollouts & PodDisruptionBudgets

Rolling updates protect you from bad deploys; PodDisruptionBudgets protect you from the cluster itself during node drains and upgrades.

You already know rolling updates replace Pods gradually. Two things separate a hobby rollout from a production one: tuning the surge so you never dip below capacity, and adding a PodDisruptionBudget (PDB) so voluntary disruptions cannot wipe out your app.

Voluntary vs involuntary disruption

A node crashing is involuntary — nothing can stop it. But draining a node for an upgrade, a cluster autoscaler scaling down, or kubectl drain are voluntary. A PDB tells Kubernetes: "you may evict my Pods for maintenance, but never take me below this floor." During a rolling node upgrade the eviction API respects your PDB and drains one node at a time only when it is safe.

minAvailable vs maxUnavailable

  • minAvailable: 2 — always keep at least 2 Pods serving.
  • maxUnavailable: 1 — never take more than 1 Pod down at once (scales naturally as you grow replicas).

The gotcha that pins a node forever

A PDB of minAvailable: 1 on a Deployment with a single replica means the node can never be drained — the eviction is refused forever and your cluster upgrade hangs. PDBs assume you run more than one replica. Combine the PDB with readiness gates so surging Pods actually pass health checks before old ones leave.

Example

Example · yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0      # never dip below full capacity
      maxSurge: 1            # bring up one extra, then retire an old one
  selector:
    matchLabels: { app: web }
  template:
    metadata:
      labels: { app: web }
    spec:
      containers:
        - name: web
          image: nginx:1.27
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-pdb
spec:
  maxUnavailable: 1          # node drains take at most 1 web Pod at a time
  selector:
    matchLabels: { app: web }

When to use it

  • A team creates a PodDisruptionBudget requiring minAvailable=2 so that rolling updates and node drains never take a three-replica service below two running pods.
  • An SRE uses maxSurge=2 and maxUnavailable=0 to get zero-downtime rolling updates by always bringing new pods up before old ones are removed.
  • A platform team uses Argo Rollouts for canary releases, sending 10% of traffic to the new version and watching error rates before promoting to 100%.

More examples

PodDisruptionBudget

Guarantees at least 2 API pods remain running during voluntary disruptions like Deployment rollouts or node drains.

Example · yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: api

Zero-downtime rolling update config

Configures maxUnavailable=0 so old pods are only removed after new pods pass readiness checks, achieving zero-downtime updates.

Example · yaml
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0   # Never remove old pod before new is ready
      maxSurge: 2         # Run 2 extra pods during the update

Verify rollout progress

Monitors a rolling update to completion and reviews the revision history to confirm the change cause annotation.

Example · bash
kubectl rollout status deployment/api
# Waiting for deployment api rollout to finish: 2 of 4 new replicas have been updated...
# deployment api successfully rolled out

kubectl rollout history deployment/api
# REVISION  CHANGE-CAUSE
# 1         Initial deploy
# 2         Update to v1.2.0

Discussion

  • Be the first to comment on this lesson.