Setting Up ArgoCD with Automated Sync and Rollback
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.
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.yaml
Wait for all pods to be ready:
kubectl wait --for=condition=Ready pods --all -n argocd --timeout=120s
kubectl get pods -n argocd
Expected 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:443
Open 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 && echo
Log 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-password
Step 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-pat
For SSH:
argocd repo add git@github.com:your-org/your-repo.git \
--ssh-private-key-path ~/.ssh/id_ed25519
Verify:
argocd repo list
Step 4: Create an Application with Automated Sync
An ArgoCD Application defines what to deploy (source) and where (destination).
argocd app create my-app \
--repo https://github.com/your-org/your-repo \
--path k8s/overlays/production \
--dest-server https://kubernetes.default.svc \
--dest-namespace production \
--sync-policy automated \
--auto-prune \
--self-heal
What 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):
# argocd-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/your-repo
targetRevision: main
path: k8s/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
retry:
limit: 3
backoff:
duration: 5s
factor: 2
maxDuration: 3m
kubectl apply -f argocd-app.yaml
Step 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 set as theARGOCD_WEBHOOK_SECRETenvironment variable in argocd-server - 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:
# Check sync status
argocd app get my-app
# Watch it sync
argocd app wait my-app --sync --health
# See what changed
argocd app diff my-app
The 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 deploy
Option 1: Git revert (preferred — keeps history):
git revert HEAD --no-edit
git push origin main
# ArgoCD auto-syncs to the reverted state
Option 2: ArgoCD rollback to a specific history entry (bypasses Git — use only in emergencies):
argocd app rollback my-app 0
This deploys revision 0 without changing Git. ArgoCD will show the app as OutOfSync because the cluster no longer matches the repo HEAD. Fix by doing a proper Git revert and re-syncing.
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:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
resource.customizations.health.my.io_MyResource: |
hs = {}
if obj.status ~= nil then
if obj.status.phase == "Ready" then
hs.status = "Healthy"
hs.message = "Resource is ready"
return hs
end
end
hs.status = "Progressing"
hs.message = "Waiting for resource to be ready"
return hs
Step 9: Multi-Environment Setup
For separate dev, staging, and production apps pointing to the same repo but different paths:
argocd app create my-app-dev \
--repo https://github.com/your-org/your-repo \
--path k8s/overlays/dev \
--dest-server https://kubernetes.default.svc \
--dest-namespace dev \
--sync-policy automated \
--auto-prune \
--self-heal
argocd app create my-app-staging \
--repo https://github.com/your-org/your-repo \
--path k8s/overlays/staging \
--dest-server https://kubernetes.default.svc \
--dest-namespace staging \
--sync-policy automated \
--auto-prune \
--self-heal
Production typically has --sync-policy none and requires manual 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/managed-by: argocd labels to adopt resources.
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.