Skip to content
Codeloom
Kubernetes

Kubernetes Rolling Updates and Rollback Strategies

Master zero-downtime deployments with Kubernetes rolling updates, rollback commands, and deployment strategies like blue-green and canary.

·7 min read · By Codeloom
Intermediate 10 min read

What you'll learn

  • How Kubernetes rolling updates work under the hood
  • Tuning maxSurge and maxUnavailable for your workload
  • How to roll back failed deployments quickly and safely

Prerequisites

When you update a Deployment in Kubernetes, the default strategy is a rolling update. Kubernetes gradually replaces old pods with new ones, ensuring your application stays available throughout the process. If something goes wrong, you can roll back to the previous version in seconds. This article covers how rolling updates work, how to tune them, and what to do when things go wrong.

How Rolling Updates Work

A Deployment manages ReplicaSets. When you update the pod template (change the image tag, environment variable, or any pod spec field), Kubernetes creates a new ReplicaSet and scales it up while scaling the old ReplicaSet down.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 4
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: myapp:1.0.0
          ports:
            - containerPort: 3000

Update the image:

kubectl set image deployment/api api=myapp:1.1.0

Kubernetes does the following:

  1. Creates a new ReplicaSet with the myapp:1.1.0 image
  2. Scales the new ReplicaSet up by one pod
  3. Waits for the new pod to pass readiness checks
  4. Scales the old ReplicaSet down by one pod
  5. Repeats until all pods run the new version

The Service continues routing traffic only to pods that pass their readiness probes, so users experience no downtime.

Configuring the Rolling Update Strategy

The strategy field controls how fast and how aggressively Kubernetes rolls out changes:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: myapp:1.1.0
          ports:
            - containerPort: 3000
          readinessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 5
            periodSeconds: 10

maxSurge — the maximum number of pods that can be created above the desired replica count. With 4 replicas and maxSurge: 1, Kubernetes runs at most 5 pods during the update.

maxUnavailable — the maximum number of pods that can be unavailable during the update. With maxUnavailable: 0, all 4 replicas must stay running at all times.

Common configurations:

PatternmaxSurgemaxUnavailableBehavior
Conservative10One new pod at a time, zero downtime
Balanced25%25%Default, good for most workloads
Fast50%50%Rolls out quickly, some capacity reduction
Full replace100%0Doubles pods briefly, fastest zero-downtime

The values can be absolute numbers or percentages. Percentages are rounded up for maxSurge and rounded down for maxUnavailable.

Readiness Probes Are Critical

Without readiness probes, Kubernetes considers a pod ready the moment the container starts. It will scale down old pods before new ones are actually serving traffic, causing errors.

Always define readiness probes for rolling updates:

containers:
  - name: api
    image: myapp:1.1.0
    readinessProbe:
      httpGet:
        path: /health
        port: 3000
      initialDelaySeconds: 5
      periodSeconds: 10
      failureThreshold: 3
    livenessProbe:
      httpGet:
        path: /health
        port: 3000
      initialDelaySeconds: 15
      periodSeconds: 20

The readiness probe tells Kubernetes when the pod is ready to serve traffic. The liveness probe tells Kubernetes when to restart the pod. Use different thresholds — readiness should be checked more frequently with a lower initial delay.

Monitoring a Rollout

Watch the rollout progress:

# Watch rollout status
kubectl rollout status deployment/api

# See rollout history
kubectl rollout history deployment/api

# See details of a specific revision
kubectl rollout history deployment/api --revision=3

Check which ReplicaSets are active:

kubectl get replicasets -l app=api

During a rollout, you will see two ReplicaSets — the old one scaling down and the new one scaling up.

Rolling Back a Deployment

If the new version has bugs, roll back immediately:

# Roll back to the previous version
kubectl rollout undo deployment/api

# Roll back to a specific revision
kubectl rollout undo deployment/api --to-revision=2

The rollback is another rolling update, just in reverse. Kubernetes scales up the old ReplicaSet and scales down the current one.

To preserve rollout history, set revisionHistoryLimit:

spec:
  revisionHistoryLimit: 10

This keeps the last 10 ReplicaSets so you can roll back to any of them. The default is 10.

Pausing and Resuming Rollouts

For large changes that involve multiple updates, pause the rollout to batch changes:

# Pause the rollout
kubectl rollout pause deployment/api

# Make multiple changes
kubectl set image deployment/api api=myapp:1.2.0
kubectl set env deployment/api API_VERSION=1.2.0

# Resume -- applies all changes as one rollout
kubectl rollout resume deployment/api

Without pausing, each kubectl set triggers a separate rollout. Pausing lets you batch them into a single rollout.

Deployment Deadline

Set progressDeadlineSeconds to fail the rollout if it takes too long:

spec:
  progressDeadlineSeconds: 300

If the Deployment does not make progress for 300 seconds, Kubernetes marks it as failed. This prevents a broken rollout from hanging forever. The default is 600 seconds.

Check for a stalled rollout:

kubectl get deployment api -o jsonpath='{.status.conditions[?(@.type=="Progressing")].message}'

Recreate Strategy

For applications that cannot run two versions simultaneously (database migrations, stateful services), use the Recreate strategy:

spec:
  strategy:
    type: Recreate

This terminates all old pods before creating new ones. There is downtime between the old pods stopping and the new pods starting. Use it only when rolling updates are not possible.

Blue-Green with Deployments

Simulate blue-green deployments using two Deployments and a Service:

# Blue deployment (current)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-blue
spec:
  replicas: 4
  selector:
    matchLabels:
      app: api
      version: blue
  template:
    metadata:
      labels:
        app: api
        version: blue
    spec:
      containers:
        - name: api
          image: myapp:1.0.0
---
# Service pointing to blue
apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  selector:
    app: api
    version: blue
  ports:
    - port: 80
      targetPort: 3000

Deploy the green version alongside blue, verify it works, then switch the Service selector:

# Deploy green
kubectl apply -f api-green.yaml

# Verify green works
kubectl run test --rm -it --image=busybox -- wget -qO- http://api-green:3000/health

# Switch traffic
kubectl patch service api -p '{"spec":{"selector":{"version":"green"}}}'

# Scale down blue after verification
kubectl scale deployment api-blue --replicas=0

Canary Deployments

Run a small percentage of traffic on the new version before full rollout:

# Stable: 9 replicas
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-stable
spec:
  replicas: 9
  selector:
    matchLabels:
      app: api
      track: stable
  template:
    metadata:
      labels:
        app: api
        track: stable
    spec:
      containers:
        - name: api
          image: myapp:1.0.0
---
# Canary: 1 replica
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-canary
spec:
  replicas: 1
  selector:
    matchLabels:
      app: api
      track: canary
  template:
    metadata:
      labels:
        app: api
        track: canary
    spec:
      containers:
        - name: api
          image: myapp:1.1.0
---
# Service selects both
apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  selector:
    app: api
  ports:
    - port: 80
      targetPort: 3000

The Service selects all pods with app: api, so roughly 10% of traffic goes to the canary. Monitor error rates, then gradually increase canary replicas while decreasing stable replicas.

Summary

Rolling updates are the default and usually the best strategy for Kubernetes deployments. Configure maxSurge and maxUnavailable based on your availability requirements, always use readiness probes, and set a progress deadline. When things go wrong, kubectl rollout undo gets you back to the previous version in seconds. For more control, blue-green and canary patterns give you explicit traffic switching at the cost of additional complexity.