GitOps with ArgoCD

A comprehensive guide to GitOps with ArgoCD covering declarative deployments, continuous delivery, sync policies, rollbacks, multi-cluster management, and practical implementation strategies for modern Kubernetes operations.

GitOps ArgoCD Continuous Delivery Kubernetes Native
What is GitOps?

GitOps is a paradigm for managing Kubernetes and infrastructure using Git as the single source of truth. In GitOps, Git repositories contain the entire desired state of the system, including application configurations, infrastructure definitions, and policies. An operator (like ArgoCD) continuously reconciles the actual cluster state with the desired state stored in Git.

GitOps brings several benefits: improved auditability (all changes are tracked in Git), faster recovery (rollback is just reverting a commit), and simplified operations (everything is declarative).

Git Repository ArgoCD Kubernetes Cluster Continuous Reconciliation
Key GitOps Principles:
  • Declarative Configuration: Everything is defined as code in Git
  • Version Control: Git is the single source of truth
  • Automated Reconciliation: Continuous sync between Git and clusters
  • Observability: Monitoring and alerting on drift detection
  • Auditability: All changes are tracked and reviewable
ArgoCD Architecture

ArgoCD is a declarative, GitOps continuous delivery tool for Kubernetes. It follows a pull-based model where the controller continuously monitors Git repositories and synchronizes cluster state.

ArgoCD API Server

Control plane component
Exposes the ArgoCD API and UI. Handles authentication, authorization, and manages application state. The primary interface for users and CI/CD systems.
UI, CLI, API access

Application Controller

Reconciliation engine
Continuously watches Git repositories and cluster state. Detects drifts and initiates synchronization. Manages application lifecycle (sync, health, prune).
Continuous reconciliation

Redis Cache

Caching layer
Caches Git repository state and manifests to improve performance. Reduces load on Git providers and speeds up reconciliation.
Performance optimization

Repo Server

Repository management
Clones Git repositories, generates manifests using Helm, Kustomize, or plain YAML. Provides rendered manifests to the API server.
Manifest generation
# Install ArgoCD kubectl create namespace argocd kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml # Install CLI curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64 chmod +x argocd sudo mv argocd /usr/local/bin/ # Get initial admin password kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d # Access ArgoCD UI kubectl port-forward svc/argocd-server -n argocd 8080:443 # Login via CLI argocd login localhost:8080 --username admin --password --insecure # Change password argocd account update-password
ArgoCD Application Definitions

An Application in ArgoCD defines which Git repository to source, which cluster to deploy to, and how to sync. Applications are the core unit of management in ArgoCD.

# Basic Application apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: nginx namespace: argocd spec: project: default source: repoURL: https://github.com/myorg/apps targetRevision: HEAD path: ./nginx destination: server: https://kubernetes.default.svc namespace: production syncPolicy: automated: prune: true selfHeal: true allowEmpty: false syncOptions: - CreateNamespace=true # Application with Helm apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: myapp namespace: argocd spec: project: default source: repoURL: https://github.com/myorg/helm-charts targetRevision: main path: ./myapp helm: valueFiles: - values-production.yaml parameters: - name: replicaCount value: "3" - name: image.tag value: "1.2.3" destination: server: https://kubernetes.default.svc namespace: production # Application with Kustomize apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: myapp-kustomize namespace: argocd spec: project: default source: repoURL: https://github.com/myorg/kustomize-apps targetRevision: main path: ./myapp/overlays/production kustomize: images: - myapp:1.2.3 destination: server: https://kubernetes.default.svc namespace: production
Application Best Practices:
  • Use separate applications for different services (microservices approach)
  • Use Projects to group applications and enforce policies
  • Use targetRevision to pin to specific versions (use branches for dev, tags for production)
  • Set appropriate sync policies for your environment
Sync Policies: Automated vs. Manual

Sync policies define how ArgoCD applies changes from Git to the cluster. You can choose between automated sync (continuous reconciliation) and manual sync (controlled by user).

Automated Sync

Continuous reconciliation
ArgoCD automatically syncs the cluster with Git whenever changes are detected. Includes automatic pruning of removed resources and self-healing of drift.
Production-ready workloads

Manual Sync

User-controlled deployment
ArgoCD detects drift but doesn't auto-sync. A user must manually trigger synchronization, providing an approval gate for changes.
Staging, controlled environments

Sync Waves

Ordered deployment
Control the order of resource deployment using sync waves. Critical resources (CRDs, storage) can be deployed before application resources.
Complex dependencies

Sync Policies

