Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Blue-Green and Canary Deploys on Kubernetes

By Kokil Thapa | Last reviewed: September 2026

Releases fail when you push a new container image straight to every pod at once. Blue-Green and Canary Deploys on Kubernetes give you a safer path: run the new version beside the old one, send real traffic in controlled steps, and roll back by flipping a selector or weight. If you already run workloads on a cluster, these patterns fit naturally on top of Deployments, Services, and Ingress. This guide walks through practical manifests, traffic-split mechanics, and the trade-offs I weigh on production systems—including Laravel apps on Kubernetes and CI pipelines that mirror bare-metal blue-green CI/CD workflows.

What is the difference between Blue-Green and Canary Deploys on Kubernetes?

Both strategies reduce blast radius during a release. They differ in how fast traffic moves and how much observability you need before full promotion.

Blue-green keeps two full stacks alive. Stable pods sit behind one Service label set; candidate pods sit behind another. You validate green, then switch 100% of traffic in one step—usually by updating a Service selector or swapping an Ingress backend. Rollback is equally fast: point traffic back to blue.

Canary sends a small slice of live traffic to the new version first—often 5%, then 25%, then 50%, then 100%. You watch error rates, latency, and business metrics between steps. If metrics degrade, you drain canary weight to zero without touching stable pods.

Blue-Green vs Canary on KubernetesBlue-GreenTwo full stacksInstant 100% switchFast rollbackCanaryShared stable + newGradual weight stepsMetric-gated promoteShared Kubernetes primitivesDeployments · Services · Ingress · HPAOptional: Argo Rollouts · Istio · Linkerd
Blue-Green and Canary Deploys on Kubernetes both run parallel versions but differ in traffic shift speed and validation depth.

Native Kubernetes Deployments use a RollingUpdate strategy by default. That is neither blue-green nor canary—it replaces pods incrementally with limited surge. For true blue-green or weighted canary, you add either manual Service wiring or a progressive delivery tool.

CriteriaBlue-GreenCanaryRollingUpdate (built-in)
Traffic shiftInstant 0→100%Gradual weightsPod-by-pod replacement
Resource cost2× pods during cutover1× + small canary slice~1× with surge
Rollback speedSeconds (selector flip)Drain canary weightkubectl rollout undo
Metric gatesManual pre-switch checksAutomated between stepsNone native
ComplexityLow with two ServicesMedium—needs Ingress or meshLowest
Best fitSchema migrations, big jumpsHigh-traffic APIs, A/B riskSmall teams, low risk

For a deeper strategy-only comparison, see the dedicated write-up on blue-green vs canary deployment strategies.

How do you implement a Blue-Green deployment on Kubernetes?

Blue-green on Kubernetes usually means two Deployments and one active Service selector. Stable runs as app=myapp,version=blue; candidate runs as app=myapp,version=green. Only one version receives production traffic at a time.

Step 1: Deploy both versions

Create separate Deployments so each version scales independently. Keep image tags explicit—never rely on :latest in production.

# blue-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-blue
  labels:
    app: myapp
    version: blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: blue
  template:
    metadata:
      labels:
        app: myapp
        version: blue
    spec:
      containers:
      - name: app
        image: registry.example.com/myapp:2.4.0
        ports:
        - containerPort: 8080
---
# green-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-green
  labels:
    app: myapp
    version: green
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: green
  template:
    metadata:
      labels:
        app: myapp
        version: green
    spec:
      containers:
      - name: app
        image: registry.example.com/myapp:2.5.0
        ports:
        - containerPort: 8080

Step 2: Wire the active Service

Point your production Service at blue initially. Green pods start but receive no traffic until you patch the selector.

apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
    version: blue
  ports:
  - port: 80
    targetPort: 8080

Step 3: Validate green, then switch

Run smoke tests against green through a headless or internal Service. When satisfied, flip the selector to green.

kubectl apply -f green-deployment.yaml
kubectl run curl-test --rm -it --image=curlimages/curl -- \
  curl -sf http://myapp-green-internal:8080/health

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

