Let me be honest. For the longest time, my deployment workflow was embarrassingly manual. I'd kubectl apply -f a bunch of YAML files, SSH into the cluster to double-check, then nervously hope nothing had drifted since the last time I touched it. Production would slowly stop looking like what was in Git, and I'd have no idea when or why.
Sound familiar? Yeah, I thought so.
The fix wasn't complicated — it just required actually sitting down and doing it. I put together a minimal but real ArgoCD + Kustomize setup that handles both a dev and a prod environment from a single Git repository. No Helm charts, no magic operators — just clean declarative YAML and a tool that watches Git and keeps your cluster honest.
"The moment you push a commit, ArgoCD notices. It doesn't ask for permission — it just makes the cluster match what's in Git. That's the whole idea."
What Even Is GitOps?
Before we dive in — real quick. GitOps is just the practice of treating your Git repository as the single source of truth for your infrastructure. Not your laptop. Not a Jenkins job. Not someone's muscle memory. Git.
ArgoCD is a Kubernetes controller that watches a Git repo and continuously reconciles your cluster to match whatever's declared there. If someone manually changes a resource in the cluster? ArgoCD notices and reverts it. If you push a new image tag to Git? ArgoCD applies it. It's the closest thing to a self-healing deployment pipeline I've found that doesn't require a PhD to operate.
The Repo Structure
The whole thing lives at github.com/ninsgosai/argocd-gitops-demo. I kept the structure as clear as possible — there's nothing clever or obscure here.
The key insight is the base + overlays pattern from Kustomize. You write your core Deployment and Service once in base/, and then each environment's overlay just patches the differences. No copy-pasting, no drift between environments. Dev and prod share the same base image and structure — they just differ in replica count and namespace.
Dev vs. Prod — What's Actually Different
Here's how the two environments break down:
| Environment | Namespace | Replicas | Image |
|---|---|---|---|
| dev | dev | 1 | nginx:1.27 |
| prod | prod | 3 | nginx:1.27 |
That's it. Dev is lean — one replica, its own namespace, just enough to test. Prod gets three replicas for basic availability. The image tag is the same right now, but you'd naturally point them at different tags as you promote versions through environments.
The ArgoCD Application Manifest
This is the piece that wires everything together. The ArgoCD Application resource tells ArgoCD: "Watch this Git repo, look at this path, and make the cluster match it." Here's what the dev application looks like:
Two lines worth paying attention to — prune: true and selfHeal: true. Prune means if you remove a resource from Git, ArgoCD removes it from the cluster. Self-heal means if someone manually edits something in the cluster, ArgoCD reverts it back to what Git says. Together, they make Git the unambiguous authority — no sneaky manual changes that go undocumented.
repoURL field to point to your own fork of the repo. You can't push commits to mine, so you'll need your own copy to actually trigger sync events.
Getting It Running
The setup is three steps. You'll need a Kubernetes cluster (local with kind/k3d works fine) and ArgoCD already installed in the argocd namespace.
repoURL in the Application manifest to point to your fork.
For prod, it's the same pattern — create a second Application resource pointing at apps/myapp/overlays/prod and apply it. One cluster, two environments, both Git-managed, zero manual state to track.
Why Kustomize and Not Helm?
Honestly? Kustomize felt like the right tool for a demo because it has zero abstraction overhead. There are no templates, no values files, no {{ .Values.something }} scattered everywhere. You read a Kustomize file and it immediately tells you what it does.
The base + overlays mental model is also really clean for multi-environment setups. Your base is the canonical app definition. Each overlay is just a patch — a minimal diff. You never copy files, you just declare what's different. That's a discipline that scales surprisingly well even as the app grows.
Helm shines when you're building reusable charts for others to consume. Kustomize shines when you're managing your own app across environments. Different tools for different problems.
What I'd Add Next
This is genuinely a starting point, not a finished pipeline. A few things I'd layer on for a real project:
Image updater. Right now the image tag is hardcoded in the overlay. ArgoCD Image Updater can watch a container registry and automatically commit updated tags back to Git when a new image is pushed — completing the full GitOps loop without any CI step needing to touch the cluster directly.
Sealed Secrets or External Secrets. You obviously can't commit raw Kubernetes Secret manifests to a public repo. Sealed Secrets encrypts them in a way that only your cluster can decrypt, so they're safe to commit. External Secrets pulls them from Vault or AWS Secrets Manager at runtime. Both integrate cleanly with ArgoCD.
App of Apps pattern. Once you have more than a couple of applications, managing each ArgoCD Application resource individually gets tedious. The App of Apps pattern is a single parent Application that manages all your child Applications — so you still have one apply to bootstrap the entire cluster.
The Part Nobody Talks About
The real value of GitOps isn't speed — it's audit trail and confidence. When something breaks at 2am and you need to know what changed and when, your Git history is the source of truth. Every deployment is a commit with a timestamp, an author, and a diff. That's worth a lot.
"Every deployment is a commit. Every rollback is a revert. The cluster and the repo are always in sync — and if they're not, ArgoCD tells you immediately."
There's also something psychologically nice about knowing that whatever's in your cluster is exactly what's in Git. You stop second-guessing yourself. You stop wondering if someone applied a hotfix directly and forgot to commit it. The cluster doesn't lie, because it can't — ArgoCD is watching.
Open Source · MIT License

