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 kubectl configured
  • 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:

FeatureArgoCD (GitOps pull)Jenkins / GitLab CI (push)
Cluster credentials storageInside cluster onlyIn CI system secrets
Drift detectionContinuous, automaticOnly at deploy time
Rollback mechanismGit revert to any commitRe-run old pipeline
Audit trailGit historyCI logs
Multi-cluster supportNative, per ApplicationManual pipeline config
Self-healingBuilt-in sync loopNot 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 apply into the argocd namespace; access via port-forward or Ingress
  • Applications are defined declaratively and support raw manifests, Helm charts, and Kustomize
  • Use automated sync with selfHeal and prune for 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