Skip to content

intermediate ~90 min updated 2026-06-01

Argo CD GitOps Deployment

Install Argo CD on a kind cluster, connect it to a Git repository, and deploy an app declaratively with an Application manifest. Watch automated sync repair drift in real time.

Objective

Deploy an application via Argo CD from a Git repository with automated sync and self-healing enabled, then observe drift correction. The Git repo becomes the single source of truth: any manual change in the cluster is reverted, and any commit is rolled out automatically.

Prerequisites

  • Docker installed and running
  • kind and kubectl installed
  • A free GitHub account
  • Git installed and configured with push access
  • Comfort with basic kubectl commands

Architecture

Argo CD runs inside the cluster and continuously compares the live state against manifests stored in your GitHub repo. An Application custom resource tells Argo CD which repo path to watch and which namespace to deploy into. With automated sync plus self-heal, the reconciliation loop pushes the cluster back to the Git-declared state.

 GitHub repo (manifests/)              kind cluster
+------------------------+   poll    +---------------------------+
| deployment.yaml        | <-------- | argocd namespace          |
| service.yaml           |           |  repo-server / controller |
+------------------------+           |  api-server / redis       |
        ^                            +------------+--------------+
        | git push                                | apply & heal
   you commit changes                +------------v--------------+
                                     | guestbook namespace       |
                                     |  Deployment + Service     |
                                     +---------------------------+

Steps

1. Create the cluster and install Argo CD

kind create cluster --name argocd-lab
kubectl create namespace argocd
kubectl apply -n argocd -f \
  https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
kubectl wait --for=condition=available deployment/argocd-server \
  -n argocd --timeout=300s

2. Get the admin password and open the UI

kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath='{.data.password}' | base64 -d; echo
kubectl port-forward svc/argocd-server -n argocd 8080:443 &

Browse to https://localhost:8080 (accept the self-signed cert) and log in as admin.

3. Create the Git repository with manifests

mkdir gitops-demo && cd gitops-demo && git init -b main
mkdir manifests
# manifests/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: guestbook
spec:
  replicas: 2
  selector:
    matchLabels:
      app: guestbook
  template:
    metadata:
      labels:
        app: guestbook
    spec:
      containers:
        - name: guestbook
          image: ghcr.io/argoproj/argocd-example-apps/guestbook-ui:latest
          ports:
            - containerPort: 80
# manifests/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: guestbook
spec:
  selector:
    app: guestbook
  ports:
    - port: 80
      targetPort: 80
git add -A && git commit -m "Initial guestbook manifests"
gh repo create gitops-demo --public --source=. --push

4. Create the Argo CD Application

# app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/YOUR_USER/gitops-demo.git
    targetRevision: main
    path: manifests
  destination:
    server: https://kubernetes.default.svc
    namespace: guestbook
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
kubectl apply -f app.yaml
kubectl get applications -n argocd -w

5. Test self-healing (drift correction)

Manually scale the deployment and watch Argo CD revert it:

kubectl scale deployment guestbook -n guestbook --replicas=5
sleep 20
kubectl get deployment guestbook -n guestbook

6. Deploy a change through Git

sed -i 's/replicas: 2/replicas: 3/' manifests/deployment.yaml
git commit -am "Scale guestbook to 3 replicas"
git push
# Within ~3 minutes (default poll interval) the cluster converges:
kubectl get deployment guestbook -n guestbook -w

Expected output

$ kubectl get applications -n argocd
NAME        SYNC STATUS   HEALTH STATUS
guestbook   Synced        Healthy

$ kubectl scale deployment guestbook -n guestbook --replicas=5
deployment.apps/guestbook scaled
$ sleep 20 && kubectl get deployment guestbook -n guestbook
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
guestbook   2/2     2            2           6m   <- self-heal reverted drift

$ kubectl get deployment guestbook -n guestbook   # after the git push
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
guestbook   3/3     3            3           9m

Troubleshooting

  • Application stuck in Unknown / ComparisonError: Argo CD cannot reach the repo. For private repos add credentials with argocd repo add or a repository Secret; for public repos verify the repoURL has no typo.
  • OutOfSync but auto-sync never runs: the syncPolicy.automated block is missing or misindented in app.yaml. Re-apply and check kubectl describe application guestbook -n argocd.
  • Pods ImagePullBackOff in guestbook namespace: the kind node cannot pull from ghcr.io. Test with docker pull ghcr.io/argoproj/argocd-example-apps/guestbook-ui:latest and check your network/proxy.
  • Port-forward to the UI drops immediately: argocd-server is not Ready yet. Run kubectl get pods -n argocd and wait for all pods Running before forwarding.
  • Self-heal does not revert your manual change: self-heal triggers on the next reconciliation (up to a few seconds for live resources, but app refresh is every 3 minutes). Force it with a UI Refresh or kubectl annotate application guestbook -n argocd argocd.argoproj.io/refresh=normal.

Cleanup

kubectl delete -f app.yaml
kubectl delete namespace guestbook --ignore-not-found
kubectl delete namespace argocd
kill %1 2>/dev/null || true
kind delete cluster --name argocd-lab
gh repo delete YOUR_USER/gitops-demo --yes
cd .. && rm -rf gitops-demo