ArgoCD Fundamentals - GitOps for Kubernetes
ArgoCD implements GitOps principles by continuously monitoring Git repositories and automatically synchronizing cluster state with the declared configuration. Rather than using imperative kubectl commands or manual Helm installations, ArgoCD treats Git as the single source of truth and ensures the cluster always matches what's defined in version control. This approach brings the benefits of code review, auditability, and automated rollback to Kubernetes deployments.
What Is ArgoCD?
ArgoCD is a declarative, GitOps continuous delivery tool for Kubernetes that automates the deployment of applications from Git repositories:
graph LR
A[Git Repository] -->|ArgoCD monitors| B[ArgoCD]
B -->|Syncs changes| C[Kubernetes Cluster]
B -->|Compares state| C
C -->|Detects drift| B
style A fill:#90EE90
style C fill:#87CEEB
Core Principles:
graph TB
A[GitOps with ArgoCD] --> B[Git as Source
of Truth]
A --> C[Declarative
Configuration]
A --> D[Automated
Sync]
A --> E[Continuous
Reconciliation]
B --> B1[All changes via Git]
B --> B2[Full audit trail]
C --> C1[Desired state defined]
C --> C2[No imperative commands]
D --> D1[Automatic deployment]
D --> D2[Self-healing]
E --> E1[Drift detection]
E --> E2[Automatic correction]
Key Benefits:
- Declarative: Define desired state in Git, ArgoCD handles the rest
- Version Control: Every change tracked with commits, branches, and pull requests
- Auditability: Complete history of who changed what and when
- Automated Rollback: Revert to any previous Git commit
- Drift Detection: Identifies manual changes to cluster resources
- Self-Healing: Automatically corrects configuration drift
- Multi-Cluster: Manage applications across multiple Kubernetes clusters
ArgoCD Architecture
ArgoCD runs as a set of controllers in the Kubernetes cluster:
graph TB
A[ArgoCD Components] --> B[API Server]
A --> C[Repository Server]
A --> D[Application Controller]
A --> E[Redis]
A --> F[Dex/OIDC]
B --> B1[Web UI]
B --> B2[CLI interface]
B --> B3[API endpoints]
C --> C1[Git operations]
C --> C2[Manifest generation]
C --> C3[Template rendering]
D --> D1[App monitoring]
D --> D2[Sync execution]
D --> D3[Health assessment]
E --> E1[Cache]
E --> E2[Session storage]
F --> F1[Authentication]
F --> F2[SSO integration]
Component Responsibilities:
API Server: Exposes the API consumed by the Web UI, CLI, and CI/CD systems. Handles authentication, authorization, and application management operations.
Repository Server: Connects to Git repositories, generates Kubernetes manifests from source files (Helm, Kustomize, plain YAML), and caches the generated manifests.
Application Controller: Monitors running applications and compares current state against desired state in Git. Triggers synchronization when differences are detected.
Redis: Provides caching for repository data and session storage for the API server.
Dex: Optional identity provider for SSO integration with external authentication systems.
Core Concepts
Applications
An Application represents a deployed application in ArgoCD:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
# Source repository
source:
repoURL: https://github.com/company/myapp.git
targetRevision: main
path: k8s
# Destination cluster and namespace
destination:
server: https://kubernetes.default.svc
namespace: production
# Sync policy
syncPolicy:
automated:
prune: true
selfHeal: true
Application States:
stateDiagram-v2
[*] --> OutOfSync: Initial deployment
OutOfSync --> Syncing: Sync triggered
Syncing --> Synced: Sync successful
Synced --> OutOfSync: Git change detected
Synced --> OutOfSync: Cluster drift detected
OutOfSync --> OutOfSync: Manual change
Syncing --> Failed: Sync error
Failed --> Syncing: Retry
- Synced: Cluster state matches Git state
- OutOfSync: Differences detected between Git and cluster
- Syncing: Sync operation in progress
- Failed: Sync operation failed
Projects
Projects provide logical grouping and RBAC for applications:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: production
namespace: argocd
spec:
description: Production applications
# Allowed source repositories
sourceRepos:
- https://github.com/company/*
# Allowed destination clusters and namespaces
destinations:
- namespace: 'production-*'
server: https://kubernetes.default.svc
# Allowed resource types
clusterResourceWhitelist:
- group: '*'
kind: '*'
# Denied resource types
namespaceResourceBlacklist:
- group: ''
kind: ResourceQuota
Project Use Cases:
- Team Isolation: Separate projects for different teams
- Environment Separation: Different projects for dev, staging, production
- Security Boundaries: Restrict what applications can deploy where
Sync Strategies
ArgoCD offers flexible synchronization approaches:
graph TB
A[Sync Strategies] --> B[Manual Sync]
A --> C[Automated Sync]
B --> B1[Explicit trigger]
B --> B2[Review before apply]
B --> B3[Controlled deployment]
C --> C1[Auto sync on Git push]
C --> C2[Self-healing enabled]
C --> C3[Prune removed resources]
Manual Sync:
syncPolicy: {} # No automated sync
Deployments require explicit approval via UI or CLI. Useful for production environments requiring human review.
Automated Sync:
syncPolicy:
automated:
prune: true # Delete resources removed from Git
selfHeal: true # Revert manual changes
allowEmpty: false # Prevent deleting all resources
Automatically deploys changes when Git commits are pushed. Prune removes resources deleted from Git. Self-heal reverts manual kubectl changes.
Sync Windows:
syncPolicy:
syncOptions:
- CreateNamespace=true
automated:
prune: true
selfHeal: true
# Restrict sync to specific time windows
syncWindows:
- kind: allow
schedule: '0 9 * * MON-FRI' # Business hours weekdays
duration: 8h
applications:
- 'production-*'
Health Assessment
ArgoCD evaluates the health of deployed resources:
graph LR
A[Resource Health] --> B[Healthy]
A --> C[Progressing]
A --> D[Degraded]
A --> E[Suspended]
A --> F[Missing]
A --> G[Unknown]
B --> B1[All checks pass]
C --> C1[In progress]
D --> D1[Failures detected]
E --> E1[Intentionally paused]
F --> F1[Resource deleted]
G --> G1[Unable to assess]
Built-in Health Checks:
# Deployment health
# Healthy when:
# - Desired replicas == available replicas
# - No old ReplicaSets with replicas > 0
# Service health
# Healthy when:
# - Service exists
# - Endpoints exist (for non-headless services)
# Ingress health
# Healthy when:
# - Ingress exists
# - LoadBalancer has assigned IP
# Custom Resource health
# Defined by CRD or custom health check
Custom Health Checks:
# ConfigMap in argocd namespace
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
resource.customizations: |
mycompany.io/Database:
health.lua: |
hs = {}
if obj.status ~= nil then
if obj.status.phase == "Running" then
hs.status = "Healthy"
hs.message = "Database is running"
elseif obj.status.phase == "Pending" then
hs.status = "Progressing"
hs.message = "Database is starting"
else
hs.status = "Degraded"
hs.message = obj.status.message
end
else
hs.status = "Progressing"
hs.message = "Waiting for status"
end
return hs
Working with ArgoCD
CLI Operations
The ArgoCD CLI provides command-line access to all functionality:
Login:
# Login to ArgoCD
argocd login argocd.example.com
# Login with SSO
argocd login argocd.example.com --sso
# Login with token
argocd login argocd.example.com --auth-token $ARGOCD_TOKEN
Managing Applications:
# Create application
argocd app create myapp \
--repo https://github.com/company/myapp.git \
--path k8s \
--dest-server https://kubernetes.default.svc \
--dest-namespace production
# List applications
argocd app list
# Get application details
argocd app get myapp
# Sync application
argocd app sync myapp
# Sync and wait
argocd app sync myapp --async=false
# Rollback to previous revision
argocd app rollback myapp
# Delete application
argocd app delete myapp
# Delete application and resources
argocd app delete myapp --cascade
Application Status:
# Watch application status
argocd app wait myapp
# Get sync status
argocd app get myapp --refresh
# View sync history
argocd app history myapp
# View differences
argocd app diff myapp
# View manifests
argocd app manifests myapp
Managing Repositories:
# Add Git repository
argocd repo add https://github.com/company/myapp.git \
--username git \
--password $GIT_TOKEN
# Add with SSH key
argocd repo add git@github.com:company/myapp.git \
--ssh-private-key-path ~/.ssh/id_rsa
# List repositories
argocd repo list
# Remove repository
argocd repo rm https://github.com/company/myapp.git
Web UI
The ArgoCD Web UI provides visual application management:
graph TB
A[ArgoCD UI] --> B[Applications View]
A --> C[Application Details]
A --> D[Settings]
B --> B1[Grid view]
B --> B2[List view]
B --> B3[Filter/search]
C --> C1[Resource tree]
C --> C2[Sync status]
C --> C3[Event logs]
C --> C4[Manifest diff]
D --> D1[Repositories]
D --> D2[Clusters]
D --> D3[Projects]
D --> D4[Users/RBAC]
Key UI Features:
- Resource Tree: Visual representation of application resources and relationships
- Live State: Real-time view of cluster resources
- Desired State: View of what's defined in Git
- Diff View: Side-by-side comparison of live vs desired state
- Sync Options: Manual sync with preview, prune, replace options
- Rollback: One-click rollback to any previous Git revision
- Logs: Container logs accessible directly from UI
- Terminal: Exec into containers from browser
Practical Example - Deploying an Application
Step 1: Prepare Git Repository
# Repository structure
myapp/
├── README.md
└── k8s/
├── deployment.yaml
├── service.yaml
└── ingress.yaml
k8s/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: company/myapp:v1.0.0
ports:
- containerPort: 8080
k8s/service.yaml:
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 8080
Step 2: Create ArgoCD Application
# application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/company/myapp.git
targetRevision: HEAD
path: k8s
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Apply Application:
# Apply application manifest
kubectl apply -f application.yaml
# Or create via CLI
argocd app create myapp \
--repo https://github.com/company/myapp.git \
--path k8s \
--dest-server https://kubernetes.default.svc \
--dest-namespace production \
--sync-policy automated \
--auto-prune \
--self-heal
Step 3: Verify Deployment
# Check application status
argocd app get myapp
# Output:
# Name: myapp
# Project: default
# Server: https://kubernetes.default.svc
# Namespace: production
# URL: https://argocd.example.com/applications/myapp
# Repo: https://github.com/company/myapp.git
# Target: HEAD
# Path: k8s
# SyncWindow: Sync Allowed
# Sync Policy: Automated (Prune)
# Sync Status: Synced to HEAD (a1b2c3d)
# Health Status: Healthy
# Watch sync progress
argocd app wait myapp --health
# View resources
kubectl get all -n production
Step 4: Update Application
# Update image in Git
cd myapp/k8s
sed -i 's/v1.0.0/v1.1.0/g' deployment.yaml
git add deployment.yaml
git commit -m "Update to v1.1.0"
git push
# ArgoCD automatically detects and syncs
# Watch the sync
argocd app get myapp --refresh
Application Patterns
App of Apps Pattern
Manage multiple applications with a parent application:
# apps/parent.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: parent-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/company/infrastructure.git
path: apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
# apps/frontend.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: frontend
spec:
source:
repoURL: https://github.com/company/frontend.git
path: k8s
destination:
server: https://kubernetes.default.svc
namespace: production
# apps/backend.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: backend
spec:
source:
repoURL: https://github.com/company/backend.git
path: k8s
destination:
server: https://kubernetes.default.svc
namespace: production
ApplicationSet Pattern
Dynamically generate applications from templates:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: microservices
namespace: argocd
spec:
generators:
- list:
elements:
- name: frontend
namespace: production
- name: backend
namespace: production
- name: worker
namespace: production
template:
metadata:
name: '{{name}}'
spec:
project: default
source:
repoURL: https://github.com/company/{{name}}.git
path: k8s
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
Common Pitfalls
Manual kubectl Changes: Directly modifying resources with kubectl causes drift. ArgoCD will revert changes if self-heal is enabled.
Wrong Target Revision: Pointing to a moving target like main can cause unexpected deployments. Use tags or commit SHAs for production.
Missing Prune: Without prune enabled, deleted resources remain in the cluster.
No Sync Windows: Unrestricted sync can deploy during critical business hours. Use sync windows for production.
Ignoring Health Status: Deploying without monitoring health can leave broken applications running.
Key Takeaways
- ArgoCD implements GitOps by treating Git as the single source of truth for Kubernetes deployments
- Applications in ArgoCD connect Git repositories to Kubernetes clusters with automatic synchronization
- The Application Controller continuously monitors Git and cluster state, detecting and reconciling differences
- Automated sync with prune and self-heal ensures cluster state always matches Git configuration
- Projects provide RBAC and logical grouping for applications across teams and environments
- ArgoCD assesses resource health using built-in checks for standard resources and custom Lua scripts for CRDs
- Manual sync requires explicit approval while automated sync deploys changes immediately upon Git commit
- The Web UI provides visual resource trees, diff views, and one-click rollbacks to previous Git revisions
- The CLI enables automation and CI/CD integration for application management operations
- App of Apps pattern manages multiple related applications through a parent Application manifest
- ApplicationSets dynamically generate multiple Applications from templates and generators
- Sync windows restrict deployment times to maintenance windows or business hours
- Drift detection identifies manual kubectl changes that deviate from Git-declared state
- Self-healing automatically reverts manual changes to match Git configuration
- Every deployment is auditable through Git commit history with full traceability of who changed what and when