Skip to content
daniel@cosenza:~/blog
SRE & DevOpsHow-To September 2, 2025 3 min read

How to Implement Blue-Green and Canary Deployments in Kubernetes

Two complete, working deployment strategies for shipping a new version with minimal risk — instant-rollback blue-green, and gradual, traffic-controlled canary.

Both blue-green and canary deployments solve the same underlying problem — reducing the blast radius of a bad release — through different mechanisms. This walks through a complete, working setup for each using plain Kubernetes primitives, no additional tooling required.

Blue-Green: two full environments, instant switch

Step 1: deploy the current version as “blue”

# deployment-blue.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-blue
spec:
  replicas: 3
  selector:
    matchLabels: {app: myapp, version: blue}
  template:
    metadata:
      labels: {app: myapp, version: blue}
    spec:
      containers:
        - name: myapp
          image: myapp:v1.0

Step 2: point the live Service at blue

apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
    version: blue      # <- this line controls which version receives traffic
  ports:
    - port: 80
      targetPort: 8080

Step 3: deploy the new version as “green,” fully, alongside blue

# deployment-green.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-green
spec:
  replicas: 3
  selector:
    matchLabels: {app: myapp, version: green}
  template:
    metadata:
      labels: {app: myapp, version: green}
    spec:
      containers:
        - name: myapp
          image: myapp:v2.0
kubectl apply -f deployment-green.yaml

Green runs fully, receiving zero production traffic, while you test it directly (port-forwarding to it, or a separate internal test Service pointed at version: green).

Step 4: switch traffic instantly

kubectl patch service myapp -p '{"spec":{"selector":{"version":"green"}}}'

All traffic now goes to green, instantly — no rolling transition period.

Step 5: roll back just as instantly, if needed

kubectl patch service myapp -p '{"spec":{"selector":{"version":"blue"}}}'

Since blue never stopped running, rollback is exactly as instant as the cutover was — the old version was never scaled down.

Step 6: clean up the old version once confident

kubectl delete deployment myapp-blue

Canary: gradual, traffic-percentage-based rollout

Step 1: run stable and canary as separate deployments, unequal replica counts

# deployment-stable.yaml — 9 replicas
metadata: {name: myapp-stable}
spec:
  replicas: 9
  template:
    metadata: {labels: {app: myapp, track: stable}}
    spec: {containers: [{name: myapp, image: "myapp:v1.0"}]}
# deployment-canary.yaml — 1 replica
metadata: {name: myapp-canary}
spec:
  replicas: 1
  template:
    metadata: {labels: {app: myapp, track: canary}}
    spec: {containers: [{name: myapp, image: "myapp:v2.0"}]}

Step 2: one Service selecting both, by the shared label only

apiVersion: v1
kind: Service
metadata: {name: myapp}
spec:
  selector: {app: myapp}      # matches BOTH stable and canary pods
  ports: [{port: 80, targetPort: 8080}]

Because the Service selects on app: myapp alone (not track), and kube-proxy load-balances roughly evenly across all matching pod IPs, a 9:1 replica ratio approximates 10% of traffic reaching the canary — a simple, dependency-free way to achieve percentage-based traffic splitting using nothing but replica counts.

Step 3: monitor the canary closely

kubectl logs -l track=canary --tail=100 -f

Watch error rates and latency for the canary pod specifically, comparing against the stable fleet, before deciding whether to proceed.

Step 4: gradually shift the ratio

kubectl scale deployment myapp-canary --replicas=3
kubectl scale deployment myapp-stable --replicas=7

Incrementally rebalance the replica counts toward the canary as confidence grows, watching metrics at each step.

Step 5: complete or abort the rollout

To complete: scale canary to the full replica count and remove myapp-stable entirely. To abort: scale canary back to 0 and delete it, leaving stable fully serving traffic exactly as before the canary was introduced.

Choosing between them

Blue-green is the right choice when you need an instant, all-or-nothing cutover and rollback — appropriate for changes you’re fairly confident about but want a fast escape hatch for. Canary is the right choice when you want to limit exposure to a smaller fraction of real traffic first, catching a problem before it affects everyone, at the cost of a more gradual, closely-monitored rollout process. Production systems handling significant traffic commonly use a proper service mesh (Istio, Linkerd) for precise percentage-based canary routing rather than the replica-ratio approximation shown here — this walkthrough uses only plain Kubernetes primitives specifically to show the underlying mechanism without additional infrastructure dependencies.