Kubernetes
13 min readMay 5, 2026

Argo Rollouts: Progressive Delivery with Canary and Blue-Green Deployments

Kubernetes rolling updates give you a basic deployment strategy, but no traffic control, no analysis, and no automatic rollback. Argo Rollouts adds progressive delivery: canary releases that shift traffic gradually, blue-green deployments with instant cutover, automated analysis using Prometheus metrics or custom webhooks, and pause/promote/abort workflows.

AJ
Ajeet Yadav
Platform & Cloud Engineer
Argo Rollouts: Progressive Delivery with Canary and Blue-Green Deployments

Kubernetes rolling updates move old pods to new pods gradually, but they don't control traffic. All pods receive production traffic immediately after they become Ready — there's no way to say "send 5% of traffic to the new version, measure error rate, and automatically roll back if it degrades." Argo Rollouts adds this layer.

Argo Rollouts replaces the Deployment with a Rollout object that supports canary and blue-green strategies with traffic management integrations (Istio, AWS ALB, NGINX) and automated analysis gates.


Installation

bash
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/download/v1.7.2/install.yaml
# Check https://github.com/argoproj/argo-rollouts/releases for current version

Or via Helm:

bash
1helm repo add argo https://argoproj.github.io/argo-helm
2helm repo update
3
4helm install argo-rollouts argo/argo-rollouts \
5  --namespace argo-rollouts \
6  --create-namespace \
7  --values rollouts-values.yaml
yaml
1# rollouts-values.yaml
2controller:
3  replicas: 2    # HA for the rollouts controller
4
5dashboard:
6  enabled: true   # Argo Rollouts UI (not the Argo CD UI)
7  service:
8    type: ClusterIP
bash
# Install the kubectl plugin
curl -LO https://github.com/argoproj/argo-rollouts/releases/latest/download/kubectl-argo-rollouts-linux-amd64
chmod +x kubectl-argo-rollouts-linux-amd64
mv kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts

Canary Rollout

A Rollout spec is almost identical to a Deployment spec, with a strategy.canary block replacing strategy.rollingUpdate:

yaml
1apiVersion: argoproj.io/v1alpha1
2kind: Rollout
3metadata:
4  name: payments-api
5  namespace: production
6spec:
7  replicas: 5
8  selector:
9    matchLabels:
10      app: payments-api
11  template:
12    metadata:
13      labels:
14        app: payments-api
15    spec:
16      containers:
17        - name: api
18          image: 123456789.dkr.ecr.us-east-1.amazonaws.com/payments-api:1.4.2
19          ports:
20            - containerPort: 8080
21          resources:
22            requests:
23              cpu: 200m
24              memory: 256Mi
25
26  strategy:
27    canary:
28      # Stable Service — receives traffic from non-canary pods
29      stableService: payments-api-stable
30      # Canary Service — receives the traffic percentage assigned to canary
31      canaryService: payments-api-canary
32
33      trafficRouting:
34        istio:
35          virtualService:
36            name: payments-api
37            routes:
38              - primary
39          destinationRule:
40            name: payments-api
41            stableSubsetName: stable
42            canarySubsetName: canary
43
44      steps:
45        - setWeight: 5        # 5% traffic to canary
46        - pause: {}           # Pause indefinitely — wait for manual promote or analysis
47        - setWeight: 20
48        - pause: {duration: 10m}    # Auto-advance after 10 minutes
49        - setWeight: 40
50        - pause: {duration: 10m}
51        - setWeight: 60
52        - analysis:
53            templates:
54              - templateName: success-rate
55        - setWeight: 80
56        - pause: {duration: 5m}
57        # Final step: 100% promoted automatically (or promote manually)

Services for Traffic Splitting

Canary traffic splitting requires two Services pointing to the same selector but managed by Argo Rollouts:

yaml
1# Stable service — points to stable (non-canary) pods
2apiVersion: v1
3kind: Service
4metadata:
5  name: payments-api-stable
6  namespace: production
7spec:
8  selector:
9    app: payments-api
10  ports:
11    - port: 80
12      targetPort: 8080
13---
14# Canary service — Argo Rollouts patches this to point to canary pods
15apiVersion: v1
16kind: Service
17metadata:
18  name: payments-api-canary
19  namespace: production
20spec:
21  selector:
22    app: payments-api
23  ports:
24    - port: 80
25      targetPort: 8080

Argo Rollouts modifies the selector on the canary Service to add a pod-hash label, isolating traffic to canary pods.


Automated Analysis

AnalysisTemplate defines metrics to query during a rollout. Argo Rollouts evaluates these and automatically promotes or aborts:

