Kubernetes

Getting Started with ArgoCD: GitOps in 30 Minutes

Intermediate35 min to complete12 min read

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)
Kubernetes
ArgoCD
GitOps
Helm
CD
DevOps

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

bash
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

Wait for the pods to be ready:

bash
kubectl wait --for=condition=ready pod \
  -l app.kubernetes.io/name=argocd-server \
  -n argocd \
  --timeout=120s
# pod/argocd-server-7d8f6b-xyz condition met

Verify everything is running:

bash
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   0

Step 2: Access the ArgoCD UI

Port-forward the ArgoCD server to your local machine:

bash
kubectl port-forward svc/argocd-server -n argocd 8090:443

Get the initial admin password (auto-generated on install):

bash
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: Kx9mR7vN2pQ4wL8y

Open 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:

bash
brew install argocd

Linux:

bash
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

Log in:

bash
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.x

Step 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:

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: 80

manifests/nginx/service.yaml:

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: 80

Commit and push these files to your repo's main branch.

Step 5: Create Your First ArgoCD Application

Create the staging namespace:

bash
kubectl create namespace staging

Now create an ArgoCD Application pointing at your repo:

bash
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-heal

What 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:

bash
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        Healthy

Verify the pods came up:

bash
kubectl get pods -n staging
# NAME                     READY   STATUS    RESTARTS
# nginx-7d8f9b-abc         1/1     Running   0
# nginx-7d8f9b-def         1/1     Running   0

Step 6: Understand Sync Policies

ArgoCD has three sync modes:

ModeCLI flagBehavior
Manual(default, no flag)Shows OutOfSync but never acts. You run argocd app sync manually.
Automated--sync-policy automatedSyncs within ~3 minutes of a Git push.
Automated + self-heal--sync-policy automated --self-healAlso 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:

bash
argocd app set nginx-staging --sync-policy none

Back to automated:

bash
argocd app set nginx-staging --sync-policy automated --auto-prune --self-heal

Step 7: Trigger a Change and Watch It Deploy

Update the image tag in your Git repo:

yaml
# manifests/nginx/deployment.yaml — change image to:
image: nginx:1.26.0

Commit and push:

bash
git add manifests/nginx/deployment.yaml
git commit -m "chore: bump nginx to 1.26.0"
git push

ArgoCD polls Git every 3 minutes by default, or you can trigger an immediate sync:

bash
argocd app sync nginx-staging

Avoid --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:

bash
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

bash
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

bash
argocd app delete nginx-staging --cascade   # deletes the app and all its resources
kubectl delete namespace argocd staging

What's Next

Official References

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.