Skip to main content
RunBook Academy

KubernetesXVI · Deployment StrategiesDeployment strategies

Rolling Update — maxSurge, maxUnavailable, and the math of a safe rollout

Advanced⏱ ~18 minkubectlkubeadm

What you'll learn

  • Describe how RollingUpdate replaces Pods in a Deployment with a new template
  • Reason about maxSurge and maxUnavailable as integer or percentage values, and the trade-off they encode
  • Calculate the worst-case Pod count during a rollout for a given replica count and burst settings
  • Identify the failure modes that turn a rolling update into an outage (failed readiness, image pull, shared dependencies)

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.

RollingUpdate is the default Deployment strategy and the one you will use most often. It replaces Pods in batches — scaling the old ReplicaSet down and the new ReplicaSet up at the same time — while the Service slowly shifts traffic to the new Pods as they pass readiness. The strategy is safe by default but not free; it requires spare cluster capacity and a readiness probe the application actually answers.

What the strategy does

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 6
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2
      maxUnavailable: 0
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: nginx
        image: nginx:1.27.2
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          periodSeconds: 5

When you change the Pod template (image, env, resources), the Deployment controller creates a new ReplicaSet and walks the old and new in parallel:

  1. Scale up the new ReplicaSet by maxSurge (or until maxUnavailable old Pods are missing).
  2. Wait for the new Pods to pass readiness.
  3. Scale down the old ReplicaSet by the number of new Pods now Ready.
  4. Repeat until the old ReplicaSet has zero replicas.
  5. Record the rollout in the Deployment’s status.
flowchart LR
    A["Old ReplicaSet<br/>6 ready"] -->|step 1| B["Old: 4 ready<br/>New: 2 surge"]
    B -->|readiness| C["Old: 4 ready<br/>New: 2 ready"]
    C -->|step 2| D["Old: 2 ready<br/>New: 4 ready"]
    D -->|readiness| E["Old: 2 ready<br/>New: 4 ready"]
    E -->|step 3| F["Old: 0 ready<br/>New: 6 ready"]

maxSurge and maxUnavailable

Two knobs control the rollout. They are independent and each takes an integer or a percentage of replicas.

FieldMeaningDefault
maxSurgeMaximum Pods above the desired count the rollout is allowed to create25%
maxUnavailableMaximum Pods below the desired count the rollout is allowed to remove25%

Constraints the API server enforces:

  • At least one of maxSurge or maxUnavailable must be non-zero.
  • A value of 0 for one of them is allowed and means “do not violate that side” of the budget.

The trade-off

ConfigurationSpare capacity neededTolerable downtime per batch
maxSurge: 0, maxUnavailable: 1None (0 surge)1 old Pod missing
maxSurge: 1, maxUnavailable: 01 extra Pod0 missing
maxSurge: 25%, maxUnavailable: 0 (defaults on large Deployments)25% extra Pods0 missing
maxSurge: 25%, maxUnavailable: 25% (legacy default)Up to 25% extraUp to 25% missing

maxUnavailable: 0 is the safest setting for capacity-tight workloads because no old Pod is removed until a new Pod is Ready. It costs maxSurge extra Pods of headroom.

flowchart TB
    subgraph "maxSurge: 2, maxUnavailable: 0"
      S1["Old RS: 6 of 6"] -->|create 2 new| S2["Old RS: 6 of 6<br/>New RS: 0 of 2"]
      S2 -->|wait readiness| S3["Old RS: 6 of 6<br/>New RS: 2 of 2 ready"]
      S3 -->|drain 2 old| S4["Old RS: 4 of 6<br/>New RS: 2 of 2"]
    end

The math of a rollout

For a Deployment with replicas: R and burst settings maxSurge: S and maxUnavailable: U:

  • Peak live Pod count: R + S
  • Worst-case missing Pod count: R - U (only if readiness on the new side lags)

The Deployment controller rounds S and U per step based on R. A maxSurge: 25% Deployment with replicas: 5 allows 1.25 extra Pods, which the controller rounds to 1 (or 2, depending on the implementation).

A rollout that does not converge past the same step for more than progressDeadlineSeconds (default 600) is marked ProgressDeadlineExceeded. The Deployment is not rolled back automatically; the operator must intervene.