yaml
1apiVersion: argoproj.io/v1alpha1
2kind: AnalysisTemplate
3metadata:
4  name: success-rate
5  namespace: production
6spec:
7  args:
8    - name: service-name
9  metrics:
10    - name: success-rate
11      interval: 1m
12      successCondition: result[0] >= 0.99    # 99% success rate required
13      failureLimit: 3    # Allow 3 failures before marking analysis as Failed
14      provider:
15        prometheus:
16          address: http://kube-prometheus-stack-prometheus.monitoring:9090
17          query: |
18            sum(rate(http_requests_total{
19              app="{{args.service-name}}",
20              status!~"5.."
21            }[5m]))
22            /
23            sum(rate(http_requests_total{
24              app="{{args.service-name}}"
25            }[5m]))

Referencing the template in the Rollout:

yaml
1steps:
2  - setWeight: 20
3  - analysis:
4      templates:
5        - templateName: success-rate
6      args:
7        - name: service-name
8          value: payments-api-canary
9  - setWeight: 50

If the analysis fails (success rate drops below 99%), Argo Rollouts automatically aborts the rollout and scales the canary back to 0.

Background Analysis

Run analysis throughout the entire rollout rather than at specific steps:

yaml
1strategy:
2  canary:
3    analysis:
4      templates:
5        - templateName: success-rate
6      args:
7        - name: service-name
8          value: payments-api-canary
9      startingStep: 1    # Start analysis after step 1 (not during the first setWeight)

Blue-Green Rollout

Blue-green maintains two full deployments — active (blue) and preview (green). Traffic switches atomically:

yaml
1apiVersion: argoproj.io/v1alpha1
2kind: Rollout
3metadata:
4  name: payments-api
5  namespace: production
6spec:
7  replicas: 3
8  selector:
9    matchLabels:
10      app: payments-api
11  template:
12    metadata:
13      labels:
14        app: payments-api
15    spec:
16      containers:
17        - name: api
18          image: 123456789.dkr.ecr.us-east-1.amazonaws.com/payments-api:1.4.2
19
20  strategy:
21    blueGreen:
22      activeService: payments-api-active      # Receives production traffic
23      previewService: payments-api-preview    # Receives preview traffic (testing)
24      autoPromotionEnabled: false             # Require manual promotion
25      prePromotionAnalysis:                   # Run analysis before promoting
26        templates:
27          - templateName: success-rate
28        args:
29          - name: service-name
30            value: payments-api-preview
31      postPromotionAnalysis:                  # Run analysis after promoting (abort if fails)
32        templates:
33          - templateName: success-rate
34        args:
35          - name: service-name
36            value: payments-api-active
37      scaleDownDelaySeconds: 300    # Keep old (blue) pods running 5 min after promotion
38      abortScaleDownDelaySeconds: 30

Rollout Operations

bash
1# Watch a rollout in progress
2kubectl argo rollouts get rollout payments-api -n production --watch
3
4# Promote (advance past a pause step or fully promote)
5kubectl argo rollouts promote payments-api -n production
6
7# Abort and roll back to stable
8kubectl argo rollouts abort payments-api -n production
9
10# Retry after an abort
11kubectl argo rollouts retry rollout payments-api -n production
12
13# Update the image (triggers a new rollout)
14kubectl argo rollouts set image payments-api api=...ecr.../payments-api:1.4.3 -n production

Rollout Status

bash
1kubectl argo rollouts get rollout payments-api -n production
2# NAME           KIND      STATUS        STABLE    DESIRED   READY   UP-TO-DATE
3# payments-api   Rollout   Progressing   1         5         4       1
4#
5# Revision 3:
6# ⟳ payments-api-77c8d4b89  canary    1/1  (5%)
7# Revision 2:
8# ✔ payments-api-6f4c7b8d   stable    4/4

HPA Integration

HPA targets Rollout objects the same way it targets Deployment objects:

yaml
1apiVersion: autoscaling/v2
2kind: HorizontalPodAutoscaler
3metadata:
4  name: payments-api
5  namespace: production
6spec:
7  scaleTargetRef:
8    apiVersion: argoproj.io/v1alpha1
9    kind: Rollout
10    name: payments-api
11  minReplicas: 3
12  maxReplicas: 20
13  metrics:
14    - type: Resource
15      resource:
16        name: cpu
17        target:
18          type: Utilization
19          averageUtilization: 70

HPA adjusts the Rollout's desired replica count, and Argo Rollouts distributes replicas between stable and canary ReplicaSets according to the current weight.


Frequently Asked Questions

How do I migrate from a Deployment to a Rollout?

Argo Rollouts docs provide a migration guide — the key step is that the Rollout spec is a superset of Deployment spec with strategy.canary or strategy.blueGreen replacing strategy.rollingUpdate. The selector and template are identical. You can delete the Deployment and create the Rollout without downtime if the pod selector remains the same.

Does Argo Rollouts work without a traffic management integration?

Yes. Without trafficRouting, Argo Rollouts uses a subset-based canary: setWeight: 20 with 5 total replicas means 1 pod runs the new version and 4 run the old version. This is an approximation of 20% — you get 20% of pods on the new version, not 20% of traffic. For exact traffic percentages, you need Istio, AWS ALB, or NGINX integration.

