GitOps: Declarative Delivery With Argo CD and Flux

Delivery as a control loop, not a push
Traditional deployment is a push: a pipeline runs, holds cloud credentials, and imperatively applies changes to a cluster. It works until you ask hard questions. What is actually running right now? Who changed it, and does it match what we think we deployed? How do we roll back cleanly? Push pipelines answer these poorly because the desired state lives in a transient pipeline run and the actual state drifts quietly afterward.
GitOps reframes delivery as a continuous control loop. The desired state of a system is declared, in full, in a Git repository. A controller running inside the target environment continuously compares that declared state to what is actually running and reconciles the difference — pulling changes in rather than having a pipeline push them. Git becomes the single source of truth; the cluster becomes an expression of it. Four properties define the model: the whole system is described declaratively, the desired state is versioned in Git, approved changes are applied automatically, and controllers continuously reconcile to correct drift.
Why the reconciliation model earns its keep
The shift from push to pull-based reconciliation is not cosmetic. It changes what you can guarantee:
- Git is the audit log. Every change is a commit — authored, reviewed, and
timestamped. "What changed and who approved it" is answered by
git log, not by correlating pipeline runs. - Rollback is a revert. Because the repository is the desired state, undoing a bad change is reverting a commit and letting the controller reconcile back. No bespoke rollback scripting.
- Drift is detected and, optionally, corrected. If someone hand-edits a live resource, the controller sees the divergence from Git and can flag it or heal it automatically. This closes the gap between what you believe is deployed and what is — a gap that continuous cloud security posture management otherwise has to catch after the fact.
- Credentials stay inside the boundary. The controller pulls from Git and applies locally, so your CI system never needs standing cluster admin credentials pointed inward.
Argo CD and Flux: same principle, different shape
Two mature CNCF projects implement GitOps for Kubernetes. Both reconcile Git to cluster; they differ in ergonomics and philosophy.
Argo CD is application-centric and ships a first-class UI. You model each
deployable unit as an Application resource pointing at a repo path, and the
dashboard visualizes sync status, health, and the live resource tree — which makes
it approachable for teams that want to see what GitOps is doing. ApplicationSets
template many applications across clusters or environments, and the app-of-apps
pattern bootstraps a whole platform from one root application.
Flux is a set of composable controllers — the GitOps Toolkit — that lean into Kubernetes-native, API-driven operation. Sources, Kustomizations, and Helm releases are separate custom resources you compose, with no bundled UI by default. Flux also includes strong image automation, watching a registry and committing image updates back to Git automatically.
| Dimension | Argo CD | Flux |
|---|---|---|
| Model | Application CRD, app-centric | Composable toolkit controllers |
| UI | Rich built-in dashboard | API-first; UI is external |
| Multi-target scaling | ApplicationSets, app-of-apps | Kustomization composition |
| Image updates | Add-on component | Built-in image automation |
| Best fit | Teams wanting visibility out of box | Teams wanting Kubernetes-native pieces |
Neither is a wrong choice. Argo CD tends to win where a visible control plane and team-friendly UI matter; Flux tends to win where teams want lean, composable controllers they wire into their own workflow.
The secrets problem you have to solve
GitOps has one obvious tension: if Git is the source of truth for everything, what about secrets? You cannot commit plaintext database passwords and API keys to a repository. Every real GitOps rollout has to answer this, and there are three common patterns:
- Encrypted-in-Git. Tools like Sealed Secrets or SOPS encrypt secret values so the ciphertext can live safely in the repository, decrypted only by a controller holding the key inside the cluster. Simple and self-contained.
- External secret references. An operator syncs values from a dedicated secrets manager (a cloud KMS-backed store or vault) into the cluster at runtime. Git holds only a reference, never the value — often the cleaner separation of concerns.
- Provider-native injection. Some platforms inject secrets from a managed store at pod start, keeping them out of both Git and the cluster's own store.
Pick one deliberately and enforce it. An accidental plaintext secret in a GitOps repo is worse than in a pipeline, because the repo is designed to be widely readable and permanently retained.
Progressive delivery on top of GitOps
Reconciliation gives you correctness; it does not by itself give you safe rollouts. A synced-but-broken version is still broken. Progressive delivery layers controlled rollout strategies onto the GitOps loop:
- Canary and blue-green releases shift a small slice of traffic to the new version, watch real signals, and proceed only if health holds. Argo Rollouts and Flagger drive this on top of Argo CD and Flux respectively.
- Automated analysis and rollback. Tie promotion to metrics — error rate, latency, saturation — so a failing canary is rolled back automatically rather than waiting for a human to notice.
- The Git trail still holds. Even with progressive delivery, the desired end state lives in Git, so the audit and rollback guarantees carry through.
This is where GitOps stops being a deployment convenience and becomes a genuine reliability control.
Where GitOps bites, and how to avoid it
- Sprawling repositories. Cramming every environment and app into one repo produces a blast radius nobody can reason about. Structure repos and paths so ownership and access map to teams.
- Drift-correction surprises. Auto-heal is powerful and occasionally hostile — it will happily revert a legitimate emergency hotfix someone applied by hand. Decide per environment whether reconciliation heals automatically or only alerts.
- Non-Kubernetes resources. GitOps for clusters is mature; extending the same discipline to cloud infrastructure needs a control-plane approach so databases, queues, and networks are reconciled the same way, not managed on the side.
- Order and dependencies. Sync waves and health checks exist because naively applying everything at once breaks on dependencies. Use them.
Where to start
Put one non-critical application under GitOps end to end before converting the estate. Move its manifests into a repository, install Argo CD or Flux, and let the controller own reconciliation — then deliberately hand-edit a live resource and watch it get flagged or healed, so the model becomes real to the team. Solve secrets on day one, not day thirty. Once one service proves the loop, expand by team and environment, and add progressive delivery where a bad release would hurt.
GitOps is a delivery discipline that only pays off when the surrounding cloud infrastructure, access model, and secrets handling are designed to support it. If you want help standing up declarative delivery that your auditors and your on-call both trust, talk to our team.


