
ArgoCD is the most widely used GitOps tool for Kubernetes. It watches your Git repository and automatically keeps your cluster in sync with whatever you define in code. Push a change to Git — ArgoCD detects it and applies it to the cluster. No manual kubectl apply in production.
This guide covers the complete setup — from installing ArgoCD on your cluster to deploying your first application the GitOps way.
What You’ll Need
- A running Kubernetes cluster (any cloud provider or local setup)
kubectlconfigured with cluster admin accessgitinstalled on your machine- A GitHub account (or any Git provider)
- About 30 minutes
How ArgoCD Works
Before installing, it helps to understand what ArgoCD actually does.
ArgoCD runs inside your Kubernetes cluster as a set of services:
- API server — handles all requests from the UI and CLI
- Repo server — clones your Git repositories and processes manifests
- Application controller — compares what is in Git with what is running in the cluster and reconciles differences
- Redis — caching layer
- Dex — optional SSO integration
The flow is simple:
Git repository → ArgoCD repo server → Application controller → Kubernetes cluster
You define the desired state in Git. ArgoCD continuously compares that with the live state. If they differ, ArgoCD syncs the cluster back to what Git says it should be. This also means if someone manually changes something in the cluster with kubectl, ArgoCD will revert it — which is the point.
Step 1 — Install ArgoCD
Create a dedicated namespace and install ArgoCD using the official manifests.
kubectl create namespace argocd
kubectl apply -n argocd \
--server-side \
--force-conflicts \
-f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Why --server-side and --force-conflicts?
Some ArgoCD CRDs (like ApplicationSet) exceed the 262KB annotation size limit imposed by standard kubectl apply. Server-side apply avoids this by not storing the last-applied-configuration annotation. This is now required for production installs.
Wait for all pods to be ready:
kubectl wait --for=condition=ready pod \
-l app.kubernetes.io/name=argocd-server \
-n argocd \
--timeout=300s
Verify everything is running:
kubectl get pods -n argocd
You should see output similar to:
NAME READY STATUS RESTARTS AGE
argocd-application-controller-0 1/1 Running 0 2m
argocd-applicationset-controller-xxx 1/1 Running 0 2m
argocd-dex-server-xxx 1/1 Running 0 2m
argocd-notifications-controller-xxx 1/1 Running 0 2m
argocd-redis-xxx 1/1 Running 0 2m
argocd-repo-server-xxx 1/1 Running 0 2m
argocd-server-xxx 1/1 Running 0 2m
Step 2 — Install the ArgoCD CLI
The CLI is useful for scripting, automation, and managing ArgoCD from the terminal.
macOS:
brew install argocd
Linux (amd64):
curl -sSL -o argocd-linux-amd64 \
https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
rm argocd-linux-amd64
Verify installation:
argocd version --client
Step 3 — Access the ArgoCD UI
By default, ArgoCD is not exposed outside the cluster. For local access, use port forwarding.
kubectl port-forward svc/argocd-server -n argocd 8080:443
Open https://localhost:8080 in your browser. You will see a certificate warning — this is expected with the default self-signed certificate. Proceed past it.
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 - Password: output from the command above
⚠️ Important: Change the password immediately after first login. The
argocd-initial-admin-secretis auto-deleted after first login in newer ArgoCD versions — save the password before that happens.
Change your password:
argocd login localhost:8080 --insecure
argocd account update-password
Step 4 — Expose ArgoCD for Production (Optional)
Port forwarding is fine for testing. For production, set up an Ingress.
Using NGINX Ingress Controller:
# argocd-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server-ingress
namespace: argocd
annotations:
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
ingressClassName: nginx
rules:
- host: argocd.yourdomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
number: 443
tls:
- hosts:
- argocd.yourdomain.com
secretName: argocd-tls
Apply it:
kubectl apply -f argocd-ingress.yaml
Replace argocd.yourdomain.com with your actual domain. You will need a TLS certificate — use cert-manager with Let’s Encrypt for automatic certificate management.
Alternatively, expose ArgoCD via a LoadBalancer:
kubectl patch svc argocd-server -n argocd \
-p '{"spec": {"type": "LoadBalancer"}}'
Step 5 — Connect Your Git Repository
Log in to ArgoCD CLI:
argocd login localhost:8080 --insecure
For public repositories: No credentials needed — ArgoCD can clone public repos without authentication.
For private repositories: Add credentials using HTTPS or SSH.
HTTPS (username/password or token):
argocd repo add https://github.com/your-org/your-repo.git \
--username your-github-username \
--password your-github-token
SSH:
argocd repo add git@github.com:your-org/your-repo.git \
--ssh-private-key-path ~/.ssh/id_rsa
Verify the repo is connected:
argocd repo list
Step 6 — Deploy Your First Application
Now the important part — deploying an application the GitOps way.
First, create a simple Kubernetes manifest in your Git repository. Create a file at manifests/deployment.yaml:
# manifests/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: default
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: ClusterIP
Push this to your Git repository. Then create an ArgoCD Application pointing to it.
Option A — Using the CLI:
argocd app create nginx-app \
--repo https://github.com/your-org/your-repo.git \
--path manifests \
--dest-server https://kubernetes.default.svc \
--dest-namespace default \
--sync-policy automated \
--auto-prune \
--self-heal
Option B — Using a YAML manifest (recommended for GitOps):
# argocd-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nginx-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/your-repo.git
targetRevision: main
path: manifests
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Apply it:
kubectl apply -f argocd-app.yaml
Check the application status:
argocd app get nginx-app
You should see:
Name: argocd/nginx-app
Project: default
Server: https://kubernetes.default.svc
Namespace: default
URL: https://localhost:8080/applications/nginx-app
Repo: https://github.com/your-org/your-repo.git
Target: main
Path: manifests
SyncStatus: Synced to main
HealthStatus: Healthy
Now open the ArgoCD UI. You will see a visual tree of all deployed resources — the Deployment, the ReplicaSet, the Pods, and the Service — along with their sync and health status.
Step 7 — Test GitOps in Action
This is where it gets interesting. Make a change to your manifest in Git and watch ArgoCD apply it automatically.
Update the replica count in manifests/deployment.yaml:
spec:
replicas: 3 # Changed from 2 to 3
Commit and push to your repository:
git add manifests/deployment.yaml
git commit -m "Scale nginx to 3 replicas"
git push origin main
ArgoCD polls the repository every 3 minutes by default. Within 3 minutes, it will detect the change and scale your deployment to 3 replicas automatically.
You can also trigger a manual sync immediately:
argocd app sync nginx-app
Watch the rollout:
kubectl get pods -n default -w
You will see a third pod come up. No kubectl apply. No manual intervention. The change went through Git.
Step 8 — Set Up Webhooks for Instant Sync
The default 3-minute polling delay is not ideal for fast deployments. Set up a webhook so ArgoCD syncs immediately when you push to Git.
In your GitHub repository:
- Go to Settings → Webhooks → Add webhook
- Payload URL:
https://argocd.yourdomain.com/api/webhook - Content type:
application/json - Events: Select “Just the push event”
- Click Add webhook
Now every git push triggers an immediate sync — no waiting for the polling interval.
Step 9 — Install ArgoCD with Helm (Production Method)
For production environments, Helm is the recommended installation method. It gives you more control over configuration.
Add the ArgoCD Helm repository:
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
Install ArgoCD:
helm install argocd argo/argo-cd \
--namespace argocd \
--create-namespace \
--set server.ingress.enabled=true \
--set server.ingress.hostname=argocd.yourdomain.com
Check the values file for all available configuration options:
helm show values argo/argo-cd > argocd-values.yaml
Edit argocd-values.yaml to customise your installation, then apply:
helm upgrade argocd argo/argo-cd \
--namespace argocd \
-f argocd-values.yaml
Useful ArgoCD Commands
# List all applications
argocd app list
# Get application details
argocd app get nginx-app
# Sync an application manually
argocd app sync nginx-app
# Rollback to a previous version
argocd app rollback nginx-app 1
# Delete an application
argocd app delete nginx-app
# List registered clusters
argocd cluster list
# List connected repositories
argocd repo list
# Check ArgoCD server version
argocd version
Common Issues and Fixes
| Issue | Fix |
|---|---|
argocd-initial-admin-secret not found | Secret is auto-deleted after first login. Reset password: argocd admin initial-password -n argocd |
| Application stuck in OutOfSync | Check repo credentials: argocd repo list. Check app events: argocd app get <name> |
| Sync failed with permission error | Check RBAC — the ArgoCD service account may not have access to the target namespace |
| Pods not coming up after sync | Check pod events: kubectl describe pod <pod-name> -n <namespace> |
| Webhook not triggering sync | Verify webhook payload URL is correct and ArgoCD server is publicly accessible |
| Port-forward keeps disconnecting | Add & to run in background or use a proper Ingress for persistent access |
Production Checklist
Before running ArgoCD in production, check these:
- Change the default admin password
- Set up SSO (Dex with GitHub, Google, or LDAP) instead of using the admin account
- Enable High Availability installation for the ArgoCD components
- Set up Ingress with a valid TLS certificate
- Configure RBAC — give each team access only to their own applications
- Set up Prometheus metrics scraping for ArgoCD
- Use pinned versions in Application manifests (
targetRevision: v2.3.1notmain) for production apps - Enable
prune: trueandselfHeal: trueon all production Applications - Back up your ArgoCD configuration — all data is stored in Kubernetes etcd
Next Steps
Now that ArgoCD is running, here is what to explore next:
- App of Apps pattern — manage multiple applications as a single ArgoCD Application
- ApplicationSets — deploy the same application across multiple clusters with a template
- Sync waves — control the order in which resources are applied
- Sealed Secrets or External Secrets — manage secrets securely in Git
- Argo Rollouts — progressive delivery with canary and blue-green deployments