Contents

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 log is your deployment history.
  • Instant rollback: if something breaks, git revert and 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:

ToolVersionNotes
OrbStack (macOS) or Docker Desktop (Windows/Linux)Container runtime
Kindv0.20+Local Kubernetes cluster
kubectlv1.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-cluster

Windows (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-cluster

Linux

# 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-cluster

Step 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 argocd

Verify all pods are running:

kubectl get pods -n argocd
NAME                                  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          60s
About the Installation
We use the official manifests because it’s the most direct and supported approach. You can also install with Helm (helm 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 argocd

Linux

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-cli

Verify the installation:

argocd version --client

Step 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:443

Now 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 --decode

The 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_pass
Security

In production, change the admin password immediately and delete the initial secret:

argocd account update-password
kubectl -n argocd delete secret argocd-initial-admin-secret

Step 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.yaml

Create 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-demo

apps/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: 50

Don’t forget to create the namespace:

kubectl create namespace staging

Step 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-heal
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: 3m
kubectl apply -f application.yaml

What Do These Options Mean?

OptionWhat it does
automatedAutomatically syncs when it detects changes in Git
prune: trueIf you delete a file from Git, deletes the resource from the cluster
selfHeal: trueIf someone changes something with kubectl, reverts it to Git state
CreateNamespace=trueCreates the namespace if it doesn’t exist
Validate=trueValidates manifests before applying
ServerSideApply=trueUses server-side apply for better conflict handling
retryRetries 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 staging

In 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:

  1. Edit deployment.yaml and change replicas: 2 to replicas: 3.
  2. Commit and push to main.
  3. 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 pods

Alternatives to ArgoCD

ArgoCD isn’t the only option for GitOps. Here’s an honest comparison:

ArgoCD vs FluxCD vs Others

ArgoCDFluxCDRancher Fleet
Version (2026)v3.3.5v2.8.1v0.15.0
CNCFGraduatedGraduatedN/A (SUSE)
Web UIBuilt-in and full-featuredNo native UIVia Rancher UI
RAM Usage~500MB-1GB~200-400MBLightweight
Community1,810+ contributors178+ contributorsSmaller
Multi-clusterYesYesIts strength
Helm/KustomizeYesYesYes
Native SSOYes (OIDC, SAML)NoVia 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.
My Recommendation
For most teams starting with GitOps, ArgoCD is the best choice. The UI is a game-changer for adoption: it lets developers and managers see deployment status without touching the terminal. FluxCD is excellent if your team is 100% CLI and already mature in Kubernetes.

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: true

Inside 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:

  1. A developer fills a form in Backstage → a PR is generated.
  2. The team reviews and merges.
  3. ArgoCD detects the change and deploys to the cluster.
  4. 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

StepWhat We Did
1Installed ArgoCD on the cluster with official manifests
2Installed the CLI (brew install argocd)
3Accessed the UI and logged in
4Prepared the manifests repository (Deployment + Service + HPA)
5Created an Application with auto sync, prune, and self-heal
6Verified deployment, self-heal, and automatic sync

Resources