Blog Detail

Got Tired of kubectl apply — So We Built a GitOps Pipeline with ArgoCD

Author
PixieBytez Team
May 26, 2026
Tags: argocdgitops
DevOps Deep Dive · May 2025

I Got Tired of kubectl apply — So I Built a GitOps Pipeline with ArgoCD

Stop copying YAMLs around and praying. Here's how I wired up ArgoCD with Kustomize overlays to get proper dev and prod deployments that actually stay in sync with Git.

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.

argocd-gitops-demo/ ├── apps/ │ └── myapp/ │ ├── base/ shared configs │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ └── kustomization.yaml │ └── overlays/ │ ├── dev/ env-specific │ │ ├── kustomization.yaml │ │ └── namespace.yaml │ └── prod/ env-specific │ ├── kustomization.yaml │ └── namespace.yaml └── argocd/ └── myapp-dev-application.yaml

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:

argocd/myapp-dev-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp-dev
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/ninsgosai/argocd-gitops-demo
    targetRevision: HEAD
    path: apps/myapp/overlays/dev  # point at the overlay
  destination:
    server: https://kubernetes.default.svc
    namespace: dev
  syncPolicy:
    automated:
      prune: true   # delete what's removed from Git
      selfHeal: true # revert manual cluster changes

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.

Heads up: Before you apply this, update the 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.

1
Fork the repo and update the repoURL in the Application manifest to point to your fork.
2
Apply the Application resource — this is the only manual step you'll ever do:
terminal
$ kubectl apply -f argocd/myapp-dev-application.yaml

# ArgoCD picks it up immediately
$ kubectl get application myapp-dev -n argocd
NAME        SYNC STATUS   HEALTH STATUS
myapp-dev   Synced        Healthy
3
Make a change in Git. Update a replica count, change an image tag, add a config — then push. Watch ArgoCD sync it automatically.

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

Clone it, fork it, break it, improve it.

View on GitHub