Can I use Argo Rollouts with Argo CD?

Yes — and this is the recommended approach. Argo CD manages the Rollout manifest in Git. When you update the image tag in Git, Argo CD syncs it, which triggers the rollout process. Argo CD has native awareness of Rollout health — it shows the rollout status (progressing, degraded, healthy) in its UI.


Header-Based Canary Routing

Route specific users to the canary version by request header — useful for internal testing before percentage-based rollout:

yaml
1steps:
2  - setHeaderRoute:
3      name: canary-header
4      match:
5        - headerName: X-Canary
6          headerValue:
7            exact: "true"
8  - pause: {}           # Hold until internal testing complete
9  - setWeight: 10
10  - pause: {duration: 10m}
11  - setWeight: 100

Internal QA team sends X-Canary: true headers. Production users see the stable version until you advance past the pause. This requires Nginx or Istio with header-based routing support.


Web Webhook Analysis

For services with a dedicated health endpoint or custom validation API:

yaml
1apiVersion: argoproj.io/v1alpha1
2kind: AnalysisTemplate
3metadata:
4  name: canary-health-check
5spec:
6  metrics:
7    - name: health
8      interval: 30s
9      count: 10
10      successCondition: result == "Healthy"
11      provider:
12        web:
13          url: "https://my-service.example.com/canary-health"
14          jsonPath: "{$.status}"

Migrating from Deployment to Rollout

Migrating an existing Deployment to a Rollout without downtime:

  1. Copy the Deployment spec into a Rollout resource — the template section is identical
  2. Add the strategy block — start with a simple canary (one step to 100%, no analysis) as a safe migration
  3. Scale the Deployment to 0 — Rollout takes over pod management
  4. Delete the Deployment once the Rollout is confirmed working
bash
# Convert a Deployment to Rollout (Argo plugin command)
kubectl argo rollouts create -f rollout.yaml

# Scale down the old Deployment
kubectl scale deployment payments-api --replicas=0 -n production

Do not delete the Deployment until the Rollout is healthy — if something goes wrong, you can scale the Deployment back up. The Rollout selector must match the Deployment selector exactly or the pods will not be adopted.


Notifications

Argo Rollouts uses the same notifications engine as Argo CD. Configure alerts for rollout events in the argo-rollouts-notification-configmap ConfigMap:

yaml
1apiVersion: v1
2kind: ConfigMap
3metadata:
4  name: argo-rollouts-notification-configmap
5  namespace: argo-rollouts
6data:
7  service.slack: |
8    token: $slack-token
9  template.rollout-completed: |
10    message: Rollout {{.rollout.metadata.name}} completed successfully
11  trigger.on-rollout-completed: |
12    - send: [rollout-completed]
13      when: "rollout.status.phase == 'Healthy'"

GitOps Integration with Argo CD

Argo Rollouts works naturally with Argo CD. Deploy the Rollout resource through Argo CD like any other Kubernetes object. The Rollout controller handles the progressive delivery; Argo CD handles reconciliation:

yaml
1# Argo CD Application for the service
2apiVersion: argoproj.io/v1alpha1
3kind: Application
4metadata:
5  name: payments-api
6  namespace: argocd
7spec:
8  source:
9    repoURL: https://github.com/my-org/payments-api
10    path: deploy/
11    targetRevision: HEAD
12  destination:
13    server: https://kubernetes.default.svc
14    namespace: production
15  syncPolicy:
16    automated:
17      prune: true
18      selfHeal: true

When you merge a new image tag to Git, Argo CD updates the Rollout. The Rollout controller starts the canary steps. Analysis runs automatically. If the analysis passes, the rollout completes. If it fails, the Rollout rolls back and Argo CD shows the sync status as OutOfSync — the desired state (new image) differs from the current state (rolled back to old image), which correctly prompts investigation before retrying.

Note: Argo CD's sync will show OutOfSync after an automatic rollback because the Rollout spec (image tag) doesn't match what's running. This is intentional — the rollback is an operational decision that should be reflected in a git change, not silently accepted.


For Istio VirtualService traffic splitting that Argo Rollouts manipulates during canary releases, see Istio Service Mesh for Kubernetes. For Argo CD that manages Rollout manifests in GitOps, see Argo CD ApplicationSet: Multi-Cluster Deployments. For the Argo CD setup that manages Rollout manifests as part of your GitOps workflow, see GitOps with Argo CD: Production Setup Guide.

Rolling out a canary release strategy for a production Kubernetes platform? Talk to us at Coding Protocols — we help platform teams implement progressive delivery pipelines that reduce deployment risk without slowing down release velocity.

Related Topics

Argo Rollouts
Canary
Blue-Green
Progressive Delivery
Kubernetes
Platform Engineering
CI/CD

Read Next