Frontend Labs
⋯

14. Deployments, ReplicaSets, and rollouts

14.1 The Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: catalog
  labels: { app.kubernetes.io/name: catalog, app.kubernetes.io/part-of: orbit }
spec:
  replicas: 3
  revisionHistoryLimit: 5
  selector:
    matchLabels: { app.kubernetes.io/name: catalog }     # IMMUTABLE after creation
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25%          # extra pods allowed above replicas during rollout
      maxUnavailable: 0      # never go below desired capacity
  minReadySeconds: 10        # a new pod must stay Ready 10s before it "counts"
  progressDeadlineSeconds: 300
  template:
    metadata:
      labels: { app.kubernetes.io/name: catalog, app.kubernetes.io/part-of: orbit }
    spec:
      containers:
        - name: catalog
          image: orbit-catalog:dev
          ports: [{ name: http, containerPort: 8080 }]
          readinessProbe: { httpGet: { path: /readyz, port: http }, periodSeconds: 5 }

Deployment → manages ReplicaSets (one per pod-template version) → manages Pods. A rolling update scales the new ReplicaSet up and the old one down within the maxSurge/maxUnavailable budget, gated on readiness. That is why readiness probes are what make rollouts safe.

Setting Effect
maxUnavailable: 0, maxSurge: 1 slowest, safest; needs spare capacity for 1 extra pod
maxUnavailable: 25%, maxSurge: 25% default; faster, temporarily reduced capacity
strategy: Recreate kill all, then start new; for apps that can't run two versions at once (some DB-migration-coupled apps, single-writer apps)
minReadySeconds catches "starts fine, crashes 5 s later" before the rollout proceeds
progressDeadlineSeconds marks the rollout Progressing=False so CI/CD can detect a stuck deploy

14.2 Rolling out and rolling back

kubectl set image deploy/catalog catalog=orbit-catalog:v2   # (demo only; GitOps in real life)
kubectl rollout status deploy/catalog --timeout=5m           # CI uses this exit code
kubectl rollout history deploy/catalog
kubectl rollout undo deploy/catalog                         # back to previous ReplicaSet
kubectl rollout undo deploy/catalog --to-revision=3
kubectl rollout restart deploy/catalog                      # new pods, same spec (e.g. reload a Secret)
kubectl rollout pause deploy/catalog                        # batch several changes into one rollout

Try a broken rollout to see the safety net:

kubectl set image deploy/catalog catalog=orbit-catalog:does-not-exist
kubectl get pods -l app.kubernetes.io/name=catalog   # old pods still serving; new one ImagePullBackOff
kubectl rollout status deploy/catalog                # eventually: "exceeded its progress deadline"
kubectl rollout undo deploy/catalog

With maxUnavailable: 0, a bad image never reduces capacity. The rollout stalls with all old pods still serving.

Best practice: kubectl rollout undo is a break-glass tool. In a GitOps setup the next sync reverts it. The durable rollback is reverting the Git commit (§36).

14.3 Why selector and labels matter

The selector is how a ReplicaSet finds "its" pods. If two Deployments' selectors overlap, they fight over pods. Use the recommended labels consistently:

labels:
  app.kubernetes.io/name: orders          # what it is
  app.kubernetes.io/instance: orders-prod # which instance
  app.kubernetes.io/version: "1.4.2"      # NOT in the selector (it changes every release)
  app.kubernetes.io/component: api
  app.kubernetes.io/part-of: orbit
  app.kubernetes.io/managed-by: kustomize

Generated from real-life-k8s-guide.md · 8 Oct 2026 16:36