11.4 Progressive Delivery Automation: Argo Rollouts, Flagger & Feature Flags
Key Takeaways
- Progressive delivery is the automation of a release strategy — a controller shifts traffic in steps, evaluates metrics, and promotes or rolls back without human intervention.
- Argo Rollouts replaces the Deployment object with a Rollout custom resource that owns the canary or blue/green steps natively.
- Flagger drives an existing Deployment by manipulating a service mesh or ingress controller's traffic weights instead of replacing the workload object.
- Automated analysis queries a metrics provider such as Prometheus against a success threshold, and a failed analysis aborts the rollout and restores full traffic to the stable version.
- Feature flags separate deployment from release, so code can ship dark and be switched on for a user segment without another rollout.
11.4 Progressive Delivery Automation: Argo Rollouts, Flagger & Feature Flags
Quick Answer: Section 11.3 described what canary and blue/green releases are. Progressive delivery is the automation that actually runs them: a controller shifts traffic in defined steps, queries metrics after each step, and promotes or aborts on its own. Argo Rollouts replaces the
Deploymentobject with aRolloutCRD; Flagger leaves the Deployment in place and drives a service mesh or ingress controller. Feature flags go further still, decoupling deployment from release entirely.
A canary that nobody watches is not a canary — it is a slow outage. The automation is the point.
1. Why Native Deployments Are Not Enough
A Kubernetes Deployment gives you exactly one automated strategy, RollingUpdate, and its only health signal is the readiness probe. That probe answers "is the process accepting connections?" — not "is the new version returning correct answers at an acceptable error rate and latency?"
So a build that passes readiness but returns HTTP 500 on 20% of requests will roll out to 100% of your fleet, cheerfully, in about ninety seconds.
| Capability | Deployment | Progressive delivery controller |
|---|---|---|
| Incremental pod replacement | Yes | Yes |
| Precise traffic weights (5%, 25%, 50%) | No | Yes |
| Automated metric analysis between steps | No | Yes |
| Automatic abort on a bad metric | No | Yes |
| Manual promotion gate mid-rollout | No | Yes |
| Blue/green with a pre-promotion test hook | No | Yes |
2. Argo Rollouts
Argo Rollouts introduces a Rollout custom resource that is a drop-in replacement for a Deployment — same Pod template, plus a strategy block that describes the release as a sequence of steps.
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: api
spec:
replicas: 10
strategy:
canary:
canaryService: api-canary
stableService: api-stable
trafficRouting:
istio:
virtualService: { name: api-vs }
steps:
- setWeight: 5
- pause: { duration: 5m } # observe
- analysis: # automated gate
templates:
- templateName: success-rate
- setWeight: 25
- pause: { duration: 10m }
- setWeight: 50
- pause: {} # indefinite: wait for manual promotion
- setWeight: 100
template:
# ... identical to a Deployment pod template ...
Three kinds of step, and knowing the difference is the exam-relevant part:
setWeight— move a percentage of traffic to the canary.pause: { duration }— wait a fixed period so metrics accumulate.pause: {}with no duration — wait indefinitely for a human to runkubectl argo rollouts promote.analysis— run anAnalysisTemplateand continue only if it succeeds.
Argo Rollouts also implements blue/green with previewService, prePromotionAnalysis, and postPromotionAnalysis hooks, plus a configurable scaleDownDelaySeconds that keeps the old version warm for an instant rollback.
3. Flagger
Flagger takes the opposite design decision: it leaves your Deployment untouched and adds a Canary resource that drives it, manipulating the traffic weights of an underlying mesh or ingress (Istio, Linkerd, App Mesh, NGINX, Traefik, Gateway API).
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: api
spec:
targetRef: { apiVersion: apps/v1, kind: Deployment, name: api }
service: { port: 80 }
analysis:
interval: 1m
threshold: 5 # abort after 5 failed checks
maxWeight: 50
stepWeight: 10
metrics:
- name: request-success-rate
thresholdRange: { min: 99 }
interval: 1m
- name: request-duration
thresholdRange: { max: 500 }
interval: 1m
webhooks:
- name: load-test
url: http://flagger-loadtester/
| Argo Rollouts | Flagger | |
|---|---|---|
| Workload object | Replaces Deployment with Rollout | Keeps the Deployment, adds a Canary |
| Traffic control | Mesh, ingress, or replica ratio | Requires a mesh or supported ingress |
| Migration cost | Change kind: on existing manifests | Add one object, change nothing else |
| Home | Argo project (CNCF graduated) | Flux project (CNCF graduated) |
4. Automated Analysis Is the Real Feature
Both controllers reduce to the same loop: shift a little traffic, ask a metrics provider whether things are still healthy, then continue or abort.
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
metrics:
- name: success-rate
interval: 1m
count: 5
successCondition: result[0] >= 0.99
failureLimit: 2
provider:
prometheus:
address: http://prometheus.monitoring:9090
query: |
sum(rate(http_requests_total{job="api",code!~"5.."}[2m]))
/
sum(rate(http_requests_total{job="api"}[2m]))
Providers include Prometheus, Datadog, New Relic, CloudWatch, and Kubernetes Jobs for arbitrary checks. On failure the controller immediately returns 100% of traffic to the stable version and scales the canary to zero — mean time to recovery measured in seconds rather than in however long it takes to page someone.
This is also where sections 12.1 and 11.4 interlock: you cannot automate a promotion decision without the metrics from your observability stack. Progressive delivery is observability with a control loop attached.
5. Feature Flags: Decoupling Deployment from Release
Even a perfect canary still ties a user-visible change to a deployment. Feature flags break that link:
DEPLOY ── ship the code to production, flag OFF ──► nobody sees it
RELEASE ── flip the flag for 1% of users ─────────► gradual exposure
ROLLBACK ─ flip the flag back ────────────────────► instant, no redeploy
Benefits that a rollout controller alone cannot give you:
- Rollback in milliseconds — a configuration change, not a rollout.
- Targeting by attribute — internal staff, a beta cohort, a single region.
- Trunk-based development — merge incomplete work behind a flag instead of maintaining long-lived branches.
- Experimentation — the A/B testing pattern from section 11.3, controlled per user rather than per Pod.
OpenFeature is the CNCF project standardising the flag-evaluation API across vendors, so application code is written once against a vendor-neutral SDK.
The cost is real and should be stated: every flag is a branch in production, and un-retired flags accumulate into combinatorial complexity nobody can reason about. Mature teams treat flag removal as part of the definition of done.
6. Choosing
| Situation | Approach |
|---|---|
| Small internal service, low blast radius | Plain Deployment with a good readiness probe |
| User-facing service, mesh already installed | Flagger — least disruption to existing manifests |
| Complex multi-step release with manual gates and blue/green hooks | Argo Rollouts |
| Change must be reversible in seconds, or targeted at a user segment | Feature flags |
| Regulated environment requiring an explicit human approval | Rollout controller with an indefinite pause: {} step |
What does a progressive delivery controller add that a standard Kubernetes Deployment rolling update cannot provide?
What is the architectural difference between Argo Rollouts and Flagger?
What problem do feature flags solve that a canary rollout does not?