GitOps for Kubernetes, hands-on. You'll install Argo CD, deploy your first application from Git, understand sync and self-healing, and adopt the patterns teams use to run hundreds of apps safely.
| You need | Why |
|---|---|
| A Kubernetes cluster (Minikube/kind/Docker Desktop) | Argo CD installs into it and deploys to it |
kubectl configured for that cluster |
You install Argo CD and inspect resources with it |
| Basic Kubernetes + Git familiarity | You'll deploy manifests from a Git repo |
If you're new to Kubernetes, do the Kubernetes getting-started tutorial first. Confirm your cluster is reachable: kubectl get nodes.
Argo CD makes Git the source of truth for what runs in your cluster. Instead of running kubectl apply from a laptop or a CI job, you commit manifests to a repo, and Argo CD continuously reconciles the cluster to match.
Git repo (desired state) -> Argo CD (reconcile) -> Kubernetes (actual state)
The payoffs: every change is reviewed and auditable, rollbacks are a git revert, and drift is detected (and optionally auto-corrected).
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Wait for the pods, then grab the initial admin password and open the UI:
kubectl -n argocd rollout status deploy/argocd-server
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath='{.data.password}' | base64 -d; echo
kubectl -n argocd port-forward svc/argocd-server 8080:443
Open https://localhost:8080 (accept the self-signed cert) and log in as admin. Install the CLI too — it's the fastest way to learn:
argocd login localhost:8080 --username admin --insecure
An Application is Argo CD's core object: it says "take the manifests at this path in this repo and keep this cluster/namespace matching them."
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: guestbook
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/argoproj/argocd-example-apps
targetRevision: HEAD
path: guestbook
destination:
server: https://kubernetes.default.svc
namespace: guestbook
syncPolicy:
syncOptions:
- CreateNamespace=true
Apply it, then sync:
kubectl apply -f guestbook-app.yaml
argocd app sync guestbook
Argo CD reads the repo, renders the manifests, and applies them. The UI shows a live resource tree — Deployment → ReplicaSet → Pods — colored by health and sync status.
Two independent signals Argo CD tracks for every app:
Synced or OutOfSync.Healthy, Progressing, Degraded, Missing.Try it: kubectl scale deploy/guestbook-ui -n guestbook --replicas=5. Argo CD immediately marks the app OutOfSync — the cluster no longer matches Git. That's drift detection.
Manual sync is training wheels. In production you want Argo CD to apply changes automatically and undo manual tampering:
spec:
syncPolicy:
automated:
prune: true # delete resources removed from Git
selfHeal: true # revert manual cluster changes back to Git
syncOptions:
- CreateNamespace=true
prune — if you delete a manifest from Git, Argo CD deletes it from the cluster. Without it, orphans pile up.selfHeal — that manual kubectl scale from step 4 gets reverted within seconds. Git wins, always.Because Git is the source of truth, rollback is just history:
argocd app history guestbook
argocd app rollback guestbook <revision>
But the cleaner path is git revert the bad commit — the change flows through review and Argo CD syncs it. Treat the Argo CLI rollback as a break-glass tool, not the normal path.
Two questions every team answers:
How do I template per-environment? Point the Application source at a Kustomize overlay or a Helm chart with per-env values:
source:
repoURL: https://github.com/acme/deploy
path: overlays/production
targetRevision: main
How do I manage many apps? Use the App-of-Apps pattern or ApplicationSets. An ApplicationSet generates one Application per cluster, per folder, or per Git branch:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: all-services
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/acme/deploy
revision: main
directories:
- path: services/*
template:
metadata:
name: '{{path.basename}}'
spec:
project: default
source:
repoURL: https://github.com/acme/deploy
targetRevision: main
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{path.basename}}'
syncPolicy:
automated: { prune: true, selfHeal: true }
Add a service folder, and a new Application appears automatically.
default.argocd.argoproj.io/sync-wave annotations.OutOfSync or Degraded.argocd app sync / CLI rollback. Those are training wheels and break-glass tools. The normal path is commit to Git; let reconciliation do the rest.default AppProject. No guardrails means any app can touch any namespace/cluster. Scope apps with AppProjects.selfHeal on without understanding it. Manual kubectl changes get silently reverted — great in prod, confusing if you didn't expect it. Know that Git always wins.prune. Without it, resources you delete from Git linger as orphans in the cluster.sync-wave annotations.Synced means "matches Git," not "working." A synced app can still be Degraded.kubectl scale the deployment to 5 replicas and watch it flip OutOfSync. Enable automated.selfHeal and watch it revert within seconds.argocd app rollback and (b) git revert the commit. Which one leaves Git as the source of truth?git directory generator, then add a new service folder to the repo — confirm a new Application appears on its own.Self-check:
prune and selfHeal each do — and what breaks if you omit each?git revert the preferred rollback over the Argo CLI?You've gone from a single manual sync to auto-healing, multi-app GitOps — the way platform teams actually run Kubernetes.
Learned the concepts? Test yourself with Argo CD interview questions.
Go to the question bank →