Kubernetes Deployments Rolling Updates

Kubernetes Deployments: Rolling Updates, Rollbacks & Strategies

EW
Emma Wilson
Site Reliability Engineer
Apr 18, 2025
16 min read

What You'll Learn

Kubernetes Deployments — how to create, configure, and manage rolling updates, rollbacks, scaling, and update strategies with real-world production YAML examples.

Deployment vs ReplicaSet vs Pod

A Deployment is the recommended way to run stateless applications in Kubernetes. It manages ReplicaSets (which manage Pods), enabling declarative updates and easy rollbacks.

Deployment
Manages updates & history
ReplicaSet
Maintains N replicas
Pod 1
Pod 2
Pod 3

Complete Production Deployment YAML

deployment.yaml — Production-grade
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: production
  labels:
    app: my-app
    version: "2.1.0"
  annotations:
    kubernetes.io/change-cause: "Release 2.1.0: Added payment module"
spec:
  replicas: 3

  # Pod selector — NEVER change this after creation!
  selector:
    matchLabels:
      app: my-app

  # Update strategy
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # How many extra pods during update
      maxUnavailable: 0  # Keep all replicas available (zero-downtime)

  # Wait before declaring pod ready (avoids flapping)
  minReadySeconds: 10

  # Keep last 5 ReplicaSets for rollback
  revisionHistoryLimit: 5

  template:
    metadata:
      labels:
        app: my-app
        version: "2.1.0"
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "3000"
    spec:
      terminationGracePeriodSeconds: 60  # Time to drain connections

      # Anti-affinity: spread pods across nodes
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                topologyKey: kubernetes.io/hostname
                labelSelector:
                  matchLabels:
                    app: my-app

      containers:
        - name: app
          image: registry.example.com/my-app:2.1.0
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 3000
              name: http
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "512Mi"
              cpu: "500m"
          env:
            - name: NODE_ENV
              value: "production"
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: db-password
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
          livenessProbe:
            httpGet:
              path: /health/live
              port: 3000
            initialDelaySeconds: 30
            periodSeconds: 20
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /health/ready
              port: 3000
            initialDelaySeconds: 10
            periodSeconds: 10
            failureThreshold: 3
          lifecycle:
            preStop:
              exec:
                command: ["/bin/sh", "-c", "sleep 5"]  # Allow LB to drain
      imagePullSecrets:
        - name: registry-credentials

Update & Rollback Commands

bash
# ─── Deploy / Update ───
kubectl apply -f deployment.yaml
kubectl set image deployment/my-app app=registry.example.com/my-app:2.2.0

# Monitor rollout progress
kubectl rollout status deployment/my-app
kubectl rollout status deployment/my-app --timeout=5m

# ─── Rollback ───
kubectl rollout history deployment/my-app           # View history
kubectl rollout history deployment/my-app --revision=3  # Specific revision
kubectl rollout undo deployment/my-app             # Rollback to previous
kubectl rollout undo deployment/my-app --to-revision=2  # Rollback to specific

# ─── Scaling ───
kubectl scale deployment my-app --replicas=5
kubectl autoscale deployment my-app --min=2 --max=10 --cpu-percent=70

# ─── Pause / Resume rollout ───
kubectl rollout pause deployment/my-app            # Pause (for canary)
kubectl rollout resume deployment/my-app           # Resume

# ─── Restart all pods (without image change) ───
kubectl rollout restart deployment/my-app

# ─── Debugging deployments ───
kubectl get deployment my-app -o yaml
kubectl describe deployment my-app                 # Events + conditions
kubectl get rs -l app=my-app                       # ReplicaSets
kubectl get pods -l app=my-app -o wide             # Pod distribution

Update Strategies Compared

RollingUpdate (Default)

Gradually replaces old pods with new ones. Zero downtime if configured correctly.

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 1
    maxUnavailable: 0

Recreate

Kills all old pods, then creates new ones. Causes downtime but ensures no version mixing.

strategy:
  type: Recreate
# Use for: DB schema migrations,
# single-instance apps that can't
# run multiple versions

Zero-Downtime Deployment Checklist

  • ✅ Set maxUnavailable: 0 to never lose capacity during rollout
  • ✅ Add readinessProbe so traffic only routes to ready pods
  • ✅ Set minReadySeconds to catch issues before proceeding
  • ✅ Add lifecycle.preStop sleep to let load balancer drain connections
  • ✅ Set terminationGracePeriodSeconds > your longest request duration
  • ✅ Add --change-cause annotation to track deployment reasons

Keep Reading

D
DevOps

Docker Networking Demystified: Bridge, Host & Overlay

8 min read Read More
C
Cloud

AWS IAM Roles vs Users vs Policies

10 min read Read More
P
Programming

Understanding Python's GIL & Multiprocessing

14 min read Read More