Containerization Fundamentals

Kubernetes Deployments & ReplicaSets, In Depth: Rollouts, Rollback & Strategies

In the previous lesson you took the Pod apart field by field — the smallest thing Kubernetes runs, and a thing you should almost never create by hand. The reason you don’t create bare Pods is simple: a Pod has no self-healing and no concept of versions. Delete it, lose the node it ran on, or ship a new image, and nothing brings the right Pods back in the right shape. That job belongs to a controller, and for the everyday case of “run N copies of a stateless app and let me update them safely” the controller you reach for is the Deployment.

This lesson is the exhaustive companion to that one-liner. A Deployment is deceptively small on the surface — a handful of YAML keys — but it sits on top of a second object, the ReplicaSet, and the way the two cooperate is what gives you zero-downtime rolling updates, instant rollback, paused canaries, and a tidy revision history. We will walk the whole ownership chain (Deployment → ReplicaSet → Pod), explain every field in the Deployment spec, dissect both update strategies (RollingUpdate with maxSurge/maxUnavailable, and Recreate), trace the rollout lifecycle end to end with the real kubectl rollout commands, and finish by drawing the line between a Deployment and its cousins — the StatefulSet and the DaemonSet. Every example is current Kubernetes (v1.30+), real YAML, and reproducible on a free local cluster.

Learning objectives

By the end of this lesson you can:

Prerequisites & where this fits

You need a terminal, a local cluster (kind, minikube, or k3d), and the kubectl basics. If you have not set up a cluster, do the lab in What Is Kubernetes? Control Plane, Nodes, etcd & the kubelet first. This lesson assumes you understand the Pod spec in detail — labels, template, probes, resources, and the reconciliation loop — which is covered in the previous lesson, Kubernetes Pods, In Depth. This is Lesson KD3 of the Kubernetes Zero-to-Hero course: it is the workload-controller foundation that scaling, autoscaling, progressive delivery (Argo Rollouts/Flagger), and the capstone all build on. The next lesson, Kubernetes Services & Networking, puts a stable network address in front of the Pods a Deployment manages.

Core concepts: the controller chain

The single most important idea in this lesson is the ownership chain:

A Deployment owns one or more ReplicaSets; the current ReplicaSet owns the Pods.

Each layer has exactly one responsibility, and understanding the split is what makes rollouts make sense.

Object Its one job API group/version You create it directly?
Pod Run your container(s) once. No self-healing. v1 (core) Rarely — only for one-off debugging.
ReplicaSet Keep exactly N identical Pods running, of one version. Cannot update Pods in place. apps/v1 Almost never — you let a Deployment make it.
Deployment Manage ReplicaSets to give versioned, safe rollouts and rollback of a stateless workload. apps/v1 Yes — this is the object you write.

Two controllers run continuously in the control plane to make this work. The ReplicaSet controller watches each ReplicaSet and reconciles actual Pod count to desired count — the classic control loop. The Deployment controller watches each Deployment and reconciles which ReplicaSets exist and how many replicas each holds — it is the thing that, during an update, creates a new ReplicaSet and shifts replicas from old to new a few at a time.

Why two objects and not one?

It is tempting to ask why a Deployment doesn’t just manage Pods directly. The answer is versioning. A ReplicaSet is, by design, immutable in its Pod template for practical purposes — it represents one version of your app (one specific image + config). When you change the Deployment’s Pod template, the Deployment does not mutate the existing ReplicaSet; it creates a brand-new ReplicaSet for the new template and scales the old one down. Because the old ReplicaSet is still there (just scaled to 0), rollback is instant: the Deployment simply scales the old ReplicaSet back up and the new one down. Every revision you have ever rolled out is, by default, a ReplicaSet sitting at 0 replicas, ready to be reactivated. That is the whole trick.

Labels, selectors and ownerReferences — how the chain is wired

The chain is held together by two mechanisms working in tandem:

