Setting Up ArgoCD with Automated Sync and Rollback
Quick answer
Install ArgoCD on Kubernetes, connect your Git repository, and configure automated sync so every push to main deploys automatically — with one-command rollback when something goes wrong.
- Step 1: Install ArgoCD
- Step 2: Access the ArgoCD UI
- Step 3: Connect Your Git Repository
- Step 4: Create an Application with Automated Sync
- Step 5: Configure a Webhook for Instant Sync
intermediate · 50 min
Before you begin
- A running Kubernetes cluster
- kubectl configured with admin access
- Helm 3 installed
- A Git repository containing Kubernetes manifests or Helm charts
ArgoCD is a GitOps controller that makes your Git repository the source of truth for Kubernetes. Instead of running kubectl apply in a CI pipeline, ArgoCD watches your repo and reconciles the cluster state continuously. Drift gets corrected automatically. Rollback means reverting a Git commit.
This tutorial installs ArgoCD, creates your first Application, enables automated sync, and shows you how rollback actually works.
Step 1: Install ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f \
https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yamlWait for all pods to be ready:
kubectl wait --for=condition=Ready pods --all -n argocd --timeout=120s
kubectl get pods -n argocdExpected output — all pods Running:
NAME READY STATUS
argocd-application-controller-0 1/1 Running
argocd-dex-server-xxx 1/1 Running
argocd-notifications-controller-xxx 1/1 Running
argocd-redis-xxx 1/1 Running
argocd-repo-server-xxx 1/1 Running
argocd-server-xxx 1/1 Running
Step 2: Access the ArgoCD UI
By default, the argocd-server is exposed as ClusterIP. Forward the port locally:
kubectl port-forward svc/argocd-server -n argocd 8080:443Open https://localhost:8080 (accept the self-signed cert warning).
Get the initial admin password:
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d && echoLog in with username admin and the password above. Change it immediately:
# Install the argocd CLI
brew install argocd # macOS; see https://argo-cd.readthedocs.io for other platforms
argocd login localhost:8080 --insecure --username admin
argocd account update-passwordStep 3: Connect Your Git Repository
If your repo is public, skip this step — ArgoCD reads public repos without credentials.
For a private repo:
argocd repo add https://github.com/your-org/your-repo \
--username your-github-username \
--password your-github-patFor SSH:
argocd repo add [email protected]:your-org/your-repo.git \
--ssh-private-key-path ~/.ssh/id_ed25519Verify:
argocd repo listStep 4: Create an Application with Automated Sync
An ArgoCD Application defines what to deploy (source) and where (destination).
1argocd app create my-app \
2 --repo https://github.com/your-org/your-repo \
3 --path k8s/overlays/production \
4 --dest-server https://kubernetes.default.svc \
5 --dest-namespace production \
6 --sync-policy automated \
7 --auto-prune \
8 --self-healWhat each flag does:
--path k8s/overlays/production— directory inside the repo containing your manifests--dest-server https://kubernetes.default.svc— deploy to the same cluster ArgoCD runs in--sync-policy automated— sync whenever the repo changes (polling every 3 minutes, or on webhook push)--auto-prune— delete Kubernetes resources when they're removed from Git--self-heal— revert manualkubectl applychanges that drift from Git
Or declaratively via a YAML manifest (preferred for production):
1# argocd-app.yaml
2apiVersion: argoproj.io/v1alpha1
3kind: Application
4metadata:
5 name: my-app
6 namespace: argocd
7spec:
8 project: default
9 source:
10 repoURL: https://github.com/your-org/your-repo
11 targetRevision: main
12 path: k8s/overlays/production
13 destination:
14 server: https://kubernetes.default.svc
15 namespace: production
16 syncPolicy:
17 automated:
18 prune: true
19 selfHeal: true
20 syncOptions:
21 - CreateNamespace=true
22 retry:
23 limit: 3
24 backoff:
25 duration: 5s
26 factor: 2
27 maxDuration: 3mkubectl apply -f argocd-app.yamlStep 5: Configure a Webhook for Instant Sync
By default, ArgoCD polls Git every 3 minutes. Configure a webhook for immediate sync on push.
In your GitHub repo → Settings → Webhooks → Add webhook:
- Payload URL:
https://your-argocd-domain/api/webhook - Content type:
application/json - Secret: generate with
openssl rand -hex 32and store it with thekubectl patchcommand below - Events: Just the push event
Or generate a shared secret and store it:
kubectl -n argocd patch secret argocd-secret \
--type='merge' \
-p='{"stringData":{"webhook.github.secret":"your-webhook-secret"}}'Step 6: Verify Sync Status
After committing a change to your repo:
1# Check sync status
2argocd app get my-app
3
4# Watch it sync
5argocd app wait my-app --health
6
7# See what changed
8argocd app diff my-appThe UI (localhost:8080) shows a visual dependency graph — green circles are healthy, yellow is progressing, red means something's wrong.
Step 7: Rollback to a Previous Version
When a deployment goes bad, rollback is a Git revert followed by a push. ArgoCD handles the rest.
# See sync history
argocd app history my-app
# ID DATE REVISION
# 0 2026-04-22 10:00:00 +0000 UTC main (abc1234)
# 1 2026-04-22 11:00:00 +0000 UTC main (def5678) ← broken deployOption 1: Git revert (preferred — keeps history):
git revert HEAD --no-edit
git push origin main
# ArgoCD auto-syncs to the reverted stateOption 2: ArgoCD rollback to a specific history entry (bypasses Git — use only in emergencies):
Note: argocd app rollback cannot be used while automated sync is enabled — ArgoCD will refuse the command. Disable automated sync first, then roll back:
argocd app set my-app --sync-policy none
argocd app rollback my-app 0This deploys revision 0 without changing Git. After the emergency is resolved, re-enable automated sync:
argocd app set my-app --sync-policy automated --auto-prune --self-healArgoCD will show the app as OutOfSync until the next auto-sync runs.
Step 8: Application Health Checks
ArgoCD understands Kubernetes resource health natively. A Deployment is Healthy when its rollout is complete. A Pod is Degraded when it's in CrashLoopBackOff.
For custom health checks, add a ConfigMap to argocd-cm:
1apiVersion: v1
2kind: ConfigMap
3metadata:
4 name: argocd-cm
5 namespace: argocd
6data:
7 resource.customizations.health.my.io_MyResource: |
8 hs = {}
9 if obj.status ~= nil then
10 if obj.status.phase == "Ready" then
11 hs.status = "Healthy"
12 hs.message = "Resource is ready"
13 return hs
14 end
15 end
16 hs.status = "Progressing"
17 hs.message = "Waiting for resource to be ready"
18 return hsStep 9: Multi-Environment Setup
For separate dev, staging, and production apps pointing to the same repo but different paths:
1argocd app create my-app-dev \
2 --repo https://github.com/your-org/your-repo \
3 --path k8s/overlays/dev \
4 --dest-server https://kubernetes.default.svc \
5 --dest-namespace dev \
6 --sync-policy automated \
7 --auto-prune \
8 --self-heal
9
10argocd app create my-app-staging \
11 --repo https://github.com/your-org/your-repo \
12 --path k8s/overlays/staging \
13 --dest-server https://kubernetes.default.svc \
14 --dest-namespace staging \
15 --sync-policy automated \
16 --auto-prune \
17 --self-healProduction typically has no --sync-policy flag (manual sync only) and requires explicit approval via the UI or argocd app sync my-app-prod.
Common Issues
App stuck in OutOfSync: Run argocd app diff my-app to see what's different. Often caused by resources that get mutated by admission webhooks (like injected sidecars or annotations). Use ignoreDifferences in the Application spec to ignore these fields.
Sync loop with self-heal: If the cluster keeps drifting back to a different state, something outside ArgoCD is modifying resources. Find the culprit with kubectl get events -n production.
Prune deletes unexpected resources: ArgoCD prunes resources it created but are no longer in Git. If you deployed something manually with kubectl apply, ArgoCD doesn't own it and won't prune it. Add app.kubernetes.io/instance: my-app labels to adopt resources into the ArgoCD application.
Frequently Asked Questions
What is the difference between automated sync and self-heal?
Automated sync applies changes when the Git repository moves ahead. Self-heal additionally reverts changes made directly in the cluster, so a manual kubectl edit is undone at the next reconcile. Enable self-heal when Git must be the only source of truth; leave it off if operators legitimately patch resources by hand during incidents.
Why does my application show OutOfSync when nothing changed?
Usually a controller or admission webhook mutating the resource after it is applied — an injected sidecar, a defaulted field, or a mutating policy. Argo CD compares the live object against Git and reports the difference honestly. Use ignoreDifferences for fields you expect something else to own, rather than disabling the comparison.
Do I need a webhook, or is polling enough?
Polling works and defaults to a few minutes, which is fine for most teams. A webhook makes sync near-instant, which matters when deploys are frequent enough that waiting is noticeable. The webhook is an optimisation, not a requirement, and polling remains the fallback if it fails.
How does rollback work if Git is the source of truth?
Argo CD blocks rollback entirely while automated sync is enabled — the operation is rejected, because the controller would immediately re-sync to Git anyway. The durable rollback is therefore a Git revert, which is also auditable. If you must roll back from the UI during an incident, disable automated sync first, roll back, then revert in Git and re-enable it.
Official References
- Argo CD Documentation — Official docs: installation, Applications, sync policies, RBAC, SSO, and notifications
- Argo CD Application Spec — Full reference for the Application CRD including syncPolicy, retry, and prune settings
- Automated Sync Policy — Official guide to automated sync, self-heal, and prune behaviour
- Argo CD Notifications — How to send Slack/email/webhook alerts on sync success, failure, or health changes
- App of Apps Pattern — Managing multiple Applications with a parent Application for cluster bootstrapping
Next in GitOps with ArgoCD
ArgoCD App-of-Apps: Managing Multi-Environment Clusters
We built Podscape to simplify Kubernetes workflows like this — logs, events, and cluster state in one interface, without switching tools.
Struggling with this in production?
We help teams fix these exact issues. Our engineers have deployed these patterns across production environments at scale.