Skip to main content
RunBook Academy

KubernetesXV · DeploymentsDeployments

Rollout and revision history — change tracking and rollback

Advanced⏱ ~16 minkubectl

What you'll learn

  • Explain how Deployments track revision history via annotations
  • Use kubectl rollout history to inspect changes
  • Use kubectl rollout undo to roll back to a previous revision
  • Use kubectl rollout pause and resume for staged rollouts

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.

Deployments track every change as a revision. This lesson covers how revision history works, how to inspect it, and how to roll back when a change goes wrong.

Revision history

When you update a Deployment’s spec (e.g., change the image), the Deployment controller:

  1. Creates a new ReplicaSet with the new spec.
  2. Scales the new ReplicaSet up.
  3. Scales the old ReplicaSet down.
  4. Marks the old ReplicaSet with an annotation recording the change.

The annotation is kubernetes.io/change-cause:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: web-7c8d9
  annotations:
    kubernetes.io/change-cause: "kubectl set image deployment/web web=nginx:1.27.2"
    deployment.kubernetes.io/revision: "3"

The annotation records:

  • kubernetes.io/change-cause: the human-readable reason for the change (set by --record or manually).
  • deployment.kubernetes.io/revision: the revision number (incremented on each change).
sequenceDiagram
    participant U as User
    participant D as Deployment
    participant RS as ReplicaSet
    U->>D: kubectl apply (new image)
    D->>RS: create new RS (revision 4)
    D->>RS: scale up new RS
    D->>RS: scale down old RS to 0
    Note over RS: old RS annotated with change-cause

Inspecting revision history

kubectl rollout history deployment/web

Output:

deployment.apps/web
REVISION  CHANGE-CAUSE
1         Initial deployment
2         kubectl set image deployment/web web=nginx:1.27.1
3         kubectl set image deployment/web web=nginx:1.27.2
4         Update replicas to 5

Each row is a revision. The change-cause tells you what changed.

# Inspect a specific revision
kubectl rollout history deployment/web --revision=3

Output:

deployment.apps/web with revision #3
Pod Template:
  Labels:	app=web
  Containers:
   web:
    Image:	nginx:1.27.2
    Port:	8080/TCP
    Host Port:	0/TCP
    Limits:
      cpu:	500m
      Memory:	512Mi
    Requests:
      cpu:	100m
      Memory:	128Mi
    Environment:	<set to the keys 'DB_HOST' from config map 'app-config'>

The full Pod template at that revision. Useful for understanding what changed between revisions.

The revision history limit

spec:
  revisionHistoryLimit: 10

The revisionHistoryLimit controls how many old ReplicaSets the Deployment retains. Default is 10. Each retained ReplicaSet uses etcd storage and counts against the namespace’s ResourceQuota.

When the limit is exceeded, the oldest ReplicaSets are deleted (along with their Pods). Production discipline: tune the limit based on the team’s rollback needs. 10 is usually enough for a few days of history.

Rolling back

# Roll back to the previous revision
kubectl rollout undo deployment/web

# Roll back to a specific revision
kubectl rollout undo deployment/web --to-revision=3

# Check the rollout status
kubectl rollout status deployment/web

rollout undo creates a new ReplicaSet with the spec from the target revision. The Deployment rolls forward to that revision (a new revision number, not the old one).

sequenceDiagram
    participant U as User
    participant D as Deployment
    U->>D: kubectl rollout undo --to-revision=3
    D->>D: create new RS with revision 3 spec (revision 5)
    D->>D: scale up new RS
    D->>D: scale down current RS to 0

The undo operation is itself a rollout; the Deployment controller rolls forward to the target spec. The result is a new revision number (because the change is recorded as a new change).

Pause and resume

# Pause the rollout
kubectl rollout pause deployment/web

# Make changes to the manifest (not via apply)
kubectl edit deployment/web
# Change image, env, etc.

# Resume the rollout
kubectl rollout resume deployment/web

rollout pause stops the Deployment from creating new ReplicaSets. Subsequent edits to the Deployment accumulate; when rollout resume is called, the Deployment controller sees the cumulative changes and rolls out.

Use cases:

  • Staged rollouts: make multiple changes (image, env, resources), pause, verify the staging environment, resume.
  • Coordination: pause the rollout, make a manual change to a Pod (e.g., debug), resume.
  • Rollout planning: pause to plan; resume when ready.

Production patterns

Stage a change in production:

# 1. Pause
kubectl rollout pause deployment/web

# 2. Apply changes
kubectl set image deployment/web web=nginx:1.27.3
kubectl set resources deployment/web -c web --limits=cpu=700m

# 3. Verify in staging
kubectl get deployment/web -o yaml | grep -A 5 template

# 4. Resume when ready
kubectl rollout resume deployment/web

Quick rollback after a failed rollout:

# Check rollout status
kubectl rollout status deployment/web --timeout=60s

# If failed, undo
kubectl rollout undo deployment/web

# Verify
kubectl rollout status deployment/web

Inspect change history before merging:

# Review recent changes
kubectl rollout history deployment/web | tail -10

# Compare revisions
kubectl rollout history deployment/web --revision=5
kubectl rollout history deployment/web --revision=6

Diagnosing rollout issues

A Deployment that won’t progress:

kubectl rollout status deployment/web --timeout=60s
# error: deployment "web" exceeded its progress deadline

The Deployment has a progressDeadlineSeconds (default 600s = 10 minutes). If the rollout does not make progress within this window, the Deployment is marked failed.

Check:

# Recent events
kubectl describe deployment/web | tail -20

# Pod status
kubectl get pods -l app=web

# ReplicaSet status
kubectl get replicaset -l app=web

Common causes:

  • New image cannot be pulled (ImagePullBackOff).
  • New Pods fail readiness probe.
  • Insufficient cluster capacity.

Cross-course references

  • The Linux course part XXXVII-Linux-Resources covers process management; rollout history is the cluster-level equivalent of a change log.
  • The Ansible course part XXXV-Ansible-Scripting covers staged rollouts; kubectl rollout pause/resume is the cluster-level equivalent.
  • The Terraform course part XVII-Terraform-Drift covers state-vs-config; rollout history is the cluster-level equivalent.

Quiz

Knowledge check · 4 questions

  1. Q1. What does `kubectl rollout undo deployment/web` do?

  2. Q2. The `kubernetes.io/change-cause` annotation on old ReplicaSets is set automatically by every kubectl apply.

  3. Q3. A team rolls out a new image. The rollout fails with `exceeded its progress deadline` after 10 minutes. Walk through the rollback procedure.

    Deployment `web` rolled out with image `nginx:1.27.3` 12 minutes ago. `kubectl rollout status deployment/web --timeout=60s` returns `deployment "web" exceeded its progress deadline`. New Pods are in `ImagePullBackOff` (image tag does not exist). The team needs to roll back.

  4. Q4. What is the difference between `kubectl rollout pause` and `kubectl rollout resume`? When is pause useful?

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

Production discipline

  • Always set change-cause annotations. Rollback history without change-cause is unhelpful in incidents.
  • Set revisionHistoryLimit based on rollback needs. 10 is the default; raise if the team needs longer history.
  • Test rollbacks regularly. A team that has never rolled back is unprepared for an incident.
  • Use pause/resume for staged rollouts. Multiple changes; pause; verify; resume.
  • Investigate failed rollouts. kubectl rollout status failures are signals of broken changes; document them in the postmortem.