ArgoCD is a declarative, GitOps-based continuous delivery tool for Kubernetes that keeps your cluster state permanently synchronized with configurations stored in Git. If you have ever spent time manually running kubectl apply after every code change or chased down configuration drift between environments, ArgoCD solves this by making Git the single source of truth for every deployed resource. This guide walks you through installing ArgoCD, connecting repositories, creating Application resources, and configuring sync policies for production-grade deployments.
Prerequisites
- A running Kubernetes cluster (v1.22+) with
kubectlconfigured - Cluster admin permissions to create namespaces and CRDs
- A Git repository containing Kubernetes manifests, Helm charts, or Kustomize overlays
- ArgoCD CLI (
argocd) installed locally (optional but recommended) - Basic familiarity with Kubernetes Deployments, Services, and namespaces
What Is GitOps and Why ArgoCD?
GitOps is an operational model where the desired state of infrastructure and applications is declared in Git. An operator running inside the cluster continuously compares the live state against the desired state and reconciles differences. ArgoCD is the most widely adopted Kubernetes-native GitOps operator, with the CNCF Graduated project status as of 2022.
The core advantages over traditional push-based CI/CD pipelines:
| Feature | ArgoCD (GitOps pull) | Jenkins / GitLab CI (push) |
|---|---|---|
| Cluster credentials storage | Inside cluster only | In CI system secrets |
| Drift detection | Continuous, automatic | Only at deploy time |
| Rollback mechanism | Git revert to any commit | Re-run old pipeline |
| Audit trail | Git history | CI logs |
| Multi-cluster support | Native, per Application | Manual pipeline config |
| Self-healing | Built-in sync loop | Not available |
The pull model is a significant security improvement: your CI pipeline no longer needs cluster credentials. ArgoCD runs inside the cluster and pulls changes from Git, which is always outbound-only.
Installing ArgoCD
Create the dedicated namespace and apply the official installation manifest:
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 reach Running state:
kubectl wait --for=condition=available deployment --all -n argocd --timeout=120s
kubectl get pods -n argocd
Accessing the Web UI
By default, the argocd-server service is of type ClusterIP. For local access, use port-forwarding:
kubectl port-forward svc/argocd-server -n argocd 8080:443
Retrieve the auto-generated admin password:
kubectl get secret argocd-initial-admin-secret -n argocd \
-o jsonpath="{.data.password}" | base64 -d && echo
Log in via CLI:
argocd login localhost:8080 --username admin --password <password> --insecure
For production, configure an Ingress with TLS and integrate SSO (Dex with GitHub/OIDC) instead of the admin account.
Connecting a Git Repository
ArgoCD needs access to your Git repository to fetch manifests. For public repos, no credentials are required. For private repos:
argocd repo add https://github.com/your-org/your-k8s-repo \
--username git \
--password <token>
For SSH:
argocd repo add git@github.com:your-org/your-k8s-repo.git \
--ssh-private-key-path ~/.ssh/id_rsa
You can also manage repositories declaratively as Kubernetes Secrets with the argocd.argoproj.io/secret-type: repository label if you prefer full GitOps management of ArgoCD itself.
Creating ArgoCD Applications
An Application is the core ArgoCD resource. It defines what to deploy, from where, and to which cluster and namespace.
Declarative Application Manifest
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-web-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/your-k8s-repo
targetRevision: main
path: manifests/my-web-app
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
selfHeal: true
prune: true
syncOptions:
- CreateNamespace=true
Apply it:
kubectl apply -f my-web-app-application.yaml
Helm Chart Applications
ArgoCD natively supports Helm without requiring Helm to be installed on CI systems:
source:
repoURL: https://github.com/your-org/your-k8s-repo
targetRevision: main
path: charts/my-web-app
helm:
valueFiles:
- values-production.yaml
parameters:
- name: image.tag
value: "v1.4.2"
Kustomize Applications
source:
repoURL: https://github.com/your-org/your-k8s-repo
targetRevision: main
path: kustomize/overlays/production
ArgoCD auto-detects kustomization.yaml and runs kustomize build automatically.
Sync Policies and Self-Healing
Sync policy is the most important configuration decision in ArgoCD.
Manual sync — ArgoCD detects drift but requires a human (or CI step) to trigger sync. Useful for production environments where you want explicit approval before changes deploy.
Automated sync — ArgoCD syncs automatically when it detects a difference between Git and the cluster. Combine with self-healing and pruning for full automation:
syncPolicy:
automated:
selfHeal: true # revert manual kubectl edits
prune: true # delete resources removed from Git
retry:
limit: 5
backoff:
duration: 5s
maxDuration: 3m
factor: 2
selfHeal: true means if someone manually edits a resource with kubectl, ArgoCD will revert it within seconds. This enforces strict GitOps discipline.
prune: true means resources deleted from the Git repo are also deleted from the cluster. Without pruning, orphaned resources accumulate over time.
Real-World Scenario: Multi-Environment Promotion
You have three environments — dev, staging, and production — each in a separate namespace, with environment-specific Kustomize overlays. Your CI pipeline builds and pushes a Docker image, then updates the image tag in a dev/kustomization.yaml file and commits to Git.
repo/
kustomize/
base/ ← shared manifests
overlays/
dev/ ← ArgoCD App for dev namespace
staging/ ← ArgoCD App for staging namespace
production/ ← ArgoCD App for production namespace (manual sync)
ArgoCD for dev has automated: {} (auto-deploy on every commit). ArgoCD for staging and production uses manual sync — an engineer reviews the diff in the UI and clicks sync, or a PR approval triggers an argocd app sync CLI call in the CI pipeline.
This pattern keeps promotion controlled and auditable through Git history, not Jenkins build logs.
Gotchas and Edge Cases
CRD ordering issues — If your app installs Custom Resource Definitions alongside resources that use them, ArgoCD may fail on first sync because CRDs are not yet established when dependent resources are applied. Use sync waves with argocd.argoproj.io/sync-wave: "-1" on CRD manifests to ensure they apply first.
Pruning and Jobs — ArgoCD prune will delete completed Jobs and their Pods if they are removed from Git. Use argocd.argoproj.io/hook: PostSync and argocd.argoproj.io/hook-delete-policy: HookSucceeded for one-time migration jobs to prevent accidental deletion.
Image tag strategy — Avoid using latest as an image tag. ArgoCD compares manifests, not image digests, so a new push to latest will not trigger a sync. Use immutable tags (git SHA or semver). The ArgoCD Image Updater project can automate tag bumping in Git.
RBAC and Projects — The default project allows all repos and all clusters. For multi-team setups, create named AppProjects with scoped source repos, destination namespaces, and allowed resource kinds to enforce least-privilege.
Secret management — Never store Kubernetes Secret manifests with plaintext data in Git. Use Sealed Secrets, External Secrets Operator, or SOPS-encrypted secrets committed to Git. See the related article on Kubernetes secrets management with SOPS and age.
Sync timeout — Long-running Helm hooks can exceed the default sync timeout (300s). Increase with --timeout in CLI or configure timeout.reconciliation in the argocd-cm ConfigMap.
Troubleshooting Common Issues
App stuck in Progressing — Check the argocd app get <name> output for degraded resources. Usually a failed Deployment rollout or a pending PVC. Run kubectl describe pod -n <namespace> on the affected Pod.
ComparisonError or Unknown health — ArgoCD cannot fetch manifests. Check repository connectivity with argocd repo list and verify credentials.
Self-healing loop — If ArgoCD keeps reverting a resource, a validating webhook or operator is modifying the resource after ArgoCD applies it (e.g., injecting sidecars). Use ignoreDifferences in the Application spec to tell ArgoCD to ignore specific fields:
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/template/spec/containers/0/resources
Pruning deletes unexpected resources — Ensure all resources you want ArgoCD to manage have the correct app.kubernetes.io/instance label. Resources without this label will not be tracked and may cause confusion.
Summary
- ArgoCD implements GitOps by continuously reconciling cluster state with Git-defined desired state
- Install with a single
kubectl applyinto theargocdnamespace; access via port-forward or Ingress - Applications are defined declaratively and support raw manifests, Helm charts, and Kustomize
- Use automated sync with
selfHealandprunefor dev/staging; manual sync for production gates - Organize multi-environment setups with Kustomize overlays or Helm value files per environment
- Secure secrets with Sealed Secrets or External Secrets Operator — never plaintext in Git
- Use sync waves to handle CRD ordering and ArgoCD Image Updater for automated tag promotion
- RBAC Projects scope repository and cluster access for multi-team deployments