Rollback is the same patch with "version":"blue". Keep blue scaled for one release cycle if disk and budget allow. That gives you an instant fallback without rebuilding pods.

Blue-Green Traffic SwitchIngressServiceselector: blueBlue Podsv2.4.0Green Podsv2.5.0 idleAfter validation: patch selector to greenServiceselector: greenBlue Podsidle standbyGreen Podslive trafficRollback = patch selector back to blueSeconds, no image rebuild required
Blue-Green Deploys on Kubernetes flip production traffic by changing the Service selector after green passes health checks.

On clusters I help maintain, I pair this pattern with Velero backups before schema changes. Blue-green gives you a clean cutover window; backups cover the rare case where rollback needs data repair too.

How do you run a Canary deployment on Kubernetes with traffic splitting?

Canary needs a layer that understands weights. Plain ClusterIP Services round-robin evenly—they cannot send 10% to canary. You typically use Ingress canary annotations, a service mesh, or Argo Rollouts.

Option A: NGINX Ingress canary annotations

If your cluster runs the NGINX Ingress Controller, annotate a second Ingress resource to mirror the stable one but route by weight or header.

# stable ingress (existing)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-stable
spec:
  ingressClassName: nginx
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-stable
            port:
              number: 80
---
# canary ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  ingressClassName: nginx
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-canary
            port:
              number: 80

Increase weight in steps: 10 → 25 → 50 → 100. Watch Prometheus or your APM between each bump. Drop weight to zero if error rate spikes.

Option B: Argo Rollouts

Argo Rollouts replaces Deployment for progressive delivery. It integrates with NGINX, Istio, and ALB for automated weight shifts and analysis runs.

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: myapp
spec:
  replicas: 5
  strategy:
    canary:
      steps:
      - setWeight: 10
      - pause: {duration: 5m}
      - setWeight: 25
      - pause: {duration: 5m}
      - setWeight: 50
      - pause: {duration: 5m}
      - setWeight: 100
      canaryService: myapp-canary
      stableService: myapp-stable
      trafficRouting:
        nginx:
          stableIngress: myapp-stable
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: app
        image: registry.example.com/myapp:2.5.0
        ports:
        - containerPort: 8080

GitOps teams often manage Rollouts through Argo CD. The Rollout CRD owns promotion logic; Argo CD syncs the desired state from Git.

Canary Weight Progression5% Canary95% Stable25% CanaryMetrics OK50% CanarySoak test100% PromoteStable updatedAutomated analysis between stepsHTTP 5xx rate · p99 latency · custom PromQLFail → abort canary, weight returns to 0%Pass → increase weight, old stable retired at 100%Argo Rollouts · Istio VirtualService · NGINX canary
Canary Deploys on Kubernetes increase traffic weight in gated steps while monitoring error and latency thresholds.

Validate JSON health payloads during canary soak with a local JSON formatter before you wire automated analysis queries. Small schema drift in /health responses has caused false-positive rollbacks for me.

Which tools support Blue-Green and Canary Deploys on Kubernetes?

Pick tooling based on what you already run. Adding Istio solely for canary is heavy if you only ship twice a month.

  • Native kubectlkubectl rollout status and kubectl rollout undo for RollingUpdate; manual Service patches for blue-green.
  • NGINX Ingress — Canary annotations by weight, header, or cookie. No mesh required.
  • Argo Rollouts — CRD with built-in steps, analysis templates, and rollback.
  • Istio / Linkerd — Fine-grained traffic split via VirtualService or TrafficSplit.
  • Flagger — Operator that automates canary with Prometheus, Grafana, or CloudWatch checks.
  • Helm — Package dual Deployments and Ingress pairs; see Helm charts for Kubernetes apps.

The official Kubernetes Deployment documentation covers RollingUpdate well. It does not replace progressive delivery controllers for weighted canary—you extend the platform with Ingress or a Rollout CRD.

