Shipping a new version of an application is always a small act of faith. Even with tests passing and a green CI pipeline, nothing tells you how code behaves under real production traffic quite like… real production traffic. Canary deployments exist to make that leap of faith smaller — and combined with GitOps, the whole process becomes safer, more visible, and easier to reason about.
What is Argo CD?
Argo CD is a GitOps continuous delivery tool for Kubernetes. It watches a Git repository containing your desired application manifests, compares that against what’s actually running on the cluster, and either flags the difference or automatically reconciles it — depending on how you’ve configured syncing.
On OpenShift specifically, Argo CD is distributed as part of the Red Hat OpenShift GitOps operator, which packages Argo CD alongside supporting components (a web console plugin, notifications, and optional integration with Argo Rollouts) as a fully supported, operator-managed installation rather than something you’d deploy and patch by hand.
What is a canary deployment?
A canary deployment routes a small percentage of live traffic to a new version of your application while the majority of traffic continues to hit the known-good version. If the new version behaves well — no errors, healthy response times, whatever signals matter to you — you gradually increase its share of traffic until it’s serving everything. If something looks wrong, you roll back having only ever exposed a fraction of your users to the problem.
Canary vs. the other deployment strategies
Recreate — the bluntest approach. Tear down the old version entirely, then bring up the new one. Simple, but guarantees downtime and offers zero rollback safety net; if the new version is broken, everyone is affected immediately.
Rolling update — the Kubernetes default. Old pods are replaced by new ones a few at a time until the whole fleet is on the new version. No downtime, but also no fine control over traffic split — once a pod is replaced, it’s serving 100% of whatever traffic lands on it, and there’s no deliberate “small percentage first” gate.
Blue/Green — run two complete environments side by side, “blue” (current) and “green” (new), both at full scale. When you’re confident, you switch traffic from blue to green all at once, typically with an instant router or load balancer flip. Rollback is instant — just flip back. The tradeoff is cost: you’re running double the infrastructure during the transition, and you’re testing “all or nothing” rather than a gradual signal.
Canary — the middle ground. Unlike rolling updates, you get explicit, deliberate control over exactly what percentage of traffic sees the new version, and you can pause at any point. Unlike blue/green, you don’t need to double your infrastructure — the new version scales up gradually as the old version scales down, so total capacity stays constant throughout.
Progressive delivery is worth a mention too — it’s canary taken further, where the percentage increases automatically based on live metrics and health checks (error rates, latency, custom business metrics) rather than a human deciding when to promote. Canary with manual approval gates, which this post focuses on, is the simpler and often the right starting point before investing in automated analysis.
What GitOps adds to canary deployments
None of the deployment strategies above require GitOps — you could run a canary rollout with nothing but kubectl and a lot of discipline. What GitOps (via Argo CD) specifically contributes:
A single source of truth. The desired state of your application — which version should be running, how many replicas, what the canary steps look like — lives in a Git repository, not scattered across imperative commands someone ran at some point. Anyone can look at the repo and know exactly what should be deployed.
Auditability. Every change to what’s running is a Git commit. Who bumped the version, when, and (via commit messages) why, is permanent history — not something you have to reconstruct from memory or cluster logs after the fact.
Drift detection and correction. If someone manually changes something on the live cluster that doesn’t match Git, Argo CD notices and flags it — or, with auto-sync and self-healing enabled, corrects it automatically. The cluster can’t silently diverge from what’s documented.
A visual, safe review layer before changes go live. With manual sync policies, a change sitting in Git doesn’t touch the cluster until someone deliberately approves the sync — a second checkpoint before deployment, separate from the canary’s own approval gates.
Consistent, repeatable environments. The same Git repository can be pointed at multiple clusters or namespaces, producing identical deployments without manual re-entry of configuration each time.
Environment:
OpenShift 4.18
MetalLB and the GitOps Operator
An external GitLab instance (you can use any Git repository)
Canary-based app deployment and testing
Test demo flow — Deploy the app first at version v1, then update the image tag in Kustomize to trigger a canary rollout, and observe how the canary deployment progresses from v1 to v2.
Search for GitOps in OperatorHub and install it.
You can keep the default configuration and click Install.
You can download all the YAML files required for the canary deployment from the link below and upload them to any Git repository:
https://github.com/Dineshk1205/canary.git
I’m using GitLab — you can see all my files in the GitLab repo below.
Once the GitOps Operator is installed, open the Argo CD dashboard. Click New App to create an application.
Give the app a name, and either use the default project or create your own with limited access. Set the sync policy to Automatic, and turn on the Auto-Create Namespace option so the target namespace gets created for you.
Under the source section, enter your repository URL — in my case: http://gitlab.kdinesh.com/demo/demo.git Then set the revision and the path to your manifests. For the destination, if Argo CD is running on the same cluster, the destination URL is: https://kubernetes.default.svc Set the destination namespace — I used version-demo.
Once everything’s filled in, click Create.
Argo CD picks up the manifests from the Git repo and creates the corresponding resources on the cluster.
Here, I deployed a sample web app at version v1 with 6 replicas.
You can confirm from the CLI that the app’s pods are running the v1 version.
You can also open the app in a browser and check its status page — it shows the replica count and live traffic split in real time. (For this test, I built a small container image specifically to report its own version, replica count, and traffic distribution live.)
Now, back in the Git repo, update the image tag from v1 to v2. Argo CD picks up the change automatically and rolls it out to the OpenShift cluster according to the canary strategy defined in the Rollout.
You can follow the rollout’s progress in Argo CD’s Rollout view. The strategy here is set to pause at 25% for manual approval; once approved, it moves to 50%, waits 60 seconds, advances to 75%, waits another 60 seconds, and finishes at 100%. These weights and wait times are fully configurable — adjust them to whatever fits your own environment. Following this strategy, the rollout starts at 25%. Once you approve it, it moves to 50%, waits 60 seconds, advances automatically to 75%, waits another 60 seconds, and completes at 100%. You can roll back at any point during this process.
Below, you can see the rollout paused at 25%, waiting for manual approval — 2 pods are already running v2 while the remaining pods are still on v1.
Here you can confirm it directly: 2 pods on the v2 image, the rest still on v1.
The dashboard reports this in real time too — 2 pods on v2, 5 on v1. Let’s generate some traffic and see how it’s actually being split.
After generating traffic, the CLI confirms it’s being distributed across both versions — v2 is currently handling about 25%, matching the current step. If everything looks healthy at this point, you can go ahead and approve, which continues the rollout through 50% > wait 60 sec > 75% > wait 60 sec > 100%.
The same information is available right in the app’s own dashboard, no CLI needed.
Time to approve. A few options are available here — choosing Abort rolls everything back to v1 immediately if something looks wrong. If it all looks good, click Resume to continue.
Click Resume to approve and continue the rollout.
The rollout is now at 50%, with 3 pods on v1 and 3 on v2 sharing traffic. It’ll wait 60 seconds before advancing to 75%.
Generating traffic again confirms the split — v1 and v2 are each handling roughly 50%, exactly as the canary strategy defines at this step.
From here, the rollout continues scaling the new version up automatically.
And finally, all pods are running v2 — the rollout is complete.
That’s the core value of canary deployments: rolling out updates gradually, with real checkpoints along the way, so problems get caught early instead of hitting everyone at once.
The following steps demonstrate how to back up and restore an OpenShift virtual machine using…
OpenShift Virtualization allows virtual machines (VMs) to run natively on Kubernetes alongside container workloads. Using…
Red Hat OpenStack Services on OpenShift (RHOSO) provides the foundation to build a private or public…
Kubernetes (often shortened to “K8s”) is an open-source system for automating the deployment, scaling, and…
Ceph is an open-source, distributed storage platform that provides object, block, and file storage in…
Prerequisites Red Hat OpenShift cluster deployed and operational You can refer to my earlier post…