· Updated · 4 min read

Why we default to Argo Rollouts for canary deploys

Plain Kubernetes Deployments treat every release as all-or-nothing. Argo Rollouts gives you a safer middle path.

KubernetesProgressive deliveryArgo

The default Kubernetes Deployment object is fine until the day a bad release takes production down. A rolling update replaces pods gradually, but it only checks that new pods start and pass their readiness probes — not whether they return errors to users. There's no built-in concept of "ship to 5% first, watch for errors, then proceed." Teams either build that logic themselves or learn the hard way. We almost always recommend Argo Rollouts instead.

What it actually adds

Argo Rollouts replaces the Deployment object with a Rollout resource that supports canary and blue-green strategies natively. The pod template stays the same. You add a strategy that declares the steps, and the controller manages the traffic shift, the pauses, the health checks, and the rollback if anything fails:

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: checkout
spec:
  replicas: 10
  strategy:
    canary:
      canaryService: checkout-canary
      stableService: checkout-stable
      trafficRouting:
        nginx:
          stableIngress: checkout
      analysis:
        templates:
          - templateName: error-rate
        args:
          - name: service
            value: checkout
      steps:
        - setWeight: 5
        - pause: { duration: 2m }
        - setWeight: 25
        - pause: { duration: 5m }
        - setWeight: 50
        - pause: { duration: 5m }
  # selector and template exactly as in a Deployment

Without a traffic router, Argo Rollouts approximates weights by scaling replicas — one canary pod out of ten is roughly 10%. With one, the split is exact, and 5% means 5% even when you only run three pods.

Automated analysis from metrics

The killer feature is analysis. An AnalysisTemplate defines what "healthy" means in terms of your own metrics — Prometheus, Datadog, CloudWatch, and others are supported — and the Rollout runs it in the background while the canary steps progress:

apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: error-rate
spec:
  args:
    - name: service
  metrics:
    - name: error-rate
      interval: 1m
      failureLimit: 1
      successCondition: result[0] < 0.005
      provider:
        prometheus:
          address: http://prometheus.monitoring:9090
          query: |
            sum(rate(http_requests_total{service="{{args.service}}",code=~"5.."}[2m]))
            /
            sum(rate(http_requests_total{service="{{args.service}}"}[2m]))

If the canary fails that gate, Argo aborts and shifts all traffic back to the stable version automatically. No on-call paged, no manual decision in the middle of the night. Pick metrics that reflect what users experience — error rate and latency at the edge — rather than CPU or memory, and make sure the canary sees enough traffic during each step for the numbers to mean something.

Works with the ingress you already have

Argo Rollouts integrates with most ingress controllers and service meshes for traffic splitting, including NGINX, AWS ALB, Traefik, and Istio. You don't need a service mesh just for canaries — for most teams, NGINX or ALB integration is enough. A mesh starts to make sense when you also want canaries for internal, service-to-service traffic.

Canary or blue-green?

  • Canary suits stateless services with steady traffic: the new version proves itself on a small share of real users before everyone gets it.
  • Blue-green suits services where running two versions side by side on live traffic is awkward, or where you want to test the new stack in full before switching. It needs capacity for two complete copies during the switch.
  • Either way, keep database changes backward compatible, because old and new versions run against the same schema at the same time.

Fitting it into GitOps

Rollouts are plain Kubernetes resources, so they live in Git next to everything else and Argo CD syncs them like any other manifest. A merge updates the image tag; the Rollout takes it from there. The kubectl plugin and dashboard show each step's progress, and kubectl argo rollouts promote or abort gives you manual control when you need it.

Migration can be gradual too. A Rollout can point at an existing Deployment's pod template with workloadRef, so you can switch one service at a time without rewriting manifests.

When it's overkill

If you ship rarely, have a small surface area, or don't yet have meaningful production metrics, the operational cost of running Argo Rollouts isn't worth it. Start by getting your observability solid — the analysis step is only as good as the metrics behind it.

Low-traffic services are a related trap. If a canary sees a dozen requests in five minutes, a single error swings the error rate wildly, and the analysis either never passes or passes by luck. For those services, longer steps or synthetic traffic help more than tighter thresholds.

The payoff

For teams shipping multiple times per day to anything resembling scale, the math is obvious: progressive delivery turns most bad deploys from incidents into non-events. That alone usually pays for the setup within the first quarter. It is also one of the cheapest ways to shrink lead time, because teams that trust their rollbacks stop batching changes.

We set up progressive delivery as part of our DevOps and platform engineering work, including for a fintech's move from a monolith to Kubernetes. If you want help introducing it, get in touch.

Let's build something awesome.

Tell us about your infrastructure or product challenge. We'll reply within one business day.