Implement GitOps with ArgoCD on Kubernetes
Deployments feel shaky when you have to click through a UI, edit a YAML file on the fly, and pray the pod starts. That nervous feeling is why many teams are moving to GitOps – a way to let Git be the single source of truth for everything that runs in the cluster. In this post I’ll walk you through a practical workflow using ArgoCD, the open‑source tool that makes GitOps feel almost magical on Kubernetes.
Why GitOps matters right now
If you’ve ever rolled back a release because a config typo broke the service, you know the pain of “manual drift”. When you store the desired state in Git, every change is versioned, reviewed, and can be replayed. That alone cuts down on hot‑fixes and makes audits a breeze. Plus, with the cloud moving faster than ever, you need a repeatable, automated path from code to cluster – GitOps gives you exactly that.
Core concepts in plain language
- Git as source of truth – Think of Git as the master recipe book. Anything you want running in the cluster lives in a repo.
- Declarative state – Instead of telling Kubernetes “run this command now”, you describe what you want (pods, services, config) and let the system make it happen.
- Continuous reconciliation – ArgoCD constantly checks the live cluster against the repo. If they differ, it can automatically fix the drift or alert you.
Setting up the basics
1. Prepare a Git repo
Create a new repo under your favorite Git host (GitHub, GitLab, Bitbucket). Inside, make a folder called manifests/ and drop in the Kubernetes YAML files for your app – deployment, service, ingress, configmap, everything. Keep the structure simple; for example:
manifests/
├─ base/
│ ├─ deployment.yaml
│ └─ service.yaml
└─ overlays/
└─ prod/
└─ kustomization.yaml
I like to use Kustomize for overlays because it lets me keep a clean base and add environment‑specific tweaks without copying files.
2. Install ArgoCD on the cluster
Run the following one‑liner (you need kubectl already pointing at your cluster):
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
That pulls the ArgoCD control plane into the argocd namespace. Wait a minute for the pods to start, then expose the UI with port‑forward:
kubectl port-forward svc/argocd-server -n argocd 8080:443
Now you can open https://localhost:8080 in your browser. The default admin password is the pod name of argocd-server; you can fetch it with:
kubectl -n argocd get pod -l app.kubernetes.io/name=argocd-server -o name | cut -d'/' -f2
3. Connect ArgoCD to your repo
In the UI, click Settings → Repositories and add a new Git repo. Supply the HTTPS URL and a personal access token with read rights. If you prefer CLI, the same can be done with:
argocd repo add https://github.com/yourorg/yourrepo.git \
--username youruser --password $TOKEN
Defining an application in ArgoCD
An Application is ArgoCD’s way of saying “this part of the repo should be synced to this namespace”. Create a file called argocd-app.yaml:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/yourorg/yourrepo.git
targetRevision: HEAD
path: manifests/overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # delete resources that are removed from Git
selfHeal: true # fix drift automatically
syncOptions:
- CreateNamespace=true
Apply it:
kubectl apply -f argocd-app.yaml
ArgoCD will now read the manifests, compare them to what’s running in production, and create any missing resources. The UI will show a green check when everything is in sync.
A practical workflow for reliable deployments
- Feature branch – Developers work on a feature branch, add or modify manifests as needed, and push to the remote.
- Pull request – The PR triggers CI (GitHub Actions, GitLab CI, etc.) that runs
kubevalorkube-scoreto catch syntax errors early. - Review & merge – Once the PR is approved, it merges into
main. Themainbranch is the GitOps “live” branch. - ArgoCD auto‑sync – Because we set
automated.selfHealto true, ArgoCD sees the new commit and starts a sync. If the sync fails, ArgoCD marks the app as “OutOfSync” and you can view the error details. - Rollback – Need to roll back? Just revert the commit in Git, and ArgoCD will automatically roll the cluster back to the previous state. No extra scripts, no manual
kubectl delete.
Handling secrets safely
Never store raw secrets in the repo. I use Sealed Secrets – you encrypt a secret locally, commit the sealed version, and let a controller in the cluster decrypt it at runtime. The workflow looks like:
kubectl create secret generic db-pass --from-literal=password=SuperSecret123 -o yaml --dry-run=client | \
kubeseal --cert mycert.pem -o yaml > sealed-db-pass.yaml
git add sealed-db-pass.yaml
git commit -m "Add sealed DB password"
ArgoCD treats the sealed secret like any other manifest, so the secret ends up in the right namespace without ever exposing the clear text.
Monitoring and troubleshooting
ArgoCD ships with a built‑in dashboard that shows sync status, health, and recent events. If a pod crashes after a sync, the UI will flag the app as “Degraded”. Click the app, go to Events, and you’ll see the exact Kubernetes error. Because the desired state lives in Git, you can always compare the live manifest (kubectl get deployment my-app -o yaml) with the version in the repo to spot differences.
For deeper logs, run:
kubectl logs -n argocd deployment/argocd-repo-server
That shows any repo fetch errors, which are often caused by expired tokens.
Tips to keep your GitOps pipeline smooth
- Keep manifests small – Split large apps into multiple ArgoCD Applications. This isolates failures and speeds up sync.
- Use Kustomize or Helm – Both let you templatize values without hard‑coding them.
- Enable pruning – Without
prune: true, removed resources linger in the cluster, leading to hidden drift. - Lock down access – Give developers read‑only access to ArgoCD UI; let the CI pipeline handle the actual sync triggers. This reduces accidental manual changes.
My personal takeaway
When I first tried to set up GitOps, I spent a whole afternoon wrestling with a mismatched namespace and a missing kustomization.yaml. The moment I got the automated sync working, the relief was palpable – no more “it works on my laptop” surprises. Now I treat every change as a commit to the repo, and the cluster behaves like a well‑kept garden: you plant a seed, step back, and let the system take care of the growth.
Give ArgoCD a spin on your next project. The learning curve is short, the payoff is big, and your future self will thank you every time a rollback is just a Git revert away.
- → How to Build a CI/CD Pipeline with GitHub Actions for Faster Deployments @techfrontier
- → End-to-End Production Pipeline: Deploying a Scalable Deep Learning Model on Kubernetes @mlengineerplay
- → 10 Ready‑to‑Use Automation Scripts That Cut Release Time in Half for Small DevOps Teams @devopschronicle
- → Step-by-step guide to building a zero‑downtime CI/CD pipeline on AWS with GitHub Actions @devopschronicle
- → Step‑by‑Step Server Documentation Workflow to Reduce Errors and Speed Deployments @checkpresenterinsights