Email copiado — support@tuurt.com
Cargando experiencia
devops · October 13, 2026 · 6 min

Blue-green vs canary on GKE: how we pick a deployment strategy for a given release

Blue-green and canary solve the same problem in very different ways. We look at which release signals, and which tooling already sitting in the cluster, decide which one to use on GKE.

By Tuurt Team

Blue-green vs canary on GKE: how we pick a deployment strategy for a given release

Blue-green and canary solve the same underlying problem -shipping a new version without taking the service down- but they solve it through mechanisms different enough that treating them as interchangeable is the most common mistake we see in GKE pipelines. The question that actually matters isn't "which one is better" but "what kind of risk does this release carry, and what rollback mechanism does that risk call for". The answer changes release by release, and a good chunk of that answer depends on what tooling is already installed in the cluster, not just on the textbook description of either strategy.

What each one actually does, without oversimplifying

Blue-green keeps two complete environments running side by side: the one serving production traffic ("blue") and the one with the new version already deployed but not yet receiving real traffic ("green"). The cutover is binary: at switch time, the Service stops pointing at blue's pods and starts pointing at green's. There's no intermediate state where some percentage of users see one version and everyone else sees another.

# The Service only changes its selector, not its definition
apiVersion: v1
kind: Service
metadata:
  name: checkout
spec:
  selector:
    app: checkout
    version: green   # was: blue
  ports:
    - port: 80
      targetPort: 8080

Canary does the opposite: it deploys the new version alongside the old one and routes a fraction of real traffic to it, increasing that fraction in steps while watching metrics along the way. There's no single cutover moment; there's a ramp.

# Argo Rollouts: canary with explicit steps and a pause to observe
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: checkout
spec:
  replicas: 10
  strategy:
    canary:
      steps:
        - setWeight: 10
        - pause: { duration: 5m }
        - setWeight: 50
        - pause: { duration: 10m }
        - setWeight: 100

The difference isn't a matter of taste. It's a difference in what class of problem each mechanism can catch before it hits every user, and in what infrastructure has to be in place to sustain it.

The cost blue-green doesn't hide: duplicated infrastructure

Blue-green needs enough headroom to run two full replicas of the service at the same time during the deployment window: the same pod count, the same reserved resources, the same warmed-up dependencies (database connections, pools, warm caches). That duplication stops being a minor detail on GKE the moment the Horizontal Pod Autoscaler is already keeping the service near the top of its range: rolling out green means the cluster has to absorb, all at once, roughly double the service's usual pod count, even if only for a few minutes.

That cost pushes blue-green toward two scenarios where it's worth paying for: services with predictable traffic where the deployment window is short and scheduled, or releases where the real risk isn't how the code behaves under load but something binary -a schema migration that already ran, an environment variable that changed, a base image version- that either works from the very first request or doesn't work for any of them. In that case canary's gradual ramp buys nothing: if the failure mode is binary, watching it with 10% of traffic for five minutes before reaching 100% only delays a failure that shows up identically on the first request that hits it.

Where canary wins: releases with behavior-under-load risk

Canary earns its cost when the risk isn't "works or doesn't" but "behaves differently under real traffic conditions": a query change that's fast against test data but turns expensive against production's actual data distribution, a timeout tweak that can trigger cascading retries, a library upgrade that shifts memory usage in a way that only shows up after processing a real volume of requests. None of those show up in a staging environment fed with synthetic traffic; they show up once a small but real slice of users is running the new code while everyone else stays on the known-good version as a live comparison point.

That live comparison is exactly why canary is rarely worth doing without an automated, metric-driven rollback, because the whole promise of "catch it before it hits everyone" falls apart if someone has to sit there watching a dashboard during every pause.

# Argo Rollouts with automated analysis: step progression depends on a metric, not a human watching a dashboard
spec:
  strategy:
    canary:
      steps:
        - setWeight: 20
        - analysis:
            templates:
              - templateName: error-rate-checkout
      analysis:
        templates:
          - templateName: error-rate-checkout
        args:
          - name: service-name
            value: checkout
---
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: error-rate-checkout
spec:
  metrics:
    - name: error-rate
      interval: 1m
      successCondition: result < 0.02
      provider:
        prometheus:
          address: http://prometheus.monitoring:9090
          query: |
            sum(rate(http_requests_total{service="checkout",status=~"5.."}[2m]))
            /
            sum(rate(http_requests_total{service="checkout"}[2m]))

Without this AnalysisTemplate -or its Flagger equivalent, if the cluster runs that operator instead of Argo Rollouts- a canary is, in practice, just a slow blue-green with decorative intermediate steps: the traffic fraction still climbs, but nothing actually stops the rollout if something starts failing between one pause and the next.

What really decides it isn't just theory: the tooling already in the cluster

This is where the decision stops being purely technical. A canary with automated metric analysis requires Argo Rollouts or Flagger already installed in the cluster, an AnalysisTemplate (or equivalent) already defined for that specific service, and a reliable metrics source -Prometheus not just installed, but actually scraping whatever the analysis needs to read. If none of that exists yet for a given service, standing up that observability pipeline just to run a single canary isn't free, and for a low-risk release it may not be worth it compared to simply doing blue-green with Kubernetes' native Service, which needs no extra operator at all.

The same applies to fine-grained routing. Splitting traffic by weight at the Kubernetes Service level is limited -load balancing across a Service's endpoints is roughly uniform, not built for arbitrary, stable weights- so a canary with precise percentage control almost always ends up depending on a service mesh like Istio, with a VirtualService defining the weights explicitly, or on Argo Rollouts' own controller managing two Services (canary and stable) and adjusting how many pods sit behind each one to approximate the target weight without a mesh. If the cluster has neither Istio nor Argo Rollouts, "canary with fine traffic control" stops being a realistic option, and the choice between strategies effectively becomes a choice between blue-green and not running canary at all.

What we check before picking a release's deployment strategy

Before deciding how to roll out a release on GKE, we first classify the kind of risk involved: if it's a binary risk -a migration, a config change, a base image version- we go blue-green, because a gradual ramp gives us no useful signal either way. If it's a behavior-under-real-traffic risk -performance, memory usage, interaction with other services- we go canary, because we need a live comparison against the known-good version. Then we confirm the canary actually has an AnalysisTemplate with a metric and a threshold defined up front, because a canary without automated analysis just delays the same failure a blue-green would surface immediately. We also check available capacity in the node pool before a blue-green rollout, since the temporary pod duplication can push the HPA or the cluster autoscaler against a limit we hadn't accounted for. And finally, we look at what operators are actually installed in the cluster -Argo Rollouts, Flagger, Istio- before designing a canary strategy around fine-grained traffic control, because proposing a 5% weight in a VirtualService that doesn't exist isn't a strategy, it's a wish list.

kubernetes gke deployments devops
← Back to blog