What is GitOps?#
GitOps is a way of managing infrastructure and application deployments where git is the only source of truth. Instead of
running kubectl apply from your laptop or a CI script, you commit the desired state to a git repo and let an operator
reconcile the cluster toward that state continuously. If someone makes a manual change on the cluster, the operator
reverts it. If a pod crashes or a Deployment gets deleted, the operator notices the drift and corrects it. The cluster
always converges toward what git says it should look like.
What is ArgoCD?#
ArgoCD is the reconciliation operator. It watches a git repo, compares what’s in git against what’s running in the cluster, and syncs the difference. That’s the whole job.
It supports Kustomize, plain YAML, and Helm charts natively. You point it at a path in a repo, tell it which cluster and
namespace to deploy into, and it takes it from there. There’s a web UI for visibility, a CLI for scripting, and a set of
Kubernetes CRDs (Application, ApplicationSet, AppProject) that represent everything it manages.
Source Code#
All manifests, configs, and examples used in this series live in: github.com/ravikrs/blog-argocd
Clone it if you want to follow along hands-on. Each post references the relevant directory.
Prerequisites#
You need:
- A local Kubernetes cluster. This series uses Rancher Desktop (k3s-based), but Minikube or docker desktop (with kubernetes cluster) works too. I am not using docker desktop because I use rancher desktop for office work as well.
kubectlinstalled and configured.brewon macOS (for installing the ArgoCD CLI).
Before doing anything, confirm you’re pointed at the right cluster:
kubectl config current-context # should print: rancher-desktop
kubectl get nodes # should show lima-rancher-desktop ReadyIf you’re on Minikube: kubectl config use-context minikube.
Installing ArgoCD#
Create the namespace and install from the stable manifest:
kubectl create namespace argocd
kubectl apply -n argocd --server-side --force-conflicts \
-f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yamlThe --server-side flag is not optional. The ArgoCD install manifest is large enough that a plain kubectl apply (
client-side) hits Kubernetes’s annotation size limit and silently skips some CRDs, including ApplicationSet. You won’t
see an error. The install appears to succeed. Then argocd-applicationset-controller enters CrashLoopBackOff
immediately and you spend an hour figuring out why.
--force-conflicts handles field manager conflicts if you re-apply on top of an existing install.
Waiting for Pods and Verifying#
Wait for all pods to be ready before proceeding:
kubectl wait --for=condition=Ready pods --all -n argocd --timeout=180sThen verify:
kubectl get pods -n argocdExpected output (all pods Running):
argocd-application-controller-0 1/1 Running
argocd-applicationset-controller-... 1/1 Running
argocd-dex-server-... 1/1 Running
argocd-notifications-controller-... 1/1 Running
argocd-redis-... 1/1 Running
argocd-repo-server-... 1/1 Running
argocd-server-... 1/1 RunningIf any pod is in Pending, check for resource constraints: kubectl describe pod <pod-name> -n argocd.
Accessing the UI#
Port-forward the ArgoCD server. Keep this terminal open:
kubectl port-forward svc/argocd-server -n argocd 8080:443Open https://localhost:8080 in your browser. Accept the self-signed cert warning.
Get the initial admin password:
kubectl get secret argocd-initial-admin-secret -n argocd \
-o jsonpath='{.data.password}' | base64 -d && echoLog in with username admin and that password. The UI shows an empty app list for now.
Installing the CLI and Logging In#
brew install argocd
argocd version --client # verify it installedLog in via CLI (with port-forward still running):
argocd login localhost:8080 \
--username admin \
--insecure--insecure skips TLS verification for the self-signed cert. Fine for local dev.
Verify CLI access:
argocd cluster list # shows the in-cluster entry
argocd app list # empty for nowThe same information is visible in the UI:
- Clusters: Settings (gear icon) → Clusters — shows the in-cluster entry with its status
- Applications: the main dashboard — empty for now, but this is where all your apps will appear once deployed
What Got Installed#
| Component | Role |
|---|---|
argocd-server | API server and web UI |
argocd-repo-server | Clones git repos, renders manifests (Helm, Kustomize) |
argocd-application-controller | Reconciles desired state (git) vs actual state (cluster) |
argocd-applicationset-controller | Generates Applications from templates |
argocd-dex-server | OIDC/SSO provider |
argocd-redis | Cache for repo-server and app-controller |
argocd-notifications-controller | Sends sync and health alerts |
The repo-server and app-controller are the core of the reconciliation loop. The rest is operational scaffolding.
Common Install Gotchas#
argocd-applicationset-controller in CrashLoopBackOff
This is almost always the --server-side problem described above. Check the logs:
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-applicationset-controller --tail=20You’ll see: no matches for kind ApplicationSet in version argoproj.io/v1alpha1. The CRD wasn’t installed because the
client-side apply hit the annotation size limit. Fix it by re-applying with --server-side:
kubectl apply -n argocd --server-side --force-conflicts \
-f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
kubectl get crd applicationsets.argoproj.io # confirm it's there nowThe controller recovers on its next restart automatically.
argocd login times out
The port-forward dropped. Restart it: kubectl port-forward svc/argocd-server -n argocd 8080:443.
Forgot the admin password
The initial password secret is still there until you delete it:
kubectl get secret argocd-initial-admin-secret -n argocd \
-o jsonpath='{.data.password}' | base64 -d && echoArgoCD CRDs not visible in k9s after a cluster restart
Rancher Desktop’s k3s API server can come back before all CRDs are fully re-registered. Restart Rancher Desktop fully (
not just the VM), wait for nodes to reach Ready, then re-open k9s. In k9s, navigate with :applications.argoproj.io
rather than :app, which can be ambiguous.
Further Reading#
If anything above was unfamiliar, these are worth a quick read before continuing with the series.
Setting up your local cluster
- Rancher Desktop — the easiest way to get a local k3s cluster on macOS/Windows/Linux. Install it, enable Kubernetes in preferences, and you’re done. No Docker Desktop license required.
- Rancher Desktop docs: Getting Started — covers install, first-run config, and switching container runtimes (containerd vs. dockerd).
- Minikube — alternative if you already have it or prefer it. Functionally equivalent for this series.
kubectl
- kubectl install guide — official install instructions for macOS, Linux, and Windows.
- kubectl Cheat Sheet — a practical reference for the commands you’ll use most. Bookmark it.
ArgoCD
- ArgoCD official docs — the reference for everything in this series. The Getting Started section there mirrors what we did here, with some extra options.
- ArgoCD GitHub — release notes, open issues, and the install manifests.
Background reading
- GitOps principles (OpenGitOps) — a short, vendor-neutral definition of what GitOps actually means. Useful if the term feels vague.
- k9s — a terminal UI for Kubernetes. Not required, but makes watching pods and logs much faster
than raw
kubectl. Install withbrew install k9s.