Prune, self-heal, allow-empty
prune removes resources not in Git. selfHeal corrects drift. allowEmpty permits zero resources.
Custom behavior control
# Automated sync with PRUNE syncPolicy: automated: prune: true # Delete resources not in Git selfHeal: true # Correct drift automatically allowEmpty: false # Don't allow empty applications # Manual sync with specific sync options syncPolicy: syncOptions: - CreateNamespace=true - ApplyOutOfSyncOnly=true - PruneLast=true # Prune only after successful sync - Validate=true # Validate before apply # Sync Waves (annotate resources) apiVersion: apps/v1 kind: Deployment metadata: name: app annotations: argocd.argoproj.io/sync-wave: "5" # Lower numbers first --- apiVersion: v1 kind: ConfigMap metadata: name: config annotations: argocd.argoproj.io/sync-wave: "1" # Config before deployment # Sync Hooks (pre/post-sync actions) apiVersion: batch/v1 kind: Job metadata: name: pre-sync-job annotations: argocd.argoproj.io/hook: PreSync argocd.argoproj.io/hook-delete-policy: HookSucceeded spec: template: spec: containers: - name: migration image: myapp:latest command: ["/bin/sh", "-c", "python migrate.py"] restartPolicy: Never
Multi-Cluster Management with ArgoCD

ArgoCD supports managing multiple clusters from a single control plane. This enables consistent deployments across development, staging, and production clusters.

# Register a cluster argocd cluster add cluster-context-name # or using kubeconfig argocd cluster add --kubeconfig ~/.kube/config --context cluster-context-name # List clusters argocd cluster list # Application with cluster-specific configuration apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: nginx-prod namespace: argocd spec: project: default source: repoURL: https://github.com/myorg/apps targetRevision: HEAD path: ./nginx helm: valueFiles: - values-prod.yaml destination: server: https://api.prod-cluster.example.com namespace: production # ApplicationSet for multi-cluster deployments apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: nginx-multi namespace: argocd spec: generators: - clusters: selector: matchLabels: environment: production template: metadata: name: '{{name}}-nginx' spec: project: default source: repoURL: https://github.com/myorg/apps targetRevision: HEAD path: ./nginx helm: valueFiles: - values-{{name}}.yaml destination: server: '{{server}}' namespace: production
Multi-Cluster Considerations: Ensure clusters have network connectivity to the ArgoCD control plane. Use different service accounts for each cluster. Consider cluster-specific configurations using Helm values or Kustomize overlays.
ApplicationSets: Advanced Application Management

ApplicationSets are a powerful feature that generates applications using a template and generators. They enable dynamic, scalable management of applications across clusters and environments.

# Cluster Generator apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: multi-cluster-apps namespace: argocd spec: generators: - clusters: selector: matchLabels: environment: production values: clusterName: '{{name}}' clusterEnv: '{{metadata.labels.environment}}' template: metadata: name: '{{name}}-app' spec: project: default source: repoURL: https://github.com/myorg/apps targetRevision: HEAD path: ./app helm: values: | environment: {{values.clusterEnv}} clusterName: {{values.clusterName}} destination: server: '{{server}}' namespace: production # Git Generator (directory-based) apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: directory-apps namespace: argocd spec: generators: - git: repoURL: https://github.com/myorg/apps revision: HEAD directories: - path: ./apps/* template: metadata: name: '{{path.basename}}' spec: project: default source: repoURL: https://github.com/myorg/apps targetRevision: HEAD path: '{{path}}' destination: server: https://kubernetes.default.svc namespace: production # List Generator apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: list-apps namespace: argocd spec: generators: - list: elements: - cluster: dev-cluster namespace: dev - cluster: staging-cluster namespace: staging - cluster: prod-cluster namespace: production template: metadata: name: '{{cluster}}-app' spec: project: default source: repoURL: https://github.com/myorg/apps targetRevision: HEAD path: ./app destination: server: 'https://{{cluster}}.example.com' namespace: '{{namespace}}'
ApplicationSet Best Practices:
  • Use ApplicationSets for managing many similar applications
  • Combine cluster and git generators for flexible patterns
  • Use label selectors to target specific clusters
  • Keep templates simple and use values for customization
  • Use the preserveResourcesOnDeletion flag carefully
Rollbacks and Disaster Recovery

GitOps makes rollbacks simple—just revert to a previous Git commit. ArgoCD also provides features for history and manual rollback.

# Rollback via Git # Revert to previous commit git revert HEAD git push # Rollback via ArgoCD UI/CLI # View application history argocd app history nginx-app # Rollback to specific revision argocd app rollback nginx-app # Force sync to specific commit argocd app sync nginx-app --revision # Configure sync with automatic rollback syncPolicy: automated: prune: true selfHeal: true retry: limit: 3 backoff: duration: 5s factor: 2 maxDuration: 30s # Disaster Recovery - Backup Applications # Export all applications argocd app list -o yaml > apps-backup.yaml # Export ApplicationSets kubectl get applicationsets -n argocd -o yaml > appsets-backup.yaml # Restore from backup kubectl apply -f apps-backup.yaml kubectl apply -f appsets-backup.yaml # Disaster Recovery - Cluster Restore # Export ArgoCD state kubectl get all -n argocd -o yaml > argocd-backup.yaml # Restore after cluster failure kubectl apply -f argocd-backup.yaml
Rollback Best Practices:
  • Always keep a clean Git history with meaningful commit messages
  • Use tags for releases to easily identify deployable versions
  • Test rollback procedures regularly in staging
  • Document rollback procedures for each application
  • Implement automated rollback on deployment failures
