Tools · Argo Rollouts

Argo Rollouts

Argo Rollouts is a Kubernetes controller that replaces the built-in Deployment rollout with a progressive one: it introduces a Rollout resource whose strategy is either a canary ramp (10% → 50% → 100%, with pauses and metric gates) or a blue/green flip between two Services, and at every step it can query Prometheus, Datadog or an arbitrary Job and abort the release by itself when the numbers go bad. It solves the one platform problem a plain Deployment cannot: a RollingUpdate keeps replacing pods whether or not the new version is any good, so the only thing between a bad image and every one of your users is a human watching a dashboard at the right moment.

☺ Explain it like I’m 10

Imagine you baked a new recipe of cookies for the whole school. A plain Kubernetes Deployment is like swapping every cookie in every lunchbox as fast as you can — if the recipe is bad, everyone finds out at once. Argo Rollouts is the sensible version: give the new cookie to two kids first, stand there and actually watch their faces for five minutes, and only if they’re smiling do you hand it to twenty more, then to everyone. And if a face goes green, you snatch the new cookies back and hand out the old ones again — automatically, without anyone having to shout.

🦫🐦Your hosts for this topic: Benny the Beaver & Pip the Hummingbird — Benny lays the delivery rails and writes the manifests, and Pip is the tiny, fast traffic-cop who hovers over each step, sips the metrics, and decides whether the release earns the next percent.

What Argo Rollouts is and the problem it solves

☺ Like you’re 10: Kubernetes already knows how to swap pods. It just doesn’t know how to stop if the new ones are bad. Argo Rollouts adds the stopping.

Argo Rollouts is one of the four projects under the CNCF-graduated Argo umbrella (alongside Argo CD, Argo Workflows and Argo Events). It is a single controller plus a set of CRDs, and it does exactly one job: release a new pod template gradually, under measurement, with an automatic reverse gear.

The gap a Deployment leaves

A Deployment with strategy.type: RollingUpdate gives you exactly two knobs — maxSurge and maxUnavailable — and they control only how many pods swap at a time. The controller’s single health signal is the readiness probe, so a version that starts perfectly and then returns HTTP 500 to a third of requests, or takes 4 seconds instead of 40 milliseconds, sails straight through to 100%. There is no way to say “hold at 10% for five minutes,” no way to say “continue only if the error rate stays under 1%,” and no way to shift traffic independently of pod counts. kubectl rollout undo exists, but it is something a human does after the damage.

◆ Key idea

Argo Rollouts exists to separate deploy (the new version is running in the cluster) from release (real users are being sent to it), and then to put a measurement in between. The unit of progress stops being “pods replaced” and becomes “percentage of traffic that survived an analysis.”

The Rollout answer

You swap kind: Deployment for kind: Rollout. Everything familiar stays — replicas, selector, and the entire template verbatim. What changes is that spec.strategy now takes either a canary block (an authored recipe of setWeight, pause, setCanaryScale and analysis steps) or a blueGreen block naming an activeService and a previewService. Underneath, the controller manages a stable and a canary (or preview) ReplicaSet exactly as a Deployment would — but it walks your steps and stops where you told it to.

☺ Like you’re 10: A Rollout is a Deployment plus a written plan for how slowly to let people in, and a rule for turning back.

You don’t have to give up your Deployment

The one real migration cost — “I have to rewrite my Deployment as a Rollout” — has an escape hatch. spec.workloadRef lets a Rollout point at an existing Deployment and borrow its pod template instead of carrying its own:

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: checkout
spec:
  replicas: 10
  workloadRef:                 # borrow the pod template from an existing Deployment
    apiVersion: apps/v1
    kind: Deployment
    name: checkout
    scaleDown: progressively   # never (default) | onsuccess | progressively
  strategy:
    canary:
      steps:
        - setWeight: 20
        - pause: { duration: 5m }

The Deployment stays in Git and stays whatever your Helm chart or Kustomize base renders; the Rollout is a thin wrapper the platform adds. Mind the scaleDown value: it defaults to never, so unless you set onsuccess or progressively you end up running both the Deployment’s pods and the Rollout’s pods behind the same Service — double the replicas, half the surprise budget.

Where it fits in a platform

☺ Like you’re 10: It sits at the very last step, right where new code meets real people.