Jargon check. A selector is a label query; a label is a key/value tag on an object. The selector “finds” objects whose labels match. Get the selector wrong and a ReplicaSet either adopts Pods it shouldn’t or sees zero Pods and creates duplicates.

A complete Deployment manifest

Here is a realistic Deployment with the fields you will use most. We will then go through spec field by field.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  labels:
    app: web
spec:
  replicas: 3
  revisionHistoryLimit: 10
  progressDeadlineSeconds: 600
  minReadySeconds: 10
  selector:
    matchLabels:
      app: web
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
  template:
    metadata:
      labels:
        app: web            # MUST match spec.selector.matchLabels
    spec:
      containers:
        - name: web
          image: nginx:1.27.1
          ports:
            - containerPort: 80
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 2
            periodSeconds: 5
          resources:
            requests:
              cpu: "50m"
              memory: "64Mi"
            limits:
              memory: "128Mi"

Apply and inspect:

kubectl apply -f web.yaml
kubectl get deploy,rs,pod -l app=web

You will see one Deployment, one ReplicaSet (with the pod-template-hash suffix), and three Pods whose names share that hash.

The Deployment spec, field by field

This is the exhaustive field matrix — every key under spec, what it does, its values, its default, when to set it, and the gotcha.

Field What it does Values / type Default When to set Gotcha
replicas Desired number of identical Pods. integer ≥ 0 1 Always set explicitly; set to 0 to “park” a Deployment without deleting it. Omit it once an HPA owns the Deployment — otherwise kubectl apply fights the autoscaler (see the HPA section).
selector Immutable label query identifying the Pods this Deployment manages. matchLabels and/or matchExpressions none (required) Always. Keep it minimal and stable. Immutable after creation. It must match template.metadata.labels or the API rejects the object. Changing it requires delete + recreate.
template The Pod template — the full PodSpec that each replica is stamped from. a PodTemplateSpec none (required) Always — this is your app. Any change here (image, env, resources, labels, annotations) triggers a new rollout. Trivial-looking edits (a changed annotation) still cut a new revision.
strategy How Pods are replaced when the template changes. object with type + rollingUpdate RollingUpdate Set Recreate only when two versions can’t run together. rollingUpdate block is ignored unless type: RollingUpdate.
minReadySeconds Seconds a new Pod must be Ready without crashing before it counts as available and the rollout proceeds. integer (seconds) 0 Set to 10–30s to catch Pods that pass readiness then immediately die. 0 means “Ready = available instantly,” so a flapping Pod can let a bad rollout race ahead.
revisionHistoryLimit How many old ReplicaSets (scaled to 0) to retain for rollback. integer ≥ 0 10 Lower (e.g. 3–5) to reduce clutter; raise if you need deep rollback history. 0 deletes all history — you lose the ability to rollout undo.
progressDeadlineSeconds How long a rollout may make no progress before it is marked failed (Progressing=False, reason ProgressDeadlineExceeded). integer (seconds) 600 Lower for fast feedback in CI; raise for slow-starting apps. Must be greater than minReadySeconds. Exceeding it does not auto-rollback — it only flags the failure (and makes kubectl rollout status exit non-zero).
paused If true, the controller records template changes but does not act on them. boolean false Set via kubectl rollout pause to batch many edits or stage a canary. A paused Deployment ignores rollouts and scaling driven by the rollout; remember to resume.

A few of these deserve their own treatment because they are where rollouts are won or lost.

selector — minimal, stable, immutable

The selector supports two forms, which can be combined:

selector:
  matchLabels:
    app: web
  matchExpressions:
    - { key: tier, operator: In, values: [frontend] }
    - { key: track, operator: NotIn, values: [canary] }

matchLabels is sugar for an equality match; matchExpressions supports the operators In, NotIn, Exists, and DoesNotExist. Keep the selector as small as possible (often a single app label). It is immutable in apps/v1 — you cannot edit it on a live Deployment; you must delete and recreate. A good rule: the selector is an identity, not a description — put descriptive labels (version, team, commit) on the Pod template, but keep the selector to the one or two labels that will never change.

template — the unit of change

The Pod template is a complete PodSpec (every field from the previous lesson — containers, probes, resources, volumes, securityContext, scheduling). The crucial behaviour: the Deployment’s identity of a “version” is a hash of this template. Change anything in it and you get a new pod-template-hash, hence a new ReplicaSet, hence a rollout. This is why a common pattern for forcing a restart (e.g. to reload a mounted ConfigMap) is to change an annotation in the templatekubectl rollout restart does exactly this under the hood by stamping a kubectl.kubernetes.io/restartedAt annotation.

Update strategies: RollingUpdate vs Recreate

When you change the Pod template, the strategy decides how old Pods are swapped for new ones. There are exactly two types.

Strategy What happens Downtime? When to use Cost / trade-off
RollingUpdate (default) New ReplicaSet scaled up and old scaled down gradually, a few Pods at a time, so the app stays available throughout. No (if probes + capacity are right) The default for stateless web/API services. Briefly runs two versions at once — your app and clients must tolerate that. May need a little spare capacity (maxSurge).
Recreate All old Pods are terminated first, then new Pods are created. Yes — a gap with zero running Pods. When two versions cannot coexist: single-writer apps, incompatible schema migrations, exclusive locks, ReadWriteOnce volumes that only one Pod may mount. Simple and safe for “never two versions,” but you accept an outage window.

Tuning RollingUpdate: maxSurge and maxUnavailable

A rolling update is governed by two knobs in spec.strategy.rollingUpdate. Both accept an absolute integer or a percentage (rounded — maxSurge rounds up, maxUnavailable rounds down).

Knob Meaning Values Default Effect of raising it Gotcha
maxSurge How many Pods above replicas may exist during the rollout. int or % 25% Faster rollout (more new Pods spin up at once); needs more spare cluster capacity. With 0, the rollout can only proceed by first removing old Pods (so maxUnavailable must be > 0).
maxUnavailable How many Pods below replicas may be unavailable during the rollout. int or % 25% Faster rollout (more old Pods removed at once); reduces serving capacity mid-rollout. With 0, the rollout can only proceed by first adding new Pods (so maxSurge must be > 0).

They cannot both be 0 — that would forbid any movement and the rollout would deadlock; the API rejects it. The two combine to define a moving window. With replicas: 3, maxSurge: 25% (→ rounds up to 1), maxUnavailable: 25% (→ rounds down to 0):

So Kubernetes adds 1 new Pod (now 4), waits for it to be Ready (+minReadySeconds), terminates 1 old Pod (back to 3), and repeats until the new ReplicaSet holds all 3. Tuning patterns:

Jargon check.Available” is stronger than “Ready”. A Pod is Ready when its readiness probe passes; it becomes available to the rollout only after it has stayed Ready for minReadySeconds. The rollout counts available Pods, not merely Ready ones.

A Recreate Deployment ignores the rollingUpdate block entirely:

spec:
  strategy:
    type: Recreate

The rollout lifecycle, end to end

Let’s trace what actually happens when you change the image, and the commands you use to watch and control it.

Triggering a rollout

A rollout is triggered by any change to spec.template — not by changing replicas (that is just scaling). Common ways to trigger one:

# Imperative: change one container's image (records a clean revision)
kubectl set image deployment/web web=nginx:1.27.2

# Declarative: edit the YAML and re-apply (the canonical, GitOps-friendly way)
kubectl apply -f web.yaml

# Force a restart with no template change (re-pulls image, reloads mounted config)
kubectl rollout restart deployment/web

Watching it: kubectl rollout status

kubectl rollout status deployment/web
# Waiting for deployment "web" rollout to finish: 1 out of 3 new replicas have been updated...
# Waiting for deployment "web" rollout to finish: 2 of 3 updated replicas are available...
# deployment "web" successfully rolled out

rollout status blocks until the rollout completes or fails and exits non-zero on failure (after progressDeadlineSeconds) — which makes it perfect for CI/CD gates. Add --timeout=120s to cap how long you wait. Behind the scenes you can watch the ReplicaSets dance:

kubectl get rs -l app=web -w
# old RS scales 3→2→1→0 while new RS scales 0→1→2→3

Inspecting history: kubectl rollout history

kubectl rollout history deployment/web
# REVISION  CHANGE-CAUSE
# 1         <none>
# 2         kubectl set image deployment/web web=nginx:1.27.2

kubectl rollout history deployment/web --revision=2   # full template of revision 2

The CHANGE-CAUSE column is populated from the kubernetes.io/change-cause annotation. It is not filled in automatically by apply; set it deliberately for readable history:

kubectl annotate deployment/web kubernetes.io/change-cause="upgrade nginx to 1.27.2 (ticket OPS-1421)" --overwrite

Each entry corresponds to a retained old ReplicaSet (capped by revisionHistoryLimit).

Rolling back: kubectl rollout undo

kubectl rollout undo deployment/web                 # back to the immediately previous revision
kubectl rollout undo deployment/web --to-revision=1 # back to a specific revision

Rollback is fast because it is just a ReplicaSet scale-swap: the target old ReplicaSet scales up, the current one scales down — the same rolling mechanics in reverse. Note that an undo itself creates a new revision number (it does not rewind the counter); the template is restored, the history moves forward.

Pausing and resuming: canaries and batched edits

kubectl rollout pause deployment/web
# ...make several edits; none of them roll out yet...
kubectl set image deployment/web web=nginx:1.27.3
kubectl set resources deployment/web -c web --limits=memory=256Mi
kubectl rollout resume deployment/web   # now ONE rollout applies all changes

pause is also the primitive behind a manual canary: pause, change the image, manually scale the new ReplicaSet up by a single Pod, observe metrics, then either resume (finish the rollout) or undo (abort). For automated canaries with metric analysis you would reach for Argo Rollouts or Flagger, but the building block is this pause/resume primitive.

Reading the result: Deployment conditions

kubectl describe deployment web | sed -n '/Conditions/,/Events/p'
# Conditions:
#   Type           Status  Reason
#   Available      True    MinimumReplicasAvailable
#   Progressing    True    NewReplicaSetAvailable
Condition Meaning Healthy value
Available At least the minimum required Pods (replicasmaxUnavailable) are available. True
Progressing The rollout is advancing (or finished successfully — reason NewReplicaSetAvailable). Goes False with reason ProgressDeadlineExceeded on a stuck rollout. True

The diagram below shows the full picture — the Deployment shifting replicas from the old ReplicaSet to the new one during a rolling update, the surge/unavailable window, and the instant scale-swap that a rollback performs.

Deployment rollout & rollback

As the diagram makes clear, a rollout is a controlled migration of replicas between two ReplicaSets, and a rollback is the same migration aimed at a ReplicaSet you kept from a previous revision — nothing is rebuilt from scratch, which is why both are fast.

Scaling: manual and automatic

Scaling changes only replicas — it does not create a new ReplicaSet or a new revision; the current ReplicaSet simply adds or removes Pods.

kubectl scale deployment/web --replicas=5            # imperative
kubectl scale deployment/web --replicas=5 --current-replicas=3   # safe: only if currently 3

Declaratively, you edit spec.replicas and re-apply. Scaling down removes Pods chosen by a ranking that prefers, roughly: unscheduled/pending Pods first, then Pods on nodes with more replicas, then younger Pods — so it tends to keep your oldest, most-settled Pods.

The HPA hook: handing replicas to an autoscaler

A HorizontalPodAutoscaler (HPA) automatically adjusts a Deployment’s replicas based on observed metrics (CPU, memory, or custom/external metrics). The HPA targets the Deployment’s scale subresource — the same replicas field you set by hand.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

The golden rule: once an HPA owns a Deployment, remove replicas from your Deployment YAML (or omit it). If you leave replicas: 3 in a manifest you keep kubectl apply-ing, you and the HPA will tug-of-war — apply resets it to 3, the HPA scales it back up, and you get rollout churn. (Server-side apply mitigates this by tracking field ownership, but the cleanest answer is to simply not declare replicas when an HPA is in charge.) HPA, KEDA, and node autoscaling are covered in depth in Kubernetes Autoscaling: HPA, KEDA & Karpenter.

Deployment vs StatefulSet vs DaemonSet

A Deployment is the right tool for stateless, interchangeable replicas. It is the wrong tool when Pods need stable identity or one-per-node placement. Here is the decision matrix.

Controller Pod identity Storage Update/scale order Use it for Don’t use it for
Deployment Interchangeable; random name suffix; new IP/name on replacement Shared or none (all replicas equivalent) Unordered, parallel (within surge/unavailable window) Stateless web/API/worker apps; anything where “any replica is as good as another” Anything needing stable identity, ordered startup, or per-Pod storage
StatefulSet Stable, sticky: ordinal names web-0, web-1, stable DNS, stable per-Pod PVC Per-Pod via volumeClaimTemplates Ordered (0,1,2 up; reverse down), one at a time by default Databases, queues, clustered systems (Kafka, ZooKeeper, etcd), leader/follower apps Plain stateless services (overkill, slower rollouts)
DaemonSet One Pod per node (or per matching node) Usually host-level (hostPath) Per-node rolling (RollingUpdate/OnDelete) Node agents: log shippers, CNI, kube-proxy, node-exporter, CSI node plugins App replicas where you want a count, not one-per-node

Quick heuristic: Deployment = “I want N copies and I don’t care which is which.” StatefulSet = “each copy is a distinct, named member with its own disk.” DaemonSet = “exactly one copy on every node.” StatefulSets are covered in Running Postgres on Kubernetes: StatefulSet, Operator, Failover & PITR.

Hands-on lab

Free and local — kind, minikube, or k3d. We will create a Deployment, do a clean rolling update, watch the ReplicaSets swap, force a failed rollout and observe the deadline, roll back, and clean up.

1. Create a cluster (skip if you already have one):

kind create cluster --name kd3        # or: minikube start   /   k3d cluster create kd3
kubectl get nodes

2. Create the Deployment (save as web.yaml from the manifest earlier, then):

kubectl apply -f web.yaml
kubectl rollout status deployment/web
kubectl get deploy,rs,pod -l app=web

Expected: 1 Deployment (3/3 ready), 1 ReplicaSet, 3 Pods sharing a pod-template-hash.

3. Do a clean rolling update and watch the ReplicaSets in a second terminal:

# Terminal A:
kubectl get rs -l app=web -w
# Terminal B:
kubectl annotate deployment/web kubernetes.io/change-cause="bump to nginx 1.27.2" --overwrite
kubectl set image deployment/web web=nginx:1.27.2
kubectl rollout status deployment/web

In Terminal A you will see the old ReplicaSet drain (3→2→1→0) while a new one fills (0→1→2→3). Check the history:

kubectl rollout history deployment/web

4. Trigger a failing rollout to see the progress deadline. Shorten the deadline first, then ship a broken image:

kubectl patch deployment web -p '{"spec":{"progressDeadlineSeconds":30}}'
kubectl set image deployment/web web=nginx:does-not-exist
kubectl rollout status deployment/web
# ...after ~30s: error: deployment "web" exceeded its progress deadline
kubectl get rs -l app=web    # the bad new RS is stuck with Pods in ImagePullBackOff
kubectl describe deployment web | grep -A3 Conditions   # Progressing=False, ProgressDeadlineExceeded

Note the old Pods are still serving — a RollingUpdate with a bad image fails safe: it never finishes draining the old ReplicaSet because the new Pods never become available.

5. Roll back:

kubectl rollout undo deployment/web
kubectl rollout status deployment/web
kubectl get pods -l app=web          # back to healthy 1.27.2 Pods

6. Scale, then observe:

kubectl scale deployment/web --replicas=5
kubectl get pods -l app=web          # 5 Pods, SAME ReplicaSet (no new revision)
kubectl rollout history deployment/web   # revision count unchanged by scaling

Validation checklist: you saw exactly one ReplicaSet per revision; a rolling update kept Pods available throughout; a bad image failed without taking down the old version; undo restored service; scaling did not create a revision.

Cleanup:

kubectl delete -f web.yaml          # removes Deployment + its ReplicaSets + Pods (ownerReferences)
kubectl delete hpa web --ignore-not-found
kind delete cluster --name kd3      # or: minikube delete  /  k3d cluster delete kd3

Cost note: entirely free — everything runs in local containers on your machine; no cloud resources are created.

Common mistakes & troubleshooting

Symptom Likely cause Fix
selector does not match template labels on apply spec.selector.matchLabelsspec.template.metadata.labels Make them match; remember the selector is immutable — fix it before first apply.
Rollout hangs forever, never “successfully rolled out” New Pods never become Ready (bad image, failing readiness probe, insufficient resources/quota) kubectl get pods, kubectl describe pod, kubectl logs; fix the probe/image/resources; old version keeps serving meanwhile.
exceeded its progress deadline No progress within progressDeadlineSeconds (often ImagePullBackOff or CrashLoopBackOff) Diagnose the new Pods; rollout undo. The deadline only flags failure — it does not auto-rollback.
Brief downtime during a rolling update maxUnavailable too high, no readiness probe, or terminationGracePeriodSeconds/preStop too short so traffic hits dying Pods Set maxUnavailable: 0 + maxSurge: 25%; add a readiness probe; add a preStop sleep so endpoints drain.
Two app versions briefly serving (sometimes a bug) That is normal for RollingUpdate If versions can’t coexist, switch to strategy.type: Recreate and accept the downtime.
Can’t roll back — no rollout history found revisionHistoryLimit: 0, or it’s the very first revision Keep history ≥ 3; you can only undo to a retained revision.
apply keeps resetting replicas; pods churn replicas declared in YAML while an HPA also owns it Remove replicas from the manifest when an HPA manages the Deployment.
New ReplicaSet created on every apply even with no real change A controller/templating tool injecting a changing annotation/label into template Find the drifting field (kubectl get rs + diff templates); stop mutating the Pod template on every render.

Best practices

Security notes

Interview & exam questions

  1. What is the relationship between a Deployment, a ReplicaSet, and a Pod? A Deployment manages ReplicaSets; the current ReplicaSet manages Pods. The Deployment adds versioning and rollout/rollback on top of the ReplicaSet’s “keep N Pods running.”
  2. What actually happens during a rolling update? The Deployment creates a new ReplicaSet for the new template and shifts replicas from the old ReplicaSet to the new one a few at a time, bounded by maxSurge/maxUnavailable, until the new one holds all replicas and the old sits at 0.
  3. maxSurge vs maxUnavailable — define both and give the defaults. maxSurge = max Pods above replicas during a roll (default 25%); maxUnavailable = max Pods below replicas that may be unavailable (default 25%). They can’t both be 0.
  4. How does rollback work and why is it fast? kubectl rollout undo scales a retained old ReplicaSet back up and the current one down — a scale-swap, not a rebuild — using the same rolling mechanics in reverse.
  5. When would you choose Recreate over RollingUpdate? When two versions cannot run simultaneously: single-writer apps, incompatible DB migrations, exclusive locks, or ReadWriteOnce volumes only one Pod may mount. You accept a downtime gap.
  6. What does progressDeadlineSeconds do — does it roll back automatically? It marks a rollout failed (Progressing=False, ProgressDeadlineExceeded) if no progress is made in time. It does not auto-rollback; it only flags the failure (and makes rollout status exit non-zero).
  7. minReadySeconds vs a readiness probe — what’s the difference? The readiness probe decides Ready; minReadySeconds requires a Pod to stay Ready that long before counting as available to the rollout — catching Pods that pass readiness then crash.
  8. What is pod-template-hash and why does it exist? A hash of the Pod template that the Deployment controller adds to each ReplicaSet’s selector and its Pods, so different-version ReplicaSets don’t fight over the same Pods. It’s the middle segment of Pod names.
  9. Why doesn’t changing replicas create a new revision, but changing the image does? replicas is scaling — handled by the same ReplicaSet. Changing the template (image, env, etc.) creates a new pod-template-hash, hence a new ReplicaSet and a new revision.
  10. How does an HPA interact with a Deployment, and what mistake do people make? The HPA writes to the Deployment’s scale subresource (replicas). The mistake is leaving replicas hard-coded in a manifest you keep apply-ing, which fights the HPA — remove it.
  11. Deployment vs StatefulSet vs DaemonSet in one line each. Deployment = N interchangeable stateless replicas; StatefulSet = stable-identity members with per-Pod storage, ordered ops; DaemonSet = one Pod per node.
  12. A rollout is stuck at “1 of 3 updated replicas are available” — how do you diagnose it? The new Pods aren’t becoming available: kubectl get pods, describe, logs to find the cause (image pull, probe, resources/quota); the old version keeps serving; rollout undo to recover.

Quick check

  1. True or false: changing spec.replicas triggers a new rollout/revision.
  2. With replicas: 4, maxSurge: 50%, maxUnavailable: 0, what is the maximum number of Pods that can exist during a rolling update, and the minimum available?
  3. Which strategy briefly runs zero Pods, and when must you use it?
  4. Which command rolls back to a specific earlier revision, and what does it do to old/new ReplicaSets?
  5. You set revisionHistoryLimit: 0. What capability do you lose?

Answers

  1. False. Scaling reuses the current ReplicaSet; only a change to spec.template cuts a new revision.
  2. Max 6 (4 + 50% surge = 4 + 2), min available 4 (4 − 0). New Pods are added before any old ones leave.
  3. Recreate — it terminates all old Pods before creating new ones; use it when two versions can’t coexist (single-writer, incompatible migration, ReadWriteOnce volume).
  4. kubectl rollout undo deployment/<name> --to-revision=<n> — it scales the retained old ReplicaSet up and the current one down (a scale-swap), and records a new revision.
  5. You lose rollback — with no retained old ReplicaSets, kubectl rollout undo has nothing to roll back to.

Exercise

Build and operate a Deployment called api from scratch:

  1. Write a Deployment manifest (api.yaml): image hashicorp/http-echo:1.0 with args ["-text=v1","-listen=:8080"], replicas: 4, a readiness probe on :8080, strategy: RollingUpdate with maxSurge: 1 and maxUnavailable: 0, minReadySeconds: 5, and revisionHistoryLimit: 5. Apply it and confirm 4/4 ready with one ReplicaSet.
  2. Roll out -text=v2 using kubectl set image (or by editing args + apply), set a meaningful kubernetes.io/change-cause, and watch the ReplicaSets swap with kubectl get rs -w. Confirm capacity never dropped below 4.
  3. Ship a deliberately broken image, watch the rollout fail against a 30s progressDeadlineSeconds, confirm the v2 Pods kept serving, then rollout undo.
  4. Create an HPA (min 4, max 12, CPU 60%) targeting api, remove replicas from api.yaml, re-apply, and confirm apply no longer fights the autoscaler.
  5. Add a StatefulSet and a DaemonSet in comments at the bottom of your file describing one workload each that would need them instead of a Deployment, and why. Clean everything up.

Certification mapping

Glossary

Next steps

KubernetesDeploymentsReplicaSetsRolloutsRollbackCKAD
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading