ArgoCD: GitOps with a Dashboard You Might Actually Use
The sync wave diagram that finally made GitOps make sense

Contents
I came to GitOps grudgingly. The pitch — “Git is the single source of truth, the cluster reconciles itself to match” — sounded like the kind of slogan that survives precisely one production incident. Then I tried to debug a drifting Kubernetes cluster the old way, kubectl apply-ing manifests by hand and trying to remember which of three engineers had hotfixed what, and I came round. ArgoCD is the tool that converted me, mostly because of one thing the others don’t do nearly as well: it shows you the state of the world.
What ArgoCD does
ArgoCD is a Kubernetes controller that continuously compares the live state of your cluster against the desired state declared in a Git repo. When they differ, it tells you the resources are OutOfSync, and — depending on your policy — either waits for you to click “Sync” or reconciles automatically. The desired state can be plain YAML, Helm charts, Kustomize overlays, or Jsonnet. You point it at a repo and a path, and it owns that slice of the cluster.
You declare an application as a custom resource, which is itself something you can keep in Git (the “app of apps” pattern):
| |
selfHeal: true is the line that earns its keep. Someone kubectl edits a deployment at 2am to “just try something”? ArgoCD notices the drift and reverts it to match Git within seconds. Your cluster becomes genuinely declarative instead of a pile of accumulated manual changes nobody can reproduce.
Getting it running
Installation is deliberately boring, which I appreciate. You apply the upstream manifests into a dedicated namespace and you have a controller, a repo-server, and an API/UI server:
| |
There’s a small chicken-and-egg charm here: ArgoCD itself can be managed by ArgoCD. You bootstrap it imperatively once, then commit its own configuration to Git and let it adopt itself. That’s the cleanest demonstration of the model — even the tool that enforces “everything in Git” lives in Git.
Two things you’ll wire up almost immediately for anything beyond a port-forward. First, real ingress with TLS — and you do not want to be hand-renewing certificates for an internal dashboard, which is exactly the job I hand to cert-manager so they renew themselves. Second, the manifests ArgoCD syncs are very often Helm charts; ArgoCD renders them server-side, so it’s worth understanding what Helm charts actually do before you point an Application at one and wonder why a value isn’t taking.
The dashboard is the actual feature
Plenty of tools do reconciliation. Flux does it well and lives more comfortably in a pure-CLI workflow. What sets ArgoCD apart is that its dashboard is good — not the usual enterprise afterthought of a UI, but the primary way most people use it. You get a live tree view of every Application: the parent app, its deployments, the replica sets beneath them, the pods beneath those, all colour-coded by sync and health status. A red node anywhere in that tree tells you exactly where a rollout went wrong, and clicking it drops you straight into the events and logs.
When a sync is in flight you watch it happen — resources going from Progressing to Healthy in real time, sync waves applying in order, hooks firing. For anyone who’s ever stared at kubectl get pods hammering the up-arrow to refresh, this is a revelation. It also makes GitOps teachable; you can sit a sceptical colleague in front of it and the model becomes obvious in about ninety seconds.
You can drive the same thing from the CLI when you want automation:
| |
Sync waves, hooks, and the bits that bite
Real applications need ordering — run the database migration before the new app version, not after. ArgoCD handles this with sync waves, an annotation that groups resources into ordered phases:
| |
This works, but it’s the area where teams trip up most: get a wave number wrong and your app starts before its dependencies, fails its health check, and you’re back in the dashboard working out why. The other classic gotcha is prune: true with a misconfigured path — remove a directory carelessly and ArgoCD will dutifully delete the corresponding live resources because that’s exactly what you told it Git wanted. Respect the prune flag.
Troubleshooting the things that actually bite
A handful of failure modes account for most of the time I’ve lost to ArgoCD:
- App stuck
OutOfSyncforever, no obvious diff. Almost always a mutating admission webhook or a controller writing a field that isn’t in your manifest, so ArgoCD sees perpetual drift. The fix isignoreDifferenceson that field’s JSON path — tell ArgoCD “this field is managed elsewhere, don’t fight over it.” Hunt these down early; left alone they train people to ignore the sync status entirely. Healthybut the app is clearly broken. ArgoCD’s health is based on resource-level signals (a Deployment’s available replicas, a Service’s endpoints), not your application’s actual behaviour. A pod can beRunningand crash-looping on real requests. ArgoCD tells you the declared state matches; it can’t tell you your code works.- DNS-shaped weirdness after a sync. Services come up but pods can’t resolve each other, and the dashboard shows everything green because the resources are fine. That’s not ArgoCD — it’s cluster DNS, and it’s worth knowing what actually happens when a pod looks up a name so you don’t waste an hour blaming the deploy tool for a CoreDNS problem.
comparison error: rpc erroron a private repo. The repo-server can’t authenticate. Check the repository credential secret and that therepoURLscheme (https vs ssh) matches the credential type. ArgoCD won’t guess.
RBAC and the multi-user reality
The moment more than one human uses ArgoCD, its default “admin can do everything” stops being acceptable. ArgoCD has a project-and-policy RBAC model: AppProject resources fence which repos, clusters, and namespaces a set of applications may touch, and a policy CSV maps SSO groups to actions. A sensible starting posture is read-only-by-default with sync rights scoped per team:
| |
This is where ArgoCD’s “the dashboard is the product” philosophy earns its keep again: you can hand a developer sync rights to their own project’s apps and nothing else, and they get the live tree view for their slice without the ability to touch anyone else’s. It turns the dashboard from an admin-only console into a self-service surface — which is most of why teams pick it over a pure-CLI tool.
ArgoCD or Flux?
The honest comparison: Flux is lighter, composes beautifully with a GitOps-all-the-way-down toolkit, and lives happily in a pure-CLI/automation workflow where nobody wants a UI to babysit. ArgoCD is heavier — it’s a few more controllers to run — and pays for that weight with the dashboard and the multi-tenant RBAC story. If your team will look at GitOps, ArgoCD. If your GitOps is machinery that humans rarely watch, Flux is the leaner fit. They solve the same problem; they bet differently on whether a human is in the loop.
The app-of-apps pattern, and why it matters
The single Application resource above is fine for one service. The moment you have twenty, manually creating twenty Applications defeats the point — you’ve just moved your manual toil from kubectl apply to the ArgoCD UI. The app-of-apps pattern fixes this: one root Application points at a Git directory full of other Application manifests, so ArgoCD bootstraps and manages your entire fleet from a single committed entry point.
| |
Add a new service by committing a new child Application file to bootstrap/apps; the root notices, and the new app appears in the tree, fully managed. Delete the file and (with prune on) it’s gone. This is where GitOps stops being a slogan and becomes the literal interface to your cluster: the contents of one Git directory are your running platform, and the cost of standing it up again from scratch — the kind of thing I weigh up when thinking about the real cost of self-hosting — drops to “apply the root app and wait.” That reproducibility is the quietly enormous payoff.
Verdict
Is ArgoCD worth it? If you’re running multiple environments or a team where more than one person touches the cluster, yes — the combination of self-healing, an auditable Git history of every change, and that genuinely useful dashboard is hard to give up once you have it. For a single-node homelab that one person manages, it’s arguably overkill; plain kubectl apply from a repo plus a cron job gets you most of the way with none of the controller to operate. The honest dividing line is team size and blast radius. The moment “who changed this and why” becomes a question you can’t answer from memory, ArgoCD pays for itself. The dashboard is the bit you’ll miss first if you ever leave.
One last caveat worth stating plainly: ArgoCD makes your cluster only as reliable as your Git repo and your manifests. It will faithfully reconcile a broken state into your cluster just as eagerly as a good one, and selfHeal means it’ll keep dragging you back to that broken state until you fix the source. That’s not a flaw — it’s the whole contract — but it does mean the discipline moves upstream into how you review changes to Git. Get that habit right and ArgoCD is the most honest operator on your cluster, doing exactly what the repo says, visibly, every time. Get it wrong and it’s a very efficient way to deploy your mistakes. Either way, you always know precisely what it did and why, which is more than I can say for the era of hand-applied manifests it replaced.




