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:

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

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:

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:

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