kubectl rollout status deployment/web -n prod
# error: error timed out waiting for the condition
kubectl describe deployment web -n prod | sed -n '/Conditions/,/Events/p'

Readiness is the gate

The RollingUpdate is only as safe as the readiness probe. The controller only counts a Pod as “new and Ready” once the readiness probe has passed. If readiness never passes:

  • The new ReplicaSet never reaches maxSurge old Pods worth of replacements.
  • The old ReplicaSet is not scaled down.
  • The rollout stalls until progressDeadlineSeconds and the Deployment becomes unhealthy.

Capacity and HPA interactions

A RollingUpdate assumes the cluster has maxSurge worth of extra capacity above the steady state. With maxSurge: 25%, rolling out a 100-replica Deployment briefly needs 125 Pods scheduled. On a cluster running at 95% utilisation, those 25 extra Pods may not fit. The rollout will not fail outright — it will throttle. The new Pods sit Pending until old Pods free capacity.

Common production settings

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 1
    maxUnavailable: 0

This is the standard “no-downtime” setting when capacity is modest. It allows 1 extra Pod and never removes an old Pod until a new one is Ready.

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 25%
    maxUnavailable: 25%

Legacy default; only used when the new template is known-safe and the cluster can absorb a temporary drop. Faster rollouts, riskier rollbacks.

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 0
    maxUnavailable: 1

Used when the cluster cannot accept any surge (e.g., the Deployment runs on a node with no spare capacity). It does a small-batch rollout with no extra Pods. Will incur brief in-under-capacity periods.

Inspecting a rollout

Read-only / Safe
$ kubectl rollout status deployment/web -n prod
deployment "web" successfully rolled out
Read-only / Safe
$ kubectl rollout history deployment/web -n prod
deployment.apps/web
REVISION  CHANGE-CAUSE
1         Initial deploy
2         Image bump to nginx:1.27.2
3         Resource limits tune
Read-only / Safe
$ kubectl get replicasets -l app=web -n prod -o wide
NAME             DESIRED   CURRENT   READY   AGE
web-7c8d9b1f8    6         6         6       2d
web-6b3d5a7e9    0         0         0       45m

The old ReplicaSet stays around with 0 replicas so that kubectl rollout undo can resurrect it instantly without re-pulling the image.

Quiz

Knowledge check · 4 questions

  1. Q1. A Deployment has `replicas: 6` with `maxSurge: 2` and `maxUnavailable: 0`. What is the maximum number of Pods that can exist at any moment during a rollout?

  2. Q2. A Deployment rollout stalls when new Pods never become Ready; the Deployment controller will automatically roll back to the previous ReplicaSet when `progressDeadlineSeconds` is exceeded.

  3. Q3. Your team changed a Deployment's image to a new version. The rollout is in progress; old Pods are being replaced. 5 minutes in, the new Pods are Running but never Ready. What happens and how do you recover?

    Deployment web with replicas 6, maxSurge 1, maxUnavailable 0. New image has a broken readiness probe returning 500. After 10 minutes the rollout is stuck.

  4. Q4. Name the two burst settings that control a RollingUpdate and explain the trade-off they encode.

Passing score: 75%. Answers are checked in this browser.

Production discipline

  • Always set explicit maxSurge and maxUnavailable. Production rollouts should not rely on a 25%/25% legacy default.
  • A readiness probe that matches the production liveness criterion is mandatory. tcpSocket: port only is not sufficient — it does not detect a process that accepts connections but cannot serve traffic.
  • Set progressDeadlineSeconds lower than the alerting threshold so the Deployment fails-fast and pages on-call.
  • Pre-pull the new image onto the nodes (DaemonSet with the image, or node-pull init scripts) so image-pull latency does not become the rollout bottleneck.
  • Treat every kubectl rollout undo as a code change in reverse. Test it in staging with the same surge settings.

The RollingUpdate strategy is the workhorse of every Kubernetes Deployments course and of most production rollouts. Its safety properties are entirely determined by the readiness probe, the burst budget, and the cluster’s capacity headroom. None of these are Kubernetes’ job to verify — they are the operator’s.