Lesson 21 of 32 · Level 3 — Application delivery
Release strategies: rolling, blue-green, canary
Choose how new versions reach users: rolling updates (the Kubernetes default), blue-green switches with instant rollback, and canaries that shift traffic gradually while watching metrics, done by hand with Services, Ingress and the Gateway API, or automated with Argo Rollouts and Flagger.
Why strategy matters
Every release is a change, and most incidents follow changes. The release strategy decides how many users see a bad version and how fast you can undo it.
A school changing its lunch menu can swap dishes table by table (rolling), set up a whole second kitchen and switch all tables at once (blue-green, easy to switch back), or let one table taste the new dish first and only serve everyone if that table is happy (canary).
Rolling update (default)
Kubernetes replaces pods a few at a time (lesson 17):
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # at most 1 extra pod during the rollout
maxUnavailable: 0 # never drop below the desired count
- Cheap and automatic; readiness probes gate each step.
- Old and new versions serve traffic at the same time for a while.
- Rollback = another rollout (
kubectl rollout undo), which also takes time. Recreatestops all old pods first: simple, but causes downtime (sometimes needed when two versions can't coexist).
Blue-green
Run two complete Deployments, shop-blue (v1, live) and shop-green (v2), and point the Service at one of them by label:
apiVersion: v1
kind: Service
metadata:
name: shop
spec:
selector: { app: shop, version: blue } # change to green to switch
ports: [ { port: 80, targetPort: http } ]
$ kubectl apply -f shop-green.yaml # deploy v2 alongside v1
$ kubectl rollout status deploy/shop-green
$ kubectl run t --rm -it --image=busybox -- wget -qO- http://shop-green-preview # test v2 directly (a second Service)
$ kubectl patch svc shop -p '{"spec":{"selector":{"app":"shop","version":"green"}}}' # switch
$ kubectl patch svc shop -p '{"spec":{"selector":{"app":"shop","version":"blue"}}}' # instant rollback if needed
- Instant switch and rollback; test the new version fully before users see it.
- Needs double capacity during the release; long-lived connections may stay on the old pods until they close.
Canary
Send a small percentage of traffic to the new version, watch, then increase.
With ingress-nginx (a second, "canary" Ingress for the same host):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop-canary
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10" # 10% of requests
spec:
ingressClassName: nginx
rules:
- host: shop.example.com
http:
paths:
- path: /
pathType: Prefix
backend: { service: { name: shop-v2, port: { number: 80 } } }
With the Gateway API (lesson 20), use weights on HTTPRoute backendRefs (90/10). Service meshes offer the same for internal traffic (see Service Mesh — Istio & Linkerd, lesson 05).
Automate it: progressive delivery
Manual canaries depend on someone watching dashboards. Argo Rollouts and Flagger automate the steps and the decision:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: shop
spec:
replicas: 5
selector:
matchLabels: { app: shop }
template:
metadata:
labels: { app: shop }
spec:
containers:
- name: shop
image: registry.example.com/shop:2.4.0
strategy:
canary:
steps:
- setWeight: 10
- pause: { duration: 10m }
- setWeight: 50
- pause: { duration: 10m }
Add an analysis (a Prometheus query for error rate or latency) so the rollout aborts automatically when metrics degrade. With traffic-routing integrations (ingress, Gateway API, meshes) weights are exact; without them, weights are approximated by replica counts. Argo Rollouts also supports blue-green.
Choosing
| Strategy | Blast radius | Rollback speed | Extra capacity | Needs |
|---|---|---|---|---|
| Rolling | Growing during rollout | Minutes | Small (surge) | Readiness probes |
| Blue-green | All at switch time (after testing) | Seconds | 2× | Two Deployments, selector switch |
| Canary | Small, controlled | Seconds (shift weight back) | Small | Traffic splitting + good metrics |
Whatever you choose:
- Data compatibility: old and new versions overlap, so schema changes use expand → migrate → contract (see SRE & Production Incident Response, lesson 04).
- Feature flags separate deploying code from releasing features, and give the fastest "off switch".
- Decide the abort rule before starting (e.g. error rate above the SLO burn threshold).
Related planning topics: how much capacity a cluster needs (Cluster Design — Architect Track, lesson 04), and proving a platform in a PoC before production (lessons 02–03 of the same track).
Try it: all three
- Deploy podinfo v1 (lesson 17) and do a rolling update to a newer tag while curling in a loop; watch versions mix.
- Build blue and green Deployments with a
versionlabel, switch the Service selector, and switch back. - Add a canary Ingress at 10% and count responses per version over 100 requests; raise it to 50%.
- Install Argo Rollouts, convert the Deployment to a Rollout with the steps above, and use
kubectl argo rollouts get rollout shop --watch. - Make the canary return errors and abort the rollout.
Going deeper: release engineering
- Tie canary analysis to your SLOs (burn-rate queries) rather than ad-hoc thresholds.
- Roll out platform changes (ingress, CNI, policies) progressively too: cluster by cluster, site by site (see GitOps with Argo CD, lesson 07).
- Keep rollback as one action (Git revert,
rollouts abort), and practise it.
Recap
- Rolling: default, cheap, gradual; versions overlap.
- Blue-green: full second copy, instant switch and rollback, double capacity.
- Canary: small share first, metrics decide; automate with Argo Rollouts/Flagger.
- Keep data changes compatible, use feature flags, and agree the abort rule up front.
This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.