ArgoCD: GitOps on Your Kubernetes Cluster Step by Step

Updated March 2026: This article uses ArgoCD v3.3.x (the latest stable version) with the official manifests installation.
What is ArgoCD?
If you followed the Kubernetes series (set up the cluster, resources, HPA, Prometheus + Grafana), you already know how to deploy and monitor apps. But there’s a problem: every time you change something, you have to run kubectl apply manually. What if you forget? What if someone applies a change directly to the cluster that isn’t in any repo?
ArgoCD solves exactly this. It’s a declarative Continuous Delivery tool for Kubernetes that implements the GitOps pattern: your Git repository is the source of truth for your cluster state. ArgoCD watches the repo, compares what’s in Git against what’s in the cluster, and if there are differences, syncs them automatically.
Think of ArgoCD as a tireless watchdog: it’s listening to your repo 24/7. When someone merges a PR with new manifests, ArgoCD detects it in seconds and updates the cluster. If someone modifies something directly in the cluster with kubectl, ArgoCD reverts it to the state defined in Git.
Why GitOps?
Before installing anything, let’s understand why this matters:
- Full audit trail: every cluster change has a commit with author, date, and description.
git logis your deployment history. - Instant rollback: if something breaks,
git revertand ArgoCD restores the previous state. - Zero direct cluster access: developers don’t need
kubectl. They create PRs, get reviews, approve, and ArgoCD deploys. - Guaranteed consistency: the cluster always reflects what’s in the repo. No drift, no ghost changes.
- Disaster recovery: if you lose the cluster, just reinstall ArgoCD and point it to the repo. It rebuilds everything on its own.
Prerequisites
For this tutorial you need what we installed in the Kubernetes post:
| Tool | Version | Notes |
|---|---|---|
| OrbStack (macOS) or Docker Desktop (Windows/Linux) | — | Container runtime |
| Kind | v0.20+ | Local Kubernetes cluster |
| kubectl | v1.35+ | CLI to interact with K8s |
If you followed the Kubernetes post, you already have everything installed. Just verify your cluster is running:
macOS (with OrbStack)
# OrbStack should already be running (icon in the menu bar)
kind get clusters
# If you don't have a cluster:
kind create cluster --name mi-clusterWindows (with Docker Desktop + WSL2)
Make sure Docker Desktop is running with the WSL2 backend. Open your WSL2 terminal:
# Verify Docker is working
docker info
# Check the cluster
kind get clusters
# If you don't have one:
kind create cluster --name mi-clusterLinux
# Verify Docker is running
sudo systemctl status docker
# Check the cluster
kind get clusters
# If you don't have one:
kind create cluster --name mi-clusterStep 1: Install ArgoCD on the Cluster
Installation is straightforward — one namespace and the official manifests:
# Create the namespace
kubectl create namespace argocd
# Install ArgoCD (stable version)
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Wait for everything to be ready
kubectl wait --for=condition=available --timeout=120s deployment/argocd-server -n argocdVerify all pods are running:
kubectl get pods -n argocdNAME READY STATUS RESTARTS AGE
argocd-application-controller-0 1/1 Running 0 60s
argocd-dex-server-xxx 1/1 Running 0 60s
argocd-notifications-controller-xxx 1/1 Running 0 60s
argocd-redis-xxx 1/1 Running 0 60s
argocd-repo-server-xxx 1/1 Running 0 60s
argocd-server-xxx 1/1 Running 0 60shelm install argocd argo/argo-cd) if you prefer managing configuration as a chart. For high-availability production setups, there’s an HA variant with multiple replicas.Step 2: Install the ArgoCD CLI
The CLI lets you interact with ArgoCD from your terminal:
macOS
brew install argocdLinux
curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x argocd
sudo mv argocd /usr/local/bin/Windows
# With Scoop
scoop install argocd
# Or with Chocolatey
choco install argocd-cliVerify the installation:
argocd version --clientStep 3: Access the ArgoCD UI
ArgoCD has a pretty solid web interface. To access it from your local machine:
# Port-forward to the ArgoCD server
kubectl port-forward svc/argocd-server -n argocd 8080:443Now open https://localhost:8080 in your browser (accept the self-signed certificate).
Get the Admin Password
# The initial password is stored in a secret
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath='{.data.password}' | base64 --decodeThe username is admin and the password is what the command returned.
Login from the CLI
argocd_pass=$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 --decode)
argocd login localhost:8080 --insecure --username admin --password $argocd_passIn production, change the admin password immediately and delete the initial secret:
argocd account update-password
kubectl -n argocd delete secret argocd-initial-admin-secretStep 4: Prepare the Manifests Repository
For this example, we’ll use a repository with the following structure:
k8s-configs/
├── apps/
│ ├── nginx-demo/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── hpa.yamlCreate a repository on GitHub (for example k8s-configs) and add these files:
apps/nginx-demo/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-demo
namespace: staging
labels:
app: nginx-demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx-demo
template:
metadata:
labels:
app: nginx-demo
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
ports:
- containerPort: 80
resources:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "200m"
memory: "128Mi"apps/nginx-demo/service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-demo
namespace: staging
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
app: nginx-demoapps/nginx-demo/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-demo-hpa
namespace: staging
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-demo
minReplicas: 2
maxReplicas: 6
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50Don’t forget to create the namespace:
kubectl create namespace stagingStep 5: Create Your First Application in ArgoCD
Now comes the magic. Let’s tell ArgoCD to watch our repository:
Option A: From the CLI
argocd app create nginx-demo \
--repo https://github.com/YOUR_USERNAME/k8s-configs.git \
--path apps/nginx-demo \
--dest-server https://kubernetes.default.svc \
--dest-namespace staging \
--sync-policy automated \
--auto-prune \
--self-healOption B: With a YAML Manifest (recommended)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nginx-demo
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/YOUR_USERNAME/k8s-configs.git
targetRevision: main
path: apps/nginx-demo
destination:
server: https://kubernetes.default.svc
namespace: staging
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- Validate=true
- ServerSideApply=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3mkubectl apply -f application.yamlWhat Do These Options Mean?
| Option | What it does |
|---|---|
automated | Automatically syncs when it detects changes in Git |
prune: true | If you delete a file from Git, deletes the resource from the cluster |
selfHeal: true | If someone changes something with kubectl, reverts it to Git state |
CreateNamespace=true | Creates the namespace if it doesn’t exist |
Validate=true | Validates manifests before applying |
ServerSideApply=true | Uses server-side apply for better conflict handling |
retry | Retries up to 5 times if sync fails |
Step 6: Verify the Deployment
If everything went well, ArgoCD will have synced the manifests automatically:
# Check the app status
argocd app get nginx-demo
# Or from kubectl
kubectl get all -n stagingIn the ArgoCD UI (https://localhost:8080) you should see the app with Synced and Healthy status.
Test Self-Heal
Let’s run a test: change something directly in the cluster and watch ArgoCD revert it:
# Scale to 5 replicas manually
kubectl scale deployment nginx-demo -n staging --replicas=5
# Wait a few seconds... ArgoCD detects the drift
kubectl get pods -n staging
# You'll see it goes back to 2 replicas (what Git says)Test Automatic Sync
Now change something in the repository:
- Edit
deployment.yamland changereplicas: 2toreplicas: 3. - Commit and push to
main. - In ~3 minutes (or less), ArgoCD will detect the change and scale to 3 replicas.
# Verify
kubectl get pods -n staging
# You'll now see 3 podsAlternatives to ArgoCD
ArgoCD isn’t the only option for GitOps. Here’s an honest comparison:
ArgoCD vs FluxCD vs Others
| ArgoCD | FluxCD | Rancher Fleet | |
|---|---|---|---|
| Version (2026) | v3.3.5 | v2.8.1 | v0.15.0 |
| CNCF | Graduated | Graduated | N/A (SUSE) |
| Web UI | Built-in and full-featured | No native UI | Via Rancher UI |
| RAM Usage | ~500MB-1GB | ~200-400MB | Lightweight |
| Community | 1,810+ contributors | 178+ contributors | Smaller |
| Multi-cluster | Yes | Yes | Its strength |
| Helm/Kustomize | Yes | Yes | Yes |
| Native SSO | Yes (OIDC, SAML) | No | Via Rancher |
When to Use Each One?
Choose ArgoCD if:
- You want a complete UI to visualize deployment status.
- You need SSO and granular RBAC out-of-the-box.
- Your team prefers a visual and accessible tool.
- You’re integrating with Backstage (there’s an official plugin).
Choose FluxCD if:
- You prefer a CLI-first, pure Kubernetes-native approach.
- Resource consumption is critical (FluxCD uses less RAM).
- You need image automation (automatically update image tags when new versions are released).
- You already use the CNCF/AWS ecosystem for Flux.
Choose Rancher Fleet if:
- You manage many clusters (100+) and need centralized management.
- You already use Rancher as your Kubernetes management platform.
The App of Apps Pattern
When you have more than a couple of services, managing each Application manually becomes tedious. The App of Apps pattern solves this: you create a “parent app” that points to a directory with many “child apps”.
The parent app:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: production-apps
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/my-org/k8s-configs.git
targetRevision: main
path: apps/production
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: trueInside apps/production/ you place the YAML files for each child Application. ArgoCD discovers and manages them automatically. Adding a new service = adding a YAML to the directory, creating a PR, merging, and ArgoCD deploys everything.
Connecting with Backstage
If you followed the previous Backstage Series #2 post, you already have a template that generates manifests and creates PRs. Now you can close the loop:
- A developer fills a form in Backstage → a PR is generated.
- The team reviews and merges.
- ArgoCD detects the change and deploys to the cluster.
- The developer sees the deployment status in the Kubernetes tab in Backstage.
There’s an ArgoCD plugin for Backstage (@roadiehq/backstage-plugin-argo-cd) that adds a card with sync status, health, and deployment history directly on each service’s page.
Summary
| Step | What We Did |
|---|---|
| 1 | Installed ArgoCD on the cluster with official manifests |
| 2 | Installed the CLI (brew install argocd) |
| 3 | Accessed the UI and logged in |
| 4 | Prepared the manifests repository (Deployment + Service + HPA) |
| 5 | Created an Application with auto sync, prune, and self-heal |
| 6 | Verified deployment, self-heal, and automatic sync |