Getting Started with ArgoCD: GitOps in 30 Minutes
Install ArgoCD, connect a Git repository, and deploy your first application using GitOps principles. Covers the ArgoCD UI, CLI, sync policies, and the difference between automated and manual syncing.
Before you begin
- kubectl installed and configured
- Access to a running Kubernetes cluster
- A GitHub repository with Kubernetes manifests (or Helm chart)
GitOps means your cluster state is always derived from Git. Every deployment, every config change, every rollback flows through a pull request and a Git commit. ArgoCD is the controller that makes this real: it watches your repository and continuously reconciles the cluster to match.
This beats kubectl apply in CI pipelines for one reason: Git becomes the authoritative source of truth. You can audit every change via git log, roll back with git revert, and know exactly what's running in production at any point in time.
What You'll Build
ArgoCD installed in its own namespace, connected to a GitHub repository containing a simple nginx Deployment and Service, automatically deployed to a staging namespace. You'll trigger a change, watch ArgoCD pick it up, and use both the UI and the argocd CLI.
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 the pods to be ready:
kubectl wait --for=condition=ready pod \
-l app.kubernetes.io/name=argocd-server \
-n argocd \
--timeout=120s
# pod/argocd-server-7d8f6b-xyz condition metVerify everything is running:
1kubectl get pods -n argocd
2# NAME READY STATUS RESTARTS
3# argocd-application-controller-0 1/1 Running 0
4# argocd-applicationset-controller-... 1/1 Running 0
5# argocd-dex-server-... 1/1 Running 0
6# argocd-redis-... 1/1 Running 0
7# argocd-repo-server-... 1/1 Running 0
8# argocd-server-... 1/1 Running 0Step 2: Access the ArgoCD UI
Port-forward the ArgoCD server to your local machine:
kubectl port-forward svc/argocd-server -n argocd 8090:443Get the initial admin password (auto-generated on install):
1# Recommended (requires the argocd CLI):
2argocd admin initial-password -n argocd
3
4# Alternative using kubectl directly:
5kubectl -n argocd get secret argocd-initial-admin-secret \
6 -o jsonpath="{.data.password}" | base64 -d; echo
7# outputs something like: Kx9mR7vN2pQ4wL8yOpen https://localhost:8090 in your browser. Accept the self-signed certificate warning and log in with username admin and the password above.
Step 3: Install the ArgoCD CLI
The CLI is more convenient than the UI for scripting and auditing.
macOS:
brew install argocdLinux:
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-amd64Log in:
1argocd login localhost:8090 \
2 --username admin \
3 --password <your-password> \
4 --insecure # skips TLS verification for localhost
5
6argocd version
7# argocd: v2.x.x
8# server: v2.x.xStep 4: Prepare Your Git Repository
Your repo needs to contain Kubernetes manifests. Create a minimal structure if you don't have one:
manifests/
└── nginx/
├── deployment.yaml
└── service.yaml
manifests/nginx/deployment.yaml:
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4 name: nginx
5 namespace: staging
6spec:
7 replicas: 2
8 selector:
9 matchLabels:
10 app: nginx
11 template:
12 metadata:
13 labels:
14 app: nginx
15 spec:
16 containers:
17 - name: nginx
18 image: nginx:1.25.0
19 ports:
20 - containerPort: 80manifests/nginx/service.yaml:
1apiVersion: v1
2kind: Service
3metadata:
4 name: nginx
5 namespace: staging
6spec:
7 selector:
8 app: nginx
9 ports:
10 - port: 80
11 targetPort: 80Commit and push these files to your repo's main branch.
Step 5: Create Your First ArgoCD Application
Create the staging namespace:
kubectl create namespace stagingNow create an ArgoCD Application pointing at your repo:
1argocd app create nginx-staging \
2 --repo https://github.com/<your-org>/<your-repo> \
3 --path manifests/nginx \
4 --dest-server https://kubernetes.default.svc \
5 --dest-namespace staging \
6 --sync-policy automated \
7 --auto-prune \
8 --self-healWhat each flag does:
--repo: the Git repository URL--path: the subdirectory within the repo to watch--dest-server: the Kubernetes API server (https://kubernetes.default.svc= the same cluster ArgoCD is installed on)--dest-namespace: the namespace to deploy into--sync-policy automated: ArgoCD syncs automatically when Git changes, no manual trigger needed--auto-prune: resources deleted from Git are deleted from the cluster--self-heal: if someone applies a manual change to the cluster, ArgoCD reverts it to match Git
Check the app status:
1argocd app get nginx-staging
2# Name: argocd/nginx-staging
3# Project: default
4# Server: https://kubernetes.default.svc
5# Namespace: staging
6# URL: https://localhost:8090/applications/nginx-staging
7# Source: ...
8# Sync Policy: Automated
9# Sync Status: Synced to main (abc1234)
10# Health Status: Healthy
11#
12# RESOURCE SYNC STATUS HEALTH STATUS
13# Namespace/staging Synced Healthy
14# apps/Deployment/nginx Synced Healthy
15# /Service/nginx Synced HealthyVerify the pods came up:
kubectl get pods -n staging
# NAME READY STATUS RESTARTS
# nginx-7d8f9b-abc 1/1 Running 0
# nginx-7d8f9b-def 1/1 Running 0Step 6: Understand Sync Policies
ArgoCD has three sync modes:
| Mode | CLI flag | Behavior |
|---|---|---|
| Manual | (default, no flag) | Shows OutOfSync but never acts. You run argocd app sync manually. |
| Automated | --sync-policy automated | Syncs within ~3 minutes of a Git push. |
| Automated + self-heal | --sync-policy automated --self-heal | Also reverts manual kubectl changes. |
For production deployments, most teams use manual sync (or automated on dev/staging, manual on prod) so that merging to the prod branch requires an explicit sync approval step.
Change the policy to manual if you want explicit control:
argocd app set nginx-staging --sync-policy noneBack to automated:
argocd app set nginx-staging --sync-policy automated --auto-prune --self-healStep 7: Trigger a Change and Watch It Deploy
Update the image tag in your Git repo:
# manifests/nginx/deployment.yaml — change image to:
image: nginx:1.26.0Commit and push:
git add manifests/nginx/deployment.yaml
git commit -m "chore: bump nginx to 1.26.0"
git pushArgoCD polls Git every 3 minutes by default, or you can trigger an immediate sync:
argocd app sync nginx-stagingAvoid --force unless you intend a destructive sync: it causes ArgoCD to use kubectl replace instead of kubectl apply, which tears down and recreates resources rather than patching them in place.
Watch the rollout:
1argocd app wait nginx-staging --operation
2# Waiting for app nginx-staging to finish syncing...
3# App 'nginx-staging' successfully synced
4
5argocd app history nginx-staging
6# ID DATE REVISION
7# 0 2026-05-20 10:00:00 +0000 UTC abc1234 (main)
8# 1 2026-05-20 10:05:00 +0000 UTC def5678 (main)Step 8: Monitor App Health
1# List all apps with health and sync status
2argocd app list
3# NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS
4# nginx-staging in-cluster staging default Synced Healthy Auto <none>
5
6# Detailed status with resource tree
7argocd app get nginx-staging
8
9# See what changed in the cluster
10kubectl get events -n staging --sort-by='.lastTimestamp'In the UI (https://localhost:8090), the app graph shows every resource with its sync status and health — useful for diagnosing partial failures where the sync succeeds but a deployment's pods are crashing.
Common Mistakes to Avoid
Not setting --dest-namespace — omitting it deploys resources to the default namespace, overriding any namespace: fields in your manifests. Always set it explicitly.
Leaving --sync-policy unset on dev/staging — the app shows OutOfSync forever but never catches up. Either commit to manual syncing (and run argocd app sync in your CI pipeline after merge) or enable automated sync.
Connecting to a monorepo without --path — ArgoCD will try to apply everything it finds in the repository root, including Helm charts, README files, and CI config. Always set --path to the relevant subdirectory.
Using HTTPS without adding credentials — for private repos, run argocd repo add https://github.com/your-org/your-repo --username <token> --password <token> before creating the app. ArgoCD stores credentials encrypted in Kubernetes secrets.
Expecting immediate sync — automated sync polls every 3 minutes. If you need immediate sync after a push, either call argocd app sync from your CI pipeline or configure a webhook (Settings → Repositories → add webhook URL from ArgoCD).
Cleanup
argocd app delete nginx-staging --cascade # deletes the app and all its resources
kubectl delete namespace argocd stagingWhat's Next
- ArgoCD App-of-Apps Pattern — manage dozens of applications across multiple environments from a single root Application
Official References
- ArgoCD Getting Started — official quick-start guide
- ArgoCD Application CRD — full spec for the Application resource (the YAML equivalent of what
argocd app creategenerates) - ArgoCD Sync Policies — automated sync, prune, self-heal, and sync windows
- Private Repositories — connecting ArgoCD to private GitHub, GitLab, or Bitbucket repos
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.