Security and RBAC in ArgoCD

ArgoCD provides comprehensive RBAC (Role-Based Access Control) to manage access to applications, projects, and cluster resources.

# ArgoCD RBAC Configuration apiVersion: v1 kind: ConfigMap metadata: name: argocd-rbac-cm namespace: argocd data: policy.default: role:readonly policy.csv: | # Project-level access p, role:admin, applications, *, default/*, allow p, role:dev, applications, get, default/nginx, allow p, role:dev, applications, sync, default/nginx, allow p, role:dev, applications, create, default/nginx, allow p, role:dev, applications, delete, default/nginx, allow # Global access p, role:viewer, applications, get, *, allow p, role:viewer, projects, get, *, allow # User bindings g, developer-team, role:dev g, operations-team, role:admin g, external-auditors, role:viewer# Single Sign-On with OIDC apiVersion: v1 kind: ConfigMap metadata: name: argocd-cm namespace: argocd data: url: https://argocd.example.com oidc.config: | name: Okta issuer: https://dev-123456.okta.com/oauth2/default clientID: 0oa1abcdefghijkl clientSecret: $oidc.okta.clientSecret requestedScopes: ["openid", "profile", "email", "groups"] groupsClaim: groups # Project definitions apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: production namespace: argocd spec: description: Production applications sourceRepos: - https://github.com/myorg/production-apps destinations: - namespace: production server: https://kubernetes.default.svc - namespace: staging server: https://kubernetes.default.svc clusterResourceWhitelist: - group: '*' kind: '*' namespaceResourceBlacklist: - group: '' kind: ResourceQuota roles: - name: team-lead policies: - p, proj:production:team-lead, applications, get, production/*, allow - p, proj:production:team-lead, applications, sync, production/*, allow groups: - lead-team
Security Best Practices:
  • Use the principle of least privilege for RBAC policies
  • Enable OIDC or SAML for SSO integration
  • Use ArgoCD Projects to enforce policies at the project level
  • Restrict source repositories to trusted Git sources
  • Enable audit logging for compliance
Frequently Asked Questions
What is the difference between ArgoCD and Jenkins?
Jenkins is a general-purpose CI/CD tool that executes pipelines (build, test, deploy). ArgoCD is specifically a GitOps CD tool that focuses on declarative deployment and continuous reconciliation of Kubernetes state. They can be used together: Jenkins builds images, ArgoCD deploys them.
How does ArgoCD handle drift?
ArgoCD detects drift by comparing the desired state (Git) with the live state (cluster). With selfHeal: true, it automatically corrects drift. With manual sync, it shows the drift and allows users to decide whether to sync.
Can ArgoCD deploy to multiple clusters?
Yes! ArgoCD supports multiple clusters. You can register clusters using argocd cluster add and deploy applications to any registered cluster. ApplicationSets make multi-cluster deployments even easier.
What is an ApplicationSet?
An ApplicationSet is a resource that generates one or more Applications using a template and generators. It enables dynamic, scalable management of applications across clusters, environments, and Git directories.
How do I implement canary deployments with ArgoCD?
Use Argo Rollouts (an extension) with ArgoCD. Argo Rollouts provides canary, blue-green, and A/B testing strategies. ArgoCD can manage the Rollout resources, and Argo Rollouts handles the progressive delivery logic.
What are the best practices for organizing Git repositories for GitOps?
Common patterns: mono-repo (all manifests in one repo), multi-repo (separate repos per app), or app-of-apps (one repo with sub-applications). Use environment-specific directories and Helm/Kustomize for configuration management.
How do I handle secrets with ArgoCD?
Use Sealed Secrets (encrypt secrets in Git) or external secret management (HashiCorp Vault, AWS Secrets Manager). ArgoCD integrates with external secrets through plugins and the External Secrets Operator. Never store raw secrets in Git.
What is the difference between sync and refresh in ArgoCD?
Refresh updates the application state from Git (detects changes). Sync applies those changes to the cluster. Refresh is "check for updates," sync is "apply updates."
Previous: Deployment Strategies Next: Helm Charts

GitOps with ArgoCD transforms Kubernetes operations by making Git the source of truth. Embrace declarative deployments, automated reconciliation, and auditability for modern, reliable infrastructure management.