Argo Rollouts belongs to the delivery plane — the machinery between “an artifact exists” and “users are on it.” On the CNPE blueprint that is squarely Domain 2: GitOps & Continuous Delivery (25%), serving the competency about safe, progressive application deployment. It consumes three other platform capabilities and produces exactly one thing: confidence.

Its neighbours, and who does what

NeighbourRelationshipWho owns what
Argo CD / FluxPuts the Rollout manifest into the clusterThe GitOps reconciler owns desired state; Rollouts owns how that state is reached. A tag bump in Git is a sync; the ramp that follows is the Rollout’s.
Istio / Linkerd / NGINX / ALB / Gateway APIActually moves the trafficRollouts writes the weights; the mesh or ingress enforces them. Without one, “weight” degrades to a replica-count approximation.
Prometheus and friendsSupplies the verdictObservability owns the SLIs; the AnalysisTemplate only turns a query result into pass/fail.
FlaggerDirect alternativeSame job, opposite shape — see the comparison below. You install one, not both, per workload.
Argo Workflows / TektonUpstream of itCI builds and scans the image and commits the tag. Rollouts never touches a registry or a pipeline.

Why a platform team, not an app team, usually owns it

Progressive delivery is the classic self-service capability: fiddly to set up once (mesh wiring, Prometheus queries, a shared ClusterAnalysisTemplate library) and trivial to consume afterwards. The product move is a golden path where the Rollout, the two Services, the router resources and a vetted analysis template all come from one chart, and the app team’s only decision is “how brave am I?” expressed as a step recipe — which is why Rollouts appears in most reference architectures as a platform component, not an app dependency.

🦆 Dot’s-eye view

“My chart has one block: rollout.strategy: cautious. I have never written an AnalysisTemplate in my life. What I get is that merging on a Friday afternoon is boring — the platform gives my change 10% of traffic, watches my service’s error rate for six minutes, and either walks it up to 100% or puts it back and posts in my channel. Either way I find out from Slack, not from the pager.”

How it works — architecture and CRDs

☺ Like you’re 10: There is one robot in a corner of the cluster reading your plan, moving pods and weights, and asking a scoreboard whether things are OK.

Argo Rollouts installs as a single controller Deployment (usually in the argo-rollouts namespace) plus its CRDs, and an optional dashboard (served by the kubectl plugin, and able to promote, abort and restart — not merely a viewer). No database, no external dependency: the controller watches the CRs, creates and scales ReplicaSets, patches Services and traffic-router resources, and records progress in the Rollout’s status. Everything it knows lives in the Kubernetes API.

The resources it introduces

KindScopeWhat it is for
RolloutNamespacedThe workload itself — a Deployment replacement carrying strategy.canary or strategy.blueGreen.
AnalysisTemplateNamespacedA reusable definition of “what does healthy mean”: metrics, providers, success/failure conditions.
ClusterAnalysisTemplateClusterThe same thing, published once by the platform team for every tenant to reference.
AnalysisRunNamespacedThe instance — created by the controller when a step fires. Read its status to see why a rollout aborted.
ExperimentNamespacedRuns one or more short-lived ReplicaSets side by side with analysis — for A/B tests and baseline-vs-canary comparisons.

The canary strategy, step by step

A canary Rollout that uses a traffic router names two Services — canaryService and stableService — which the controller keeps pointed at the right ReplicaSets by injecting a rollouts-pod-template-hash label into each Service’s selector; it then walks steps in order. (Without a trafficRouting block those two Services are optional: one Service in front of both ReplicaSets is enough, because the split is being approximated by pod counts anyway.) The four step types you will actually write:

Alongside the steps, strategy.canary.analysis (not inside steps) declares background analysis: it starts as soon as the canary receives traffic and runs for the whole rollout, so a regression that only appears at 50% still aborts you. Inline analysis gates a step; background analysis guards the release. Run both.

Rollout CR strategy.canary.steps AnalysisTemplate successCondition 🐦 controller argo-rollouts ns stable ReplicaSet v1.4.2 · 90% canary ReplicaSet v1.4.3 · 10% traffic router Istio · NGINX · ALB · plugins set weight 🦆 user traffic 90 / 10 split AnalysisRun every 60s · count 5 Prometheus success-rate query fail analysis fails → abort → weight back to 0 → stable ReplicaSet serves 100%

The blueGreen strategy

Blue/green needs no traffic router at all — it works by re-pointing Service selectors. You name an activeService (what users hit) and optionally a previewService (what your smoke tests hit). The new ReplicaSet comes up behind the preview Service with zero user traffic; then autoPromotionEnabled: true flips the active selector immediately, or false waits for a manual promote. prePromotionAnalysis runs before the flip, postPromotionAnalysis after, and scaleDownDelaySeconds (default 30) keeps the old ReplicaSet alive so rollback is a flip, not a cold start.

The resources you will actually write

☺ Like you’re 10: Three files: the plan, the second plan, and the rule for what “healthy” means.

A canary Rollout with real traffic splitting

The shape you will write most often. Note the two Services, the trafficRouting block that makes the weights real, and the background analysis that runs alongside the steps rather than inside them.

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: checkout
  namespace: checkout
spec:
  replicas: 10
  revisionHistoryLimit: 3
  selector:
    matchLabels: { app: checkout }
  template:                              # identical to a Deployment's pod template
    metadata:
      labels: { app: checkout }
    spec:
      containers:
        - name: checkout
          image: registry.acme.io/checkout:1.4.3
          ports: [ { containerPort: 8080 } ]
          readinessProbe:
            httpGet: { path: /healthz, port: 8080 }
  strategy:
    canary:
      canaryService: checkout-canary     # selector managed by the controller
      stableService: checkout-stable
      trafficRouting:
        istio:
          virtualService:
            name: checkout-vsvc           # you create this; the controller only edits weights
            routes: [ primary ]           # a named http route with TWO destinations:
                                          #   checkout-stable and checkout-canary
      analysis:                           # BACKGROUND — runs for the whole rollout
        templates:
          - templateName: success-rate
            clusterScope: true            # it is a ClusterAnalysisTemplate (see below)
        startingStep: 1                   # 0-indexed: start after step 0 (setWeight: 10)
        args:
          - name: service-name
            value: checkout-canary.checkout.svc.cluster.local
      steps:
        - setWeight: 10
        - pause: { duration: 5m }         # timed soak
        - analysis:                       # INLINE — this step blocks until it passes
            templates:
              - templateName: latency-p99  # namespaced AnalysisTemplate, no clusterScope
            args:
              - name: service-name
                value: checkout-canary.checkout.svc.cluster.local
        - setWeight: 40
        - pause: { duration: 5m }
        - setWeight: 80
        - pause: {}                       # indefinite — waits for a human `promote`
      # after the last step the canary is promoted to stable automatically

A blueGreen Rollout with a manual gate

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: ledger
  namespace: ledger
spec:
  replicas: 6
  selector:
    matchLabels: { app: ledger }
  template:
    metadata:
      labels: { app: ledger }
    spec:
      containers:
        - name: ledger
          image: registry.acme.io/ledger:2.9.0
  strategy:
    blueGreen:
      activeService: ledger              # users hit this Service
      previewService: ledger-preview     # smoke tests hit this one, zero user traffic
      autoPromotionEnabled: false        # WAIT for an explicit promote (default is true)
      scaleDownDelaySeconds: 600         # keep the old RS for 10 min for instant rollback
      prePromotionAnalysis:              # must pass BEFORE the active selector flips
        templates:
          - templateName: smoke-suite
        args:
          - name: target
            value: ledger-preview.ledger.svc.cluster.local
      postPromotionAnalysis:             # watch the real thing AFTER the flip
        templates:
          - templateName: success-rate
            clusterScope: true           # cluster-scoped template, so say so
        args:                            # its declared arg has no default — supply one
          - name: service-name
            value: ledger.ledger.svc.cluster.local
⚠ autoPromotionEnabled defaults to true

Leave it out and your “blue/green” flips to 100% the instant the preview pods are Ready — which is a slightly slower Deployment, not a gate. If you want a human or a test suite to decide, you must write autoPromotionEnabled: false (or set autoPromotionSeconds for a timed hold). This is the single most common blue/green misconfiguration.

AnalysisTemplate — the thing that makes it worth doing

Everything above is theatre without this file. An AnalysisTemplate declares one or more metrics; each has a provider, an interval, a count of measurements, and a successCondition or failureCondition evaluated against result. failureLimit is the number of failed measurements the run will tolerate — it defaults to 0, and the run fails once failures exceed it, which aborts the rollout. Two details bite people: a template’s declared args have no values until a caller supplies them (or the arg carries a value/valueFrom default), and referencing a cluster-scoped template requires clusterScope: true on the reference — leave it out and the controller looks for a namespaced AnalysisTemplate of that name and fails the run.

apiVersion: argoproj.io/v1alpha1
kind: ClusterAnalysisTemplate            # published once by the platform team
metadata:
  name: success-rate
spec:
  args:
    - name: service-name                 # supplied by each Rollout that uses it
  metrics:
    - name: success-rate
      interval: 60s                      # measure once a minute
      count: 5                           # take 5 measurements, then finish
      initialDelay: 60s                  # let the canary warm up first
      successCondition: result[0] >= 0.99
      failureLimit: 2                    # TOLERATE 2 failures; the 3rd fails the run
      provider:
        prometheus:
          address: http://prometheus.monitoring.svc.cluster.local:9090
          query: |
            sum(rate(http_requests_total{
                  service="{{args.service-name}}", code!~"5.."}[2m]))
            /
            sum(rate(http_requests_total{
                  service="{{args.service-name}}"}[2m]))
---
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: smoke-suite
  namespace: ledger
spec:
  args:
    - name: target
  metrics:
    - name: smoke
      provider:
        job:                             # run an arbitrary Kubernetes Job; exit 0 = pass
          spec:
            backoffLimit: 0
            template:
              spec:
                restartPolicy: Never
                containers:
                  - name: smoke
                    image: registry.acme.io/smoke-tests:3.1
                    args: [ "--target", "{{args.target}}" ]

☺ Like you’re 10: The template is the school nurse’s checklist. The AnalysisRun is the actual check-up. Two bad readings and the release goes home.

Besides prometheus and job, the controller ships providers for the usual commercial and open-source metric backends — datadog, newRelic, cloudWatch, graphite, influxdb and kayenta among them — plus a plugin mechanism for anything not built in. The one to remember is the generic web provider: it calls a URL and evaluates the JSON response with a JSON path. That is the universal escape hatch — if a system can answer “is this healthy?” over HTTP, it can gate your release, which means change-freeze calendars, ticket systems and bespoke scorecards are all fair game as release gates.

Day-to-day commands

☺ Like you’re 10: There is a special extra command you have to install. Plain kubectl does not come with it.

Installing the controller and the plugin

# the controller + CRDs
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts \
  -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml

# the kubectl plugin — a SEPARATE download, not part of kubectl or the controller
curl -fSL -o kubectl-argo-rollouts \
  https://github.com/argoproj/argo-rollouts/releases/latest/download/kubectl-argo-rollouts-linux-amd64
chmod +x kubectl-argo-rollouts
sudo mv kubectl-argo-rollouts /usr/local/bin/

kubectl argo rollouts version

Watching and driving a release

# the command you will live in — a live tree of revisions, weights, pods and analysis
kubectl argo rollouts get rollout checkout -n checkout --watch

# trigger a new release without editing YAML (great for labs; use Git in prod)
kubectl argo rollouts set image checkout checkout=registry.acme.io/checkout:1.4.4 -n checkout

kubectl argo rollouts list rollouts -n checkout      # everything and its status
kubectl argo rollouts status checkout -n checkout    # blocks until Healthy/Degraded; CI-friendly

kubectl argo rollouts promote checkout -n checkout          # continue past the current pause
kubectl argo rollouts promote checkout -n checkout --full   # SKIP all remaining steps + analysis
kubectl argo rollouts pause  checkout -n checkout           # freeze where it is

kubectl argo rollouts abort   checkout -n checkout          # traffic back to stable, now
kubectl argo rollouts retry rollout checkout -n checkout    # un-abort and re-run the steps
kubectl argo rollouts undo    checkout -n checkout --to-revision=3
kubectl argo rollouts restart checkout -n checkout          # rolling pod restart, no version change

kubectl argo rollouts dashboard                      # local UI on :3100 (can also promote/abort)

When the plugin is not installed

Every one of those is a wrapper over the API, so plain kubectl always works — worth practising, because a lab box may not have the plugin:

kubectl get rollout checkout -n checkout -o wide
kubectl describe rollout checkout -n checkout            # events explain WHY it paused
kubectl get analysisrun -n checkout                      # who vetoed the release
kubectl describe analysisrun checkout-6c9f8d-2-1 -n checkout   # the measurement values

# abort / un-abort are a single boolean in the Rollout's STATUS. The Rollout CRD
# has a status subresource, so a plain patch must target it explicitly (kubectl 1.24+):
kubectl patch rollout checkout -n checkout --type merge \
  --subresource status -p '{"status":{"abort":true}}'    # == `abort`
kubectl patch rollout checkout -n checkout --type merge \
  --subresource status -p '{"status":{"abort":false}}'   # == `retry rollout`

Promoting past a step-level pause has no equally tidy one-liner — the controller tracks pause state in status.pauseConditions, and the plugin clears it for you — so promotion is the one operation where installing the plugin genuinely pays for itself. If you truly have no plugin, the reliable moves are to change the pod template (a new revision supersedes the paused one) or to abort and roll forward properly. See Command Reference for these alongside the rest of the platform CLI set.

Gotchas and failure modes

☺ Like you’re 10: Most people get bitten by four things. Read these once and you will skip all four.

A canary without analysis is just a slow bad deploy

The big one, and a judgement failure rather than a config error. setWeight: 10; pause: {duration: 5m}; setWeight: 100 looks careful and achieves almost nothing: it ships the same bug to everyone five minutes later, while giving the team a comforting feeling of rigour. A canary earns its complexity only when something looks at the numbers and can say no. If you cannot yet produce a trustworthy SLI, an indefinite pause: {} with a human and a dashboard is honest; a timed pause with nobody watching is theatre. And a canary run at 03:00 against no traffic proves nothing — the analysis window must contain enough requests to be meaningful, which is what setCanaryScale and count/interval are for.

The plugin is separate, and the first rollout is special

kubectl argo rollouts is not part of kubectl and is not installed by the controller manifest — most “the command doesn’t exist” confusion traces to that one fact. The other surprise: the first time a Rollout is created it skips the steps entirely and goes to 100%, because there is no stable version to canary against. Changing replicas skips them too — only pod template changes start a new revision and re-run the strategy. Engineers testing a step recipe often conclude it is broken when they are watching the initial deploy.

Abort leaves the Rollout Degraded on purpose

When analysis fails or you run abort, traffic snaps back to the stable ReplicaSet and the canary scales down — but the Rollout still carries the new spec and sits Degraded. It will not retry by itself, and re-applying the identical manifest will not restart it. You need retry rollout, a fixed image, or undo. This bites under GitOps: Git says 1.4.3 and Argo CD reports Synced while production happily serves 1.4.2. Synced does not mean released — alert on Rollout health, not just sync status, and see Triage: Delivery.

Traffic-router and mesh wiring

Weights are only as real as the router underneath. With no trafficRouting block, setWeight: 10 is approximated by ReplicaSet counts — with 3 replicas your “10%” is really 33%, and connection-sticky besides. With Istio, the VirtualService and its named route must already exist and be shaped the way the Rollout expects; with NGINX you point at a stableIngress and the controller creates and manages a second canary Ingress. Gateway API support arrives through the separate Argo Rollouts Gateway API plugin rather than being built in. And if you autoscale, point the HPA at the Rollout (it exposes the scale subresource), never at the wrapped Deployment.

⚠ Two controllers, one object

Any resource that Argo Rollouts generates and owns — the managed canary Ingress, the Service selectors, an Istio VirtualService's weights — must be excluded from your GitOps reconciler's diffing (Argo CD ignoreDifferences, or Flux equivalents). Otherwise self-heal reverts the weight the Rollout just set, the Rollout sets it again, and you get a flapping loop that looks like a networking bug and is really a governance bug. Related patterns live in Anti-patterns.

Alternatives and when to choose it

☺ Like you’re 10: Four ways to be careful. Pick by how much control you want to write down yourself.

The four options, side by side

OptionShapeAnalysisChoose it when…
Argo RolloutsRollout replaces the Deployment (or wraps it via workloadRef)AnalysisTemplate — many providers, inline and backgroundYou want an explicit, authored step recipe with manual gates and mixed auto/human promotion; you already run Argo CD; you want blue/green without a mesh.
FlaggerCanary CR wraps an untouched DeploymentMetricTemplate + built-in request-success-rate, plus webhooksYou want convention over configuration, don’t want to change the workload kind, and live in the Flux world. Auto-starts on any image change.
Plain Deployment + flagsNormal RollingUpdate, release controlled in codeWhatever your flag platform gives youYour risk is per-feature rather than per-binary, or you cannot get request-level traffic control. Composes with Rollouts rather than competing.
Mesh-native splitting by handYou edit VirtualService/HTTPRoute weights yourselfNone — you are the analysisOne-off migrations and experiments. Do not build a platform on it; you are hand-rolling a controller.

Rollouts or Flagger — the honest split

Both do the same job, and the choice is rarely about capability. The visible difference is the workload kind: Argo Rollouts asks you to change kind: Deployment to kind: Rollout (or wrap it with workloadRef), while Flagger leaves the Deployment untouched and adds a separate Canary object beside it. That single fact drives most of the rest — anything in your ecosystem that assumes a Deployment (a chart, a dashboard, a policy, a colleague’s muscle memory) keeps working under Flagger and needs a second look under Rollouts.

The second difference is the shape of the release itself. Rollouts gives you an ordered list of steps you author; Flagger gives you a loop parameterised by stepWeight, maxWeight and interval. If every team should ship the same way, a loop is a feature. If a payments service and an internal admin tool genuinely deserve different ceremony, an authored list is.

◆ Key idea

The honest differentiator is who writes the recipe. Argo Rollouts hands you a programmable sequence — pauses, uneven weights, an experiment in the middle, a human gate before the last 20% — and expects you to author it. Flagger hands you a convention (stepWeight up to maxWeight, checked every interval) and expects you to accept it. Neither is better; a platform team that wants one golden path often prefers Flagger's opinionation, and one serving teams with genuinely different risk profiles usually prefers Rollouts' expressiveness.

What adopting it actually costs

Be honest with yourself about the bill before you put it on a golden path. You take on a new controller to upgrade; a workload kind that some tooling will not recognise; a traffic router that must be wired correctly per ingress or mesh, or else your weights are polite fictions; a metrics stack trustworthy enough that a query result is allowed to veto a release; and a GitOps configuration that stops the reconciler and the Rollout controller from fighting over the same fields. None of that is exotic, but all of it is platform work, which is exactly why it belongs to a platform team once rather than to every app team forever — the product framing again. The rule of thumb: if you cannot name the SLI that would abort a release, you are not ready to adopt progressive delivery; you are ready to build observability.

🦫 Benny & Pip’s workshop · 20 min

On a kind cluster: install the controller and the plugin, then apply the canary Rollout above with the trafficRouting and analysis blocks removed and replicas: 5. Watch the first apply go straight to 100% — that’s the initial-rollout rule. Now kubectl argo rollouts set image a new tag and run get rollout --watch in a second terminal: see the canary ReplicaSet appear at 1 pod for setWeight: 10 (there’s your rounding problem, live). Hit promote to step past the pause. Finally, add the success-rate template pointed at a Prometheus query that cannot pass (try vector(0)), deploy again, and watch the AnalysisRun go Failed and the rollout abort. Then run kubectl get rollout and note it stays Degraded until you retry — the gotcha you’ll otherwise learn in production.

🎬 At the Platform Guild
🦊

Foxy: We’ve got canaries now! setWeight: 10, wait two minutes, setWeight: 100. Progressive delivery, ticked off the roadmap.

🐦

Pip: Who’s watching during those two minutes?

🦊

Foxy: …the pause is watching?

🐦

Pip: A pause is a nap, not a nurse. Without an AnalysisTemplate you’ve built a slow bad deploy — same bug, same everyone, two minutes later, plus a false sense of safety.

🦫

Benny: One ClusterAnalysisTemplate fixes it for every team at once. Success rate over 99% for five measurements, failureLimit: 2. Teams just name it.

👺

Gizmo: Or — hear me out — promote --full on everything. Skips the steps and the analysis. Ship it! 🤑

🐢

Timmy: That flag exists for the 3am incident when you already know the fix, Gizmo. In a pipeline it is a very expensive way to write kind: Deployment.

🦆

Dot: Wait — so if analysis aborts, Argo CD still says Synced while prod runs the old version?

🦫

Benny: Exactly, and that’s the alert everyone forgets to write. Synced is about Git. Healthy is about users.

Exam relevance and going further

☺ Like you’re 10: On exam day you cannot open the Argo Rollouts website. So learn the shape of these files by hand, not by copy-paste.

Argo is named on the official CNPE tool list, and progressive delivery sits inside Domain 2 — GitOps & Continuous Delivery (25%), the largest domain. The exam is tool-agnostic in style but will happily ask you to make a release safe, and a Rollout is the most direct way to demonstrate that you can.

The documentation caveat — read this twice

⚠ argo-rollouts.readthedocs.io is NOT available during the exam

The CNPE permits only kubernetes.io/docs (translations included), kubernetes.io/blog, task-specific documentation linked from the exam’s own Quick Reference box, and locally installed documentation (man pages, /usr/share, distribution packages). Argo Rollouts’ project docs are not on that list. Nothing on this page can be looked up mid-task unless a Quick Reference link happens to provide it. And do not count on kubectl explain to rescue you here the way it does for built-in objects: the Argo CRDs ship a deliberately loose schema for spec, so explain tends to return little or nothing below the top level. The substitutes that do work in-cluster are kubectl argo rollouts --help (and --help on each subcommand), and reading a Rollout that already exists with kubectl get rollout NAME -o yaml to copy its shape. Practise both — and practise writing the strategy block from memory, because that is the part nothing in the cluster will hand you. The manifests worth committing to memory are drilled on Know It Cold; the full allowlist and its traps are on Docs Map.

⚖ CNPA vs CNPE — The allowlist above is a CNPE-specific mechanic — it exists only because CNPE is hands-on and something is technically reachable mid-task. CNPA has no such list at all: it is a fully closed-book multiple-choice exam with zero external lookups of any kind, which makes it stricter here, not looser. Still, the concept-level knowledge — what a progressive-delivery controller does and why a canary needs a gate — is exactly the kind of thing CNPA's closed-book recall draws on.

What to be able to do cold

Where to go next on this site, and officially

The lesson this page supports is CI/CD & Progressive Delivery; the reconciler that delivers your Rollout is GitOps Workflows; the SLIs that make analysis meaningful come from Observability; the direct alternative is Flagger; and the whole shed is mapped on The Tool Landscape. Terms like canary and AnalysisRun are defined in the Glossary; when a rollout is stuck, start at Triage: Delivery; and for the wider picture see Release Engineering.

Officially, and for study only: project documentation at argo-rollouts.readthedocs.io (start with Specification and Analysis), source at github.com/argoproj/argo-rollouts, the Argo project home at argoproj.github.io, and the ecosystem map at landscape.cncf.io. For the traffic-routing half, learn the vendor-neutral Kubernetes Gateway API.

🐢 Timmy’s checkpoint

1. What does a Rollout give you that a Deployment’s RollingUpdate cannot, in one sentence? 2. Name the four canary step types. 3. What is the difference between inline analysis and background analysis? 4. What does autoPromotionEnabled default to in a blueGreen strategy, and why does that matter? 5. After an analysis-triggered abort, what is serving traffic and what state is the Rollout in? 6. Why is promote --full dangerous in a pipeline? 7. Can you open the Argo Rollouts docs during the CNPE exam?

Check your answers
  1. Traffic-percentage control that is independent of pod counts, plus measured gates between steps and an automatic abort — a RollingUpdate only knows readiness probes and never stops on its own.
  2. setWeight, pause (timed or indefinite), setCanaryScale, and analysis. (experiment is a fifth, less common one.)
  3. Inline analysis is a steps[].analysis entry that blocks that step until it passes; background analysis is declared at strategy.canary.analysis and runs alongside the whole rollout, so it can abort at any weight.
  4. It defaults to true — so without setting it to false the rollout flips to the new version as soon as preview pods are Ready, and you get no gate at all.
  5. The stable ReplicaSet is serving 100% and the canary is scaled down; the Rollout object still holds the new spec and sits Degraded. It will not retry by itself — you need retry rollout, a new image, or undo. (And your GitOps app may still report Synced.)
  6. It skips all remaining steps and the analysis, promoting straight to 100% — it is an incident tool, not a pipeline step. Automating it turns a Rollout back into a plain Deployment with extra YAML.
  7. No. Only kubernetes.io/docs, kubernetes.io/blog, the exam’s Quick Reference links and local docs are permitted. Fall back to kubectl argo rollouts --help and to reading an existing Rollout with -o yamlkubectl explain is thin for these CRDs.