For autoscaling during canary, tie Horizontal Pod Autoscaling to both stable and canary Deployments. A 10% traffic slice still needs enough canary replicas to handle peak RPS without throttling.

When should you choose Blue-Green vs Canary on Kubernetes?

Neither pattern wins every time. Match the strategy to release risk, traffic volume, and team maturity.

Choose Your Deploy StrategyNew release ready?DB schema change?Needs instant cutoverUse Blue-GreenHigh traffic API?Need metric gatesUse CanaryLow risk patch? → RollingUpdate
Decision flow for Blue-Green and Canary Deploys on Kubernetes based on schema changes, traffic volume, and observability needs.

Choose blue-green when:

  1. You run database migrations that require a hard cutover window.
  2. Your app cannot serve two API versions simultaneously.
  3. You need rollback in seconds without gradual drain.
  4. Traffic is moderate and doubling pod count briefly is affordable—often Rs 8,000–15,000/month (~USD 60–110) extra on a small DOKS cluster.

Choose canary when:

  1. You serve high RPS APIs where 1% bad traffic still hurts revenue.
  2. Prometheus or Datadog already tracks SLIs you trust.
  3. You release frequently and want promotion automated in CI.
  4. You can tolerate longer rollout windows—30–90 minutes is normal.

On a production Laravel booking app, I default to canary for API pods and blue-green for worker Deployments. Workers do not sit behind Ingress; flipping their Deployment is cleaner than partial queues.

What are common mistakes with Blue-Green and Canary Deploys on Kubernetes?

These patterns fail in predictable ways. Most are configuration gaps, not Kubernetes bugs.

Shared state and session stickiness

Blue-green breaks when sessions live in pod memory. Externalize sessions to Redis 8.10 or a database before you attempt either pattern. Canary has the same requirement—users routed to canary must not lose auth state.

Forgetting readiness probes

Green pods marked Ready before the app accepts traffic cause 502s the moment you switch. Align readinessProbe with real dependencies—DB, cache, migrations complete. Debug failing pods with the steps in CrashLoopBackOff troubleshooting.

Canary without metrics

Manual weight bumps without SLI checks are just slow rolling updates. Define abort thresholds upfront: HTTP 5xx above 1%, p99 latency 2× baseline, or business KPI dips.

Resource quotas and HPA conflicts

Blue-green at 2× replicas can hit namespace quotas. Pre-scale green before cutover. Review resource limits and requests so neither stack gets OOMKilled under load.

Ignoring DNS and Ingress caching

Some CDNs cache by URL regardless of backend. Purge edge cache after blue-green switch. Canary header routing fails if clients ignore custom headers—use weight-based splits for browser traffic.

Lock down who can patch production Services. A mistaken selector flip is a production incident. Tight RBAC policies limit patch rights to your CD pipeline service account.

Key Takeaways

  • Blue-Green and Canary Deploys on Kubernetes run parallel versions; blue-green switches traffic instantly via Service selectors, canary shifts weight in gated steps.
  • Plain Deployments only offer RollingUpdate—add NGINX Ingress canary annotations, Argo Rollouts, or a mesh for true weighted canary.
  • Validate green internally before patching the production Service; keep blue scaled briefly for fast rollback.
  • Automate canary promotion with SLI checks—error rate, latency, and custom PromQL—not manual guesswork.
  • Externalize sessions and state before either pattern; readiness probes must reflect real app readiness.
  • Match strategy to risk: schema migrations favor blue-green; high-traffic APIs favor canary with observability.

People Also Ask

Can Kubernetes Deployments do canary releases natively?

No. Standard Deployments support RollingUpdate and Recreate only. Weighted canary requires Ingress annotations, a service mesh, or a progressive delivery controller like Argo Rollouts. You can approximate canary by running two Deployments and manually adjusting replica counts, but that is coarse and not weight-accurate.

How is blue-green different from a RollingUpdate?

RollingUpdate replaces old pods incrementally while traffic always hits a mixed pool. Blue-green keeps 100% of traffic on one version until you deliberately switch. Rollback with RollingUpdate uses revision history; blue-green rollback is a Service selector patch back to the idle stack.

Does blue-green deployment cost more on Kubernetes?

Yes, temporarily. You run two full replica sets during the overlap window. Plan for roughly double CPU and memory until you scale down blue. Canary usually costs less because the new version starts at a small replica count and traffic slice.

What is the fastest rollback method after a bad canary?

Set canary Ingress weight to zero or run kubectl argo rollouts abort myapp if you use Argo Rollouts. Stable pods never left the pool, so traffic returns immediately. Then investigate the failed image tag before retrying.

Ship safer releases on Kubernetes

Blue-Green and Canary Deploys on Kubernetes turn releases from a single risky event into a controlled experiment. Start with manual blue-green on two Deployments if your team is new to the cluster. Add Argo Rollouts or Ingress canary once Prometheus dashboards and runbooks exist. The goal is not fancy tooling—it is sleeping through deploy night.

If you want help designing a progressive delivery pipeline for your app—or migrating from symlink Deployer releases to Kubernetes—Linux and Kubernetes administration and ongoing support cover cluster setup through production runbooks. See how similar systems were shipped on Adventure Third Pole Trek and Notary Kathmandu, or contact us to plan your rollout strategy.

Frequently Asked Questions

Both run two application versions in parallel on the same cluster instead of replacing every pod at once. Blue-green keeps a stable stack (blue) and a candidate stack (green), then shifts production traffic in one step—usually by changing a Service selector or Ingress backend. Canary sends a small live traffic slice to the new version first, then increases weight in gated steps while you watch error rates and latency. Either pattern lets you promote after validation or roll back without rebuilding the stable stack.

Both reduce release blast radius, but they differ in speed and validation depth. Blue-green runs two full replica sets and switches traffic instantly from 0% to 100% on the candidate after pre-switch checks. Rollback is equally fast—a selector flip back to the idle stack. Canary starts with a small weight (often 5–10%), bumps through steps like 25%, 50%, then 100%, with metric gates between each step. If SLIs degrade, you drain canary weight to zero without touching stable pods. Blue-green suits hard cutovers; canary suits high-traffic APIs where even 1% bad traffic hurts.

No. Standard Deployments only support RollingUpdate and Recreate strategies. Weighted canary needs Ingress annotations, a service mesh, or a progressive delivery controller like Argo Rollouts.

RollingUpdate replaces old pods incrementally while traffic always hits a mixed pool of old and new versions—there is no clean separation. Blue-green keeps 100% of production traffic on one version until you deliberately switch via a Service selector patch or Ingress backend swap. Rollback with RollingUpdate uses kubectl rollout undo against revision history. Blue-green rollback patches the Service back to the idle stack in seconds. RollingUpdate costs roughly one replica set with surge; blue-green temporarily doubles pod count during the overlap window.

Create two separate Deployments with distinct version labels—for example app=myapp,version=blue and app=myapp,version=green—each with explicit image tags, never :latest. Point your production Service selector at blue initially so green pods start but receive no traffic. Validate green through an internal or headless Service with smoke tests against /health. When satisfied, patch the Service selector to version=green. Rollback is the same patch with version=blue. On clusters I help maintain, I pair this with Velero backups before schema changes so rollback covers data repair if needed.

Plain ClusterIP Services round-robin evenly and cannot send 10% to canary—you need a weight-aware layer. With NGINX Ingress Controller, annotate a second Ingress with nginx.ingress.kubernetes.io/canary: "true" and nginx.ingress.kubernetes.io/canary-weight, then bump weight in steps: 10 → 25 → 50 → 100 while watching Prometheus or your APM. Argo Rollouts replaces Deployment for automated progressive delivery with pause steps and analysis runs; GitOps teams often sync Rollouts through Argo CD. Tie Horizontal Pod Autoscaling to both stable and canary Deployments so a 10% slice still has enough replicas at peak RPS.

Pick based on what you already run—adding Istio solely for canary is heavy if you ship twice a month. Native kubectl handles RollingUpdate rollbacks and manual Service patches for blue-green. NGINX Ingress supports canary by weight, header, or cookie without a mesh. Argo Rollouts adds CRD-based steps, analysis templates, and automated rollback. Istio and Linkerd split traffic via VirtualService or TrafficSplit. Flagger automates canary with Prometheus, Grafana, or CloudWatch checks. Helm packages dual Deployments and Ingress pairs. The official Kubernetes Deployment docs cover RollingUpdate well but do not replace progressive delivery controllers for weighted canary.

Match strategy to release risk, traffic volume, and observability maturity. Choose blue-green when database migrations need a hard cutover window, the app cannot serve two API versions simultaneously, or you need rollback in seconds without gradual drain. Choose canary when you serve high-RPS APIs where 1% bad traffic still hurts revenue, Prometheus or Datadog already tracks SLIs you trust, and you release frequently with automated CI promotion. On a production Laravel booking app, I default to canary for API pods and blue-green for worker Deployments—workers do not sit behind Ingress, so flipping their Deployment is cleaner than partial queues.

Yes, temporarily—you run two full replica sets during the overlap window, roughly doubling CPU and memory until you scale down the idle stack.

Most failures are configuration gaps, not Kubernetes bugs. Sessions stored in pod memory break both patterns—externalize to Redis 8.10 or a database first. Readiness probes that mark pods Ready before DB, cache, and migrations are complete cause 502s the moment you switch. Manual canary weight bumps without SLI checks are just slow rolling updates; define abort thresholds upfront. Blue-green at 2× replicas can hit namespace quotas—pre-scale green before cutover. CDNs cache by URL regardless of backend, so purge edge cache after a blue-green switch. Lock down who can patch production Services with tight RBAC on your CD pipeline service account.

Set canary Ingress weight to zero, or run kubectl argo rollouts abort myapp if you use Argo Rollouts. Stable pods never left the pool.

If green or canary pods are marked Ready before the application truly accepts traffic, you get 502 errors the moment traffic shifts. Align readinessProbe with real dependencies: database connectivity, cache availability, and completed migrations. Debug pods stuck in a bad state using CrashLoopBackOff troubleshooting steps before you flip selectors or increase canary weight. On canary rollouts, the same probe misconfiguration causes false confidence during weight bumps—Prometheus may look fine while new pods reject connections. Treat readiness as a gate, not a formality.

Blue-green breaks when sessions live in pod memory—a user authenticated on blue loses state when traffic moves to green. Canary has the same requirement because users routed to the canary slice must not lose auth state mid-request. Externalize sessions to Redis 8.10 or a database before attempting either pattern. For blue-green with schema migrations, I pair the cutover window with Velero backups so rollback covers the rare case where traffic reversion also needs data repair. Shared in-pod caches and local file uploads need the same externalization treatment.

Manual weight bumps without SLI checks are just slow rolling updates dressed up as progressive delivery. Define abort thresholds before the first canary step: HTTP 5xx above 1%, p99 latency at 2× baseline, or dips in business KPIs you already track in Prometheus or Datadog. Increase NGINX canary weight in steps—10 → 25 → 50 → 100—and watch dashboards between each bump. With Argo Rollouts, wire analysis templates into pause steps so promotion is automated, not guesswork. Validate JSON health payloads during canary soak; small schema drift in /health responses has caused false-positive rollbacks for me.

A mistaken Service selector patch is a production incident as severe as shipping a bad image. Lock down who can patch production Services—tight RBAC policies should limit patch rights to your CD pipeline service account, not individual developers with broad cluster-admin access. The same applies to canary Ingress weight annotations: anyone who can edit Ingress in the production namespace can redirect live traffic. Audit changes through GitOps where Argo CD syncs desired Rollout state from Git rather than ad-hoc kubectl patch commands. Treat traffic-switch permissions as production-critical, on par with secrets access.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: