Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Rolling Updates with Deployment

Perform a rolling update with Deployment in Kubernetes: step-by-step walkthrough, mental model, hands-on exercise, troubleshooting, and what to study next.

Focus: perform a rolling update with deployment

Sponsored

You've built a Deployment, and your app is running smoothly. But now you need to push a new version — new code, updated config, or a different image tag. A simple kubectl delete followed by kubectl create would cause downtime, and your users would see errors. That's exactly the problem this lesson solves: you'll learn how to perform a rolling update with Deployment, the safe, zero-downtime way to update running applications in Kubernetes.

The problem this lesson solves

Updating a live application is risky. If you stop all old Pods before starting new ones, your users face a gap — 503 errors, dropped connections, angry customers. If you start all new Pods first, you might run out of cluster resources or accidentally serve traffic from both old and new versions simultaneously (which can cause data corruption or API mismatches).

Kubernetes Deployments exist precisely to manage this tension. A rolling update increments the new version gradually, replacing old Pods one by one (or in batches) while verifying each new Pod is healthy before moving to the next. This means:

  • Zero downtime — users are always served by a working Pod.
  • Controlled rollout speed — you can pause, resume, or roll back if something goes wrong.
  • Automatic health checking — Kubernetes waits for readiness probes before replacing the next Pod.

The pain this lesson solves: you go from "fear of updating" to "confident, automated rollouts."

Core concept / mental model

Think of a Deployment as a fleet manager for immutable Pods. You tell it the desired state (your YAML definition), and it drives the current state toward that desired state. During an update, the Deployment creates a ReplicaSet for the new version and gradually scales it up while scaling the old ReplicaSet down to zero.

Pro tip: A ReplicaSet is the underlying controller that ensures a specified number of identical Pod replicas are running. A Deployment wraps a ReplicaSet with update logic — like rolling updates and rollbacks.

The mental model: imagine a line of production workers (Pods) on a conveyor belt. To update their tools, you don't stop the whole line. Instead, you bring in a new worker with new tools (new ReplicaSet), verify they work, then pull out one old worker at a time. The line never stops.

Key definitions

  • Rolling update strategy — the Deployment's strategy.type: RollingUpdate (default).
  • maxSurge — maximum number of Pods above the desired replica count during the update (default 25%).
  • maxUnavailable — maximum number of Pods that can be unavailable during the update (default 25%).

If your desired replica count is 4, with defaults: - maxSurge = 25% → 1 extra Pod allowed above 4 (total 5). - maxUnavailable = 25% → only 1 Pod can be down at a time.

This ensures availability stays high while new Pods spin up.

How it works step by step

When you execute kubectl set image deployment/myapp myapp=myapp:v2 or apply an updated YAML file (kubectl apply -f deployment-v2.yaml), the Deployment controller follows this sequence:

  1. Detect change — The controller notices the Pod template (e.g., image tag) has changed.
  2. Create new ReplicaSet — A ReplicaSet for the new Pod template is created, with replica count 0.
  3. Scale up new ReplicaSet — Add 1 new Pod (controlled by maxSurge).
  4. Scale down old ReplicaSet — Remove 1 old Pod (controlled by maxUnavailable).
  5. Repeat — Until all old Pods are replaced by new ones.
  6. Declare update complete — The old ReplicaSet is scaled to 0, but remains in history for rollback.

Pro tip: You can watch the progress with kubectl rollout status deployment myapp.

Example with real numbers

Assume a Deployment with replicas=3, default rolling update settings:

Step Old Replicas New Replicas Total Pods Notes
Start 3 0 3 All healthy
1 3 1 4 maxSurge=25% ≈1 extra
2 2 1 3 maxUnavailable=25% ≈1 removed
3 2 2 4 Another new Pod created
4 1 2 3 One old Pod removed
5 1 3 4 Final new Pod created
6 0 3 3 Old scaled to 0, update done

Notice the total Pods never drops below 3 (except briefly if maxUnavailable allows), and never exceeds 4.

Hands-on walkthrough

Let's perform a rolling update with a real Deployment. We'll start with a simple nginx app, update the image, and monitor the rollout.

Step 1: Create the initial Deployment

# deployment-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: nginx:1.23-alpine
        ports:
        - containerPort: 80
kubectl apply -f deployment-v1.yaml
deployment.apps/myapp created

Step 2: Verify initial state

kubectl get pods -l app=myapp

Expected output (names and status vary):

NAME                     READY   STATUS    RESTARTS   AGE
myapp-6d9f9c8c8-abc12   1/1     Running   0          30s
myapp-6d9f9c8c8-def34   1/1     Running   0          30s
myapp-6d9f9c8c8-ghi56   1/1     Running   0          30s

Step 3: Perform the rolling update

Update the image to a newer version:

kubectl set image deployment/myapp myapp=nginx:1.24-alpine
deployment.apps/myapp image updated

Or apply a modified YAML file — same effect. Watch the rollout in real time:

kubectl rollout status deployment/myapp

While that command is running, in another terminal, watch Pods change:

kubectl get pods -l app=myapp --watch

You'll see new Pods starting (with a different generation hash in the name), and old Pods terminating one by one. No downtime.

Step 4: Verify the update

kubectl rollout history deployment/myapp
deployment.apps/myapp
REVISION  CHANGE-CAUSE
1         <none>
2         <none>

The revision number increments with each update. Now check the actual image running:

kubectl get deployment myapp -o jsonpath='{.spec.template.spec.containers[0].image}'
nginx:1.24-alpine

Step 5: Check the old ReplicaSet

kubectl get replicaset -l app=myapp

Expected output shows the old ReplicaSet at 0 replicas, ready for rollback if needed.

Compare options / when to choose what

Rolling update is Kubernetes' default strategy, but not the only one. Here's how it compares to alternatives:

Strategy Description Use when Pros Cons
RollingUpdate (default) Gradually replace Pods Most apps, zero-downtime needs Gradual rollback, built-in, maxSurge/maxUnavailable Takes longer than recreate
Recreate Terminate all old, then create new Batch jobs, canary groups, stateful apps with exclusive resources Fastest, clean slate Downtime, no gradual rollout
Blue/Green Deploy new version alongside old, switch traffic Critical services, canary testing Instant switch, easy rollback 2x resource cost
Canary Route small % of traffic to new version High-risk rollouts, gradual exposure Minimal blast radius Requires service mesh or Ingress

When to choose RollingUpdate: - Your app is stateless or mostly stateless. - You need zero downtime. - You want simplicity — no extra tooling. - You're okay with a rollout that takes minutes (not seconds).

When to avoid RollingUpdate: - Your app cannot run two versions simultaneously (e.g., database schema migrations that break with old code). - You need instant, complete switchovers. - You're dealing with stateful workloads that require careful IP/hostname handling (use StatefulSet with OnDelete strategy).

Pro tip: For most web APIs and microservices, RollingUpdate with readiness probes is the safest bet. Always define a readinessProbe in your Pod template — it tells Kubernetes the Pod is ready to serve traffic before counting it as "available."

Troubleshooting & edge cases

Even with rolling updates, things can go wrong. Here are common failures and fixes.

1. Rolling update stalls

Symptom: kubectl rollout status hangs at "Waiting for deployment spec update to be observed..." or Pods stay in Pending/CrashLoopBackOff.

Fix: - Check Pod logs: kubectl logs <pod-name>. - Verify readiness probe: kubectl get pods | grep Running vs kubectl get pods -o wide. If a Pod is Running but not Ready, your probe is failing. - Scale up resources if Pods are stuck in Pending due to CPU/memory.

2. maxUnavailable reached but new Pods not starting

Symptom: Old Pods are terminating, but new ones won't schedule.

Fix: - Check node resources: kubectl describe nodes. You may need to add nodes. - Check PVC if using persistent volumes. - Verify image pull: kubectl describe pod <new-pod> for ImagePullBackOff.

3. Rollback failure

If you need to revert quickly:

kubectl rollout undo deployment/myapp
deployment.apps/myapp rolled back

But if the undo itself fails (e.g., because the previous revision's image is also broken), you can roll back to a specific revision:

kubectl rollout undo deployment/myapp --to-revision=1

4. Pods crash after update

Symptom: New Pods restart endlessly.

Fix: - kubectl logs <pod-name> --previous to see last log before crash. - kubectl describe pod <pod-name> shows Last State: Terminated with exit code. - Fix your image or configuration, then reapply.

5. Config mismatch between versions

If your old Pods use environment variables that are removed in the new version, your app might break. Use readinessProbe to catch this early.

What you learned & what's next

You now know how to perform a rolling update with Deployment safely, with zero downtime. You understand:

  • The mental model of Deployments as fleet managers.
  • The step-by-step mechanics of scaling in/out ReplicaSets.
  • How to set and verify a rolling update using kubectl set image and kubectl rollout status.
  • The differences between RollingUpdate, Recreate, Blue/Green, and Canary strategies.
  • How to troubleshoot stalled rollouts, failing Pods, and rollbacks.

What's next: Now that you can update Deployments, the next step is to automate rollbacks when health checks fail — you'll learn about Deployment rollbacks and how to set up automated recovery with readiness probes and PDBs (Pod Disruption Budgets). This is crucial for production safety. In the next lesson, you'll implement a canary release or blue/green deployment pattern, giving you even finer control over risk.

Pro tip: Always set revisionHistoryLimit in your Deployment spec (default 10) to limit the number of old ReplicaSets kept for rollback. Too many can slow down rollout history.

Practice recap

Practice exercise: Create a Deployment with 5 replicas and a readiness probe. Update the image to a different version (e.g., from nginx:alpine to httpd:alpine). Use kubectl rollout status and kubectl get pods --watch to observe the rolling update in action. Then roll back to the previous revision using kubectl rollout undo deployment/<name>. Verify that Pods return to the original image.

Common mistakes

  • Forgetting to define a readiness probe — Kubernetes doesn't wait for the app to be ready without it, so new Pods might receive traffic before they can serve requests, causing errors.
  • Setting maxSurge or maxUnavailable to 0% — This can stall the rollout because Kubernetes can't start any new Pod or stop any old Pod. Use percentage or integer values (e.g., 25% or 1).
  • Using kubectl delete deployment and re-creating — This causes downtime. Always update the existing Deployment's template to trigger a rolling update.
  • Not verifying the rollout status — Running kubectl set image and walking away ignores potential failures. Always use kubectl rollout status to confirm completion.
  • Assuming all Pods update simultaneously — Rolling updates are gradual by design. If you need all Pods to change at once, use Recreate strategy or blue/green deployment.

Variations

  1. Using kubectl set image vs. kubectl apply -f — The set command is quick for one-off changes, but applying an updated YAML file is more repeatable and version-controlled for CI/CD.
  2. Helm upgrades — When using Helm, rolling updates are triggered automatically when chart values change, using the same underlying Deployment strategy.
  3. Argo Rollouts — For advanced rolling update patterns (canary, blue/green, automated rollbacks), consider Argo Rollouts which extends Kubernetes Deployment with more sophisticated rollout strategies.

Real-world use cases

  • Production web service update — Update a Node.js API from v1.2 to v1.3 with zero downtime while users continue making requests.
  • Database migration alongside code change — Update both a backend image and a configuration map that points to a new database schema version, using readiness probes to prevent traffic until migration completes.
  • Canary rollout of a new feature — Deploy a new version of a payment processing service to 10% of traffic (using Service weights) while the old version handles 90%, gradually shifting as monitoring confirms stability.

Key takeaways

  • A rolling update replaces old Pods with new ones gradually, ensuring zero downtime and controlled rollout speed.
  • The Deployment controller uses two parameters: maxSurge (extra Pods allowed) and maxUnavailable (Pods that can be down), both defaulting to 25%.
  • Always define a readinessProbe so Kubernetes only counts a new Pod as available when it's truly ready to serve traffic.
  • Use kubectl rollout status deployment/<name> to monitor the rollout in real time and kubectl rollout history to track revisions.
  • Rolling updates are reversible with kubectl rollout undo, which reverts to the previous revision.
  • For complex rollouts (canary, blue/green), consider tools like Argo Rollouts or Helm with weighted traffic routing.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.