15 - Deployments & Rolling Updates

What Is a Deployment?

A Deployment manages ReplicaSets which manage Pods. It provides:

  • Declarative updates (change spec → K8s handles the rest)
  • Rolling updates (zero-downtime deployments)
  • Rollback capability
  • Scaling
  • Pause/resume rollouts
Deployment
    │
    ├── ReplicaSet (v2) ← current (3 pods)
    │     ├── Pod (v2)
    │     ├── Pod (v2)
    │     └── Pod (v2)
    │
    └── ReplicaSet (v1) ← old (0 pods, kept for rollback)

Deployment Manifest

yaml
apiVersion: apps/v1 kind: Deployment metadata: name: web-app labels: app: web-app spec: replicas: 3 # How to find pods this Deployment manages selector: matchLabels: app: web-app # Rolling update strategy strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # Max pods over desired count during update maxUnavailable: 0 # Max pods unavailable during update # How long to wait before considering a new pod available minReadySeconds: 10 # How many old ReplicaSets to keep (for rollback) revisionHistoryLimit: 10 # Pod template (same as Pod spec) template: metadata: labels: app: web-app version: v2 spec: containers: - name: app image: myapp:v2 ports: - containerPort: 8080 resources: requests: cpu: 250m memory: 256Mi limits: cpu: 500m memory: 512Mi readinessProbe: httpGet: path: /ready port: 8080 periodSeconds: 5 livenessProbe: httpGet: path: /health port: 8080 periodSeconds: 10

Deployment Strategies

1. Rolling Update (Default)

Gradually replaces old pods with new ones:

yaml
strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # Create 1 extra pod at a time maxUnavailable: 0 # Always maintain full capacity
Step 1: 3 old pods running
[v1] [v1] [v1]

Step 2: Create 1 new pod (maxSurge=1)
[v1] [v1] [v1] [v2]

Step 3: New pod ready → terminate 1 old pod
[v1] [v1] [v2]

Step 4: Create another new pod
[v1] [v1] [v2] [v2]

Step 5: New pod ready → terminate 1 old pod
[v1] [v2] [v2]

Step 6: Create last new pod
[v1] [v2] [v2] [v2]

Step 7: New pod ready → terminate last old pod
[v2] [v2] [v2]

Done! Zero downtime.

2. Recreate

Kill all old pods, then create new ones (has downtime):

yaml
strategy: type: Recreate
Step 1: [v1] [v1] [v1]
Step 2: [  ] [  ] [  ]   ← DOWNTIME
Step 3: [v2] [v2] [v2]

Use when: App can't run two versions simultaneously (e.g., database schema incompatibility).

3. Blue-Green (Manual)

Run two full environments, switch traffic:

yaml
# Blue deployment (current) apiVersion: apps/v1 kind: Deployment metadata: name: web-blue spec: replicas: 3 selector: matchLabels: app: web version: blue template: metadata: labels: app: web version: blue spec: containers: - name: app image: myapp:v1 --- # Green deployment (new version) apiVersion: apps/v1 kind: Deployment metadata: name: web-green spec: replicas: 3 selector: matchLabels: app: web version: green template: metadata: labels: app: web version: green spec: containers: - name: app image: myapp:v2 --- # Service points to blue apiVersion: v1 kind: Service metadata: name: web spec: selector: app: web version: blue # Switch to "green" to cut over ports: - port: 80 targetPort: 8080
bash
# Switch traffic to green kubectl patch svc web -p '{"spec":{"selector":{"version":"green"}}}' # Rollback: switch back to blue kubectl patch svc web -p '{"spec":{"selector":{"version":"blue"}}}'

4. Canary (Manual or with Service Mesh)

Route a small percentage of traffic to the new version:

yaml
# Stable deployment (90% traffic) apiVersion: apps/v1 kind: Deployment metadata: name: web-stable spec: replicas: 9 selector: matchLabels: app: web track: stable template: metadata: labels: app: web track: stable spec: containers: - name: app image: myapp:v1 --- # Canary deployment (10% traffic) apiVersion: apps/v1 kind: Deployment metadata: name: web-canary spec: replicas: 1 # 1 out of 10 pods = ~10% traffic selector: matchLabels: app: web track: canary template: metadata: labels: app: web track: canary spec: containers: - name: app image: myapp:v2 --- # Service selects ALL pods with app=web (both stable and canary) apiVersion: v1 kind: Service metadata: name: web spec: selector: app: web # Matches both track=stable and track=canary ports: - port: 80 targetPort: 8080

For precise traffic splitting, use Istio, Linkerd, or Argo Rollouts.

Performing Updates

bash
# Update image (triggers rolling update) kubectl set image deployment/web-app app=myapp:v3 # Or edit the YAML kubectl edit deployment web-app # Or apply updated manifest (recommended) kubectl apply -f deployment.yaml # Update with a record (for rollback annotation) kubectl set image deployment/web-app app=myapp:v3 --record

Monitoring Rollouts

bash
# Watch rollout status kubectl rollout status deployment/web-app # Waiting for deployment "web-app" rollout to finish: # 2 out of 3 new replicas have been updated... # deployment "web-app" successfully rolled out # See rollout history kubectl rollout history deployment/web-app # REVISION CHANGE-CAUSE # 1 <none> # 2 kubectl set image deployment/web-app app=myapp:v2 # 3 kubectl set image deployment/web-app app=myapp:v3 # See details of a specific revision kubectl rollout history deployment/web-app --revision=2

Rollbacks

bash
# Rollback to previous version kubectl rollout undo deployment/web-app # Rollback to specific revision kubectl rollout undo deployment/web-app --to-revision=1 # Check which revision is active kubectl describe deployment web-app | grep "revision"

Pause and Resume

bash
# Pause rollout (make multiple changes without triggering multiple rollouts) kubectl rollout pause deployment/web-app # Make changes kubectl set image deployment/web-app app=myapp:v4 kubectl set resources deployment/web-app -c app --limits=cpu=500m,memory=512Mi # Resume (single rollout with all changes) kubectl rollout resume deployment/web-app

Scaling

bash
# Manual scaling kubectl scale deployment/web-app --replicas=5 # Or edit the manifest kubectl patch deployment web-app -p '{"spec":{"replicas":5}}'

For auto-scaling, see 21 - Auto-Scaling.

Deployment Conditions

bash
kubectl describe deployment web-app
ConditionMeaning
AvailableMinimum replicas are available
ProgressingRollout is in progress
ReplicaFailureFailed to create pods

kubectl Deployment Commands

bash
# Create kubectl create deployment web --image=nginx:alpine --replicas=3 # List kubectl get deployments kubectl get deploy # Describe kubectl describe deployment web-app # Delete kubectl delete deployment web-app # Restart all pods (rolling restart) kubectl rollout restart deployment/web-app

FAANG Interview Angle

Common questions:

  1. "How do you achieve zero-downtime deployments in Kubernetes?"
  2. "Explain rolling update strategy and its parameters"
  3. "Compare blue-green, canary, and rolling update strategies"
  4. "How do you rollback a failed deployment?"
  5. "What happens if a new pod fails readiness checks during rollout?"

Key answers:

  • Rolling updates with readiness probes; maxSurge/maxUnavailable control the pace
  • maxSurge: extra pods allowed. maxUnavailable: pods that can be down. Both 0 = impossible
  • Rolling: gradual, built-in. Blue-green: instant switch, double resources. Canary: test with subset
  • kubectl rollout undo; K8s keeps old ReplicaSets for rollback
  • Rollout stalls; old pods continue serving; deployment shows "Progressing" condition

Official Links