ArgoCD
Workflows and Pipelines
Container native workflow engine for Kubernetes supporting both DAG and step based workflows
Argo Workflows is an open source container-native workflow engine for orchestrating parallel jobs on Kubernetes. Argo Workflows is implemented as a Kubernetes CRD.
- Define workflows where each step in the workflow is a container.
- Model multi-step workflows as a sequence of tasks or capture the dependencies between tasks using a graph (DAG).
- Easily run compute intensive jobs for machine learning or data processing in a fraction of the time using Argo Workflows on Kubernetes.
- Run CI/CD pipelines natively on Kubernetes without configuring complex software development products.
Continuous Delivery
Declarative Continuous Delivery following Gitops
Application definitions, configurations, and environments should be declarative and version controlled. Application deployment and lifecycle management should be automated, auditable, and easy to understand.
Advanced Deployment Controller
Additional Kubernetes deployment strategies such as Blue-Green and Canary
Events
Event based dependency manager for Kubernetes
What Argo does differently is how they manage the actual CI/CD. It is specifically developed for Kubernetes and integrates with it through CRD's (Custom Resource Definitions). It defines a new CRD which is the 'Workflow'. In this workflow you define what needs to happen by laying out steps in a yaml format. Each step runs inits own Docker containeron your own Kubernetes cluster.
Others
- GitHub - argoproj/argo-workflows: Workflow Engine for Kubernetes · GitHub
- Home | Argo
- https://argoproj.github.io/argo-rollouts
- https://argoproj.github.io/argo-events/setup/kafka
Overview
ArgoCD is a declarative, GitOps continuous delivery tool for Kubernetes. It automatically syncs your K8s cluster state with Git repository configurations.
Type: Continuous Delivery (GitOps)
Key Features:
- Declarative GitOps-based continuous delivery
- Automated deployment and lifecycle management
- Multi-cluster, multi-tenant support
- Visual UI for application state and diff
- Automated drift detection and self-healing
- SSO integration (SAML, OIDC, LDAP)
- RBAC for multi-team environments
- Webhook integrations
Architecture: Kubernetes-native, runs as K8s controllers
Core Concepts
GitOps Workflow
[Git Repository]
↓ (Git commit/push)
[ArgoCD detects change]
↓ (Compare desired vs actual)
[Sync if different]
↓ (Apply manifests)
[Kubernetes Cluster]
Principles:
- Git as single source of truth - All desired state in Git
- Declarative - Kubernetes manifests describe desired state
- Automated - Automatic sync from Git to cluster
- Auditable - Full history in Git
- Self-healing - Detect and correct drift
Components
ArgoCD Server:
- API server + Web UI
- Application management
- Repository/cluster management
- RBAC enforcement
Repository Server:
- Maintains local cache of Git repositories
- Generates Kubernetes manifests
- Supports Helm, Kustomize, Jsonnet
Application Controller:
- Monitors applications
- Compares desired state (Git) vs actual state (K8s)
- Triggers sync operations
Dex (Optional):
- SSO/OIDC provider integration
- User authentication
Redis:
- Caching layer
- Temporary data storage
Installation
Quick Start (Non-HA)
# Create namespace
kubectl create namespace argocd
# Install ArgoCD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Wait for pods
kubectl wait --for=condition=Ready pods --all -n argocd --timeout=300s
# Get initial admin password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# Port forward to access UI
kubectl port-forward svc/argocd-server -n argocd 8080:443
# Access at https://localhost:8080
# Username: admin
# Password: (from above command)
Production Install (HA)
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/ha/install.yaml
Differences:
- Multiple replicas of argocd-server
- Multiple replicas of argocd-repo-server
- Redis HA cluster (3 replicas)
- argocd-application-controller runs as StatefulSet
Helm Install
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm install argocd argo/argo-cd \
--namespace argocd \
--create-namespace \
--set server.service.type=LoadBalancer
CLI Installation
# macOS
brew install argocd
# Linux
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/
# Login
argocd login localhost:8080 --username admin --password <password>
# Change password
argocd account update-password
Application Configuration
Basic Application Manifest
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
# Source repository
source:
repoURL: https://github.com/myorg/myapp
targetRevision: HEAD
path: k8s/overlays/production
# Destination cluster
destination:
server: https://kubernetes.default.svc
namespace: production
# Sync policy
syncPolicy:
automated:
prune: true # Delete resources not in Git
selfHeal: true # Auto-sync on drift
allowEmpty: false
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
Using Helm Charts
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-helm
namespace: argocd
spec:
source:
repoURL: https://charts.example.com
chart: myapp
targetRevision: 1.2.3
helm:
releaseName: myapp
values: |
replicaCount: 3
image:
tag: v1.2.3
parameters:
- name: service.type
value: LoadBalancer
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
Using Kustomize
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-kustomize
namespace: argocd
spec:
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: overlays/production
kustomize:
images:
- myapp:v1.2.3
commonLabels:
environment: production
namePrefix: prod-
destination:
server: https://kubernetes.default.svc
namespace: production
CLI Operations
Application Management
# List applications
argocd app list
# Get application details
argocd app get myapp
# Create application
argocd app create myapp \
--repo https://github.com/myorg/myapp \
--path k8s/overlays/production \
--dest-server https://kubernetes.default.svc \
--dest-namespace production
# Sync application
argocd app sync myapp
# Sync with prune
argocd app sync myapp --prune
# Delete application
argocd app delete myapp
# Enable auto-sync
argocd app set myapp --sync-policy automated
# Disable auto-sync
argocd app set myapp --sync-policy none
# Set auto-prune
argocd app set myapp --auto-prune
# Set self-heal
argocd app set myapp --self-heal
Diff and Sync
# Show diff between Git and cluster
argocd app diff myapp
# Show manifest
argocd app manifests myapp
# Sync specific resource
argocd app sync myapp --resource Deployment:myapp
# Rollback to previous sync
argocd app rollback myapp
# History
argocd app history myapp
Repository Management
# Add repository
argocd repo add https://github.com/myorg/myapp
# Add private repo (SSH)
argocd repo add git@github.com:myorg/myapp.git \
--ssh-private-key-path ~/.ssh/id_rsa
# Add private repo (HTTPS)
argocd repo add https://github.com/myorg/myapp \
--username myuser \
--password mytoken
# List repos
argocd repo list
# Remove repo
argocd repo rm https://github.com/myorg/myapp
Cluster Management
# Add external cluster
argocd cluster add my-cluster
# List clusters
argocd cluster list
# Remove cluster
argocd cluster rm https://cluster-api-server
Web UI Features
Application View
Overview:
- Application health status
- Sync status (synced/out-of-sync)
- Last sync time
- Git revision
Resource Tree:
- Visual DAG of all K8s resources
- Health status per resource
- Pod logs viewer
- Events viewer
- Resource diff viewer
App Details:
- Parameters and source
- Sync policy configuration
- Sync history
- Manifest preview
Operations
- Manual Sync - Trigger deployment
- Refresh - Fetch latest Git state
- Hard Refresh - Clear cache and refresh
- Rollback - Revert to previous sync
- Terminate - Kill running sync operation
Multi-Cluster Management
Register Additional Clusters
# List contexts
kubectl config get-contexts
# Add cluster
argocd cluster add <context-name>
# Example
argocd cluster add staging-cluster
argocd cluster add production-cluster
Deploy to Multiple Clusters
ApplicationSet:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: myapp-multicluster
namespace: argocd
spec:
generators:
- list:
elements:
- cluster: staging
url: https://staging.k8s.local
namespace: staging
- cluster: production
url: https://prod.k8s.local
namespace: production
template:
metadata:
name: '{{cluster}}-myapp'
spec:
source:
repoURL: https://github.com/myorg/myapp
targetRevision: HEAD
path: 'overlays/{{cluster}}'
destination:
server: '{{url}}'
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
Advanced Features
Projects
Logical grouping of applications with RBAC:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: myproject
namespace: argocd
spec:
description: My Project
# Source repos
sourceRepos:
- 'https://github.com/myorg/*'
# Destination clusters/namespaces
destinations:
- namespace: 'production'
server: https://kubernetes.default.svc
- namespace: 'staging'
server: https://kubernetes.default.svc
# Cluster resource whitelist
clusterResourceWhitelist:
- group: '*'
kind: '*'
# Namespace resource blacklist
namespaceResourceBlacklist:
- group: ''
kind: ResourceQuota
# Roles
roles:
- name: developer
policies:
- p, proj:myproject:developer, applications, get, myproject/*, allow
- p, proj:myproject:developer, applications, sync, myproject/*, allow
Sync Windows
Restrict sync operations to specific time windows:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: myproject
spec:
syncWindows:
- kind: allow
schedule: '0 9-17 * * 1-5' # Mon-Fri, 9am-5pm
duration: 8h
applications:
- '*-production'
- kind: deny
schedule: '0 0-6 * * *' # Midnight-6am daily
duration: 6h
applications:
- '*'
Sync Hooks
Execute jobs during sync operations:
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: migrate
image: myapp:latest
command: ["npm", "run", "migrate"]
restartPolicy: Never
Hook Types:
PreSync- Before applying manifestsSync- During manifest applicationPostSync- After all resources are healthySyncFail- When sync failsSkip- Skip resource
Delete Policies:
HookSucceeded- Delete after successful executionHookFailed- Delete after failed executionBeforeHookCreation- Delete previous hook before creating new one
Resource Hooks and Waves
Control deployment order:
apiVersion: apps/v1
kind: Deployment
metadata:
name: database
annotations:
argocd.argoproj.io/sync-wave: "0" # Deploy first
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
annotations:
argocd.argoproj.io/sync-wave: "1" # Deploy after wave 0
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
annotations:
argocd.argoproj.io/sync-wave: "2" # Deploy last
Integration with CI/CD
CI builds, ArgoCD deploys (Recommended)
GitHub Actions + ArgoCD:
name: CI
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
# Build and push Docker image
- uses: actions/checkout@v4
- name: Build Docker
run: |
docker build -t myapp:${{ github.sha }} .
docker push myapp:${{ github.sha }}
# Update K8s manifest in Git
- name: Update manifest
run: |
git clone https://github.com/myorg/k8s-manifests
cd k8s-manifests
sed -i "s|image: myapp:.*|image: myapp:${{ github.sha }}|" deployment.yaml
git commit -am "Update image to ${{ github.sha }}"
git push
# ArgoCD automatically syncs the change
Image Updater
Auto-update image tags in Git:
# Install ArgoCD Image Updater
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml
Annotate application:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
annotations:
argocd-image-updater.argoproj.io/image-list: myimage=myregistry/myapp
argocd-image-updater.argoproj.io/myimage.update-strategy: semver
argocd-image-updater.argoproj.io/write-back-method: git
RBAC Configuration
User Management
# Create local user
argocd account update-password \
--account developer \
--new-password password123
# List users
argocd account list
Configure RBAC
argocd-rbac-cm ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
namespace: argocd
data:
policy.default: role:readonly
policy.csv: |
# Developers can view and sync apps
p, role:developer, applications, get, */*, allow
p, role:developer, applications, sync, */*, allow
p, role:developer, repositories, get, *, allow
# DevOps can do everything
p, role:devops, applications, *, */*, allow
p, role:devops, clusters, *, *, allow
p, role:devops, repositories, *, *, allow
p, role:devops, projects, *, *, allow
# Group mappings (from SSO)
g, developers, role:developer
g, devops-team, role:devops
SSO Integration (OIDC)
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
url: https://argocd.example.com
oidc.config: |
name: Google
issuer: https://accounts.google.com
clientID: <client-id>
clientSecret: <client-secret>
requestedScopes:
- openid
- profile
- email
Monitoring and Alerts
Prometheus Metrics
ArgoCD exposes metrics at /metrics:
argocd_app_info- Application metadataargocd_app_sync_total- Sync countersargocd_app_health_status- Health statusargocd_app_k8s_request_total- K8s API calls
Grafana Dashboard
# Import official dashboard
# Dashboard ID: 14584
Webhook Notifications
Slack:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.slack: |
token: $slack-token
template.app-deployed: |
message: |
Application {{.app.metadata.name}} is now running new version.
trigger.on-deployed: |
- when: app.status.operationState.phase in ['Succeeded']
send: [app-deployed]
Best Practices
Repository Structure
Option 1: Mono-repo
my-app/
├── src/ # Application code
├── k8s/
│ ├── base/ # Base manifests
│ └── overlays/
│ ├── dev/
│ ├── staging/
│ └── production/
└── .github/
└── workflows/
Option 2: Separate repos
app-code-repo/ # Application code + Dockerfile
k8s-manifests-repo/ # Kubernetes manifests only
├── apps/
│ ├── app1/
│ └── app2/
└── clusters/
├── staging/
└── production/
Application Organization
- One app per microservice - Easier to manage
- Use ApplicationSets - For multi-cluster/multi-env
- Leverage Projects - Logical grouping + RBAC
- Enable auto-sync with caution - Start manual, enable for stable apps
Security
- Enable RBAC - Restrict access per team
- Use SSO - Integrate with company IdP
- Least privilege - Limit cluster permissions
- Private repos - Use SSH keys or tokens
- Audit logs - Enable and review regularly
Performance
- Resource limits - Set CPU/memory for ArgoCD components
- Prune old resources - Enable auto-prune
- Refresh interval - Default 3min, adjust as needed
- Cache tuning - Configure Redis appropriately
Argo Rollouts (Advanced Deployments)
Progressive delivery controller for K8s:
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
Canary Deployment
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: myapp
spec:
replicas: 5
strategy:
canary:
steps:
- setWeight: 20
- pause: {duration: 1m}
- setWeight: 40
- pause: {duration: 1m}
- setWeight: 60
- pause: {duration: 1m}
- setWeight: 80
- pause: {duration: 1m}
template:
spec:
containers:
- name: myapp
image: myapp:v2
Blue-Green Deployment
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: myapp
spec:
replicas: 3
strategy:
blueGreen:
activeService: myapp-active
previewService: myapp-preview
autoPromotionEnabled: false
template:
spec:
containers:
- name: myapp
image: myapp:v2
Troubleshooting
Application Not Syncing
# Check sync status
argocd app get myapp
# Force refresh
argocd app get myapp --refresh
# Hard refresh (clear cache)
argocd app get myapp --hard-refresh
# Check diff
argocd app diff myapp
# Manual sync
argocd app sync myapp
Application Stuck in Progressing
# Check resource status
kubectl get all -n <namespace>
# Check events
kubectl get events -n <namespace>
# Check pod logs
kubectl logs -n <namespace> <pod-name>
# Terminate operation
argocd app terminate-op myapp
Repository Connection Issues
# Test connection
argocd repo get https://github.com/myorg/myapp
# Check credentials
kubectl get secret -n argocd
# Re-add repository
argocd repo rm https://github.com/myorg/myapp
argocd repo add https://github.com/myorg/myapp
High Memory Usage
# Increase limits
kubectl edit deployment argocd-repo-server -n argocd
# Clear cache
kubectl delete pod -n argocd -l app.kubernetes.io/name=argocd-repo-server
Common Patterns
Environment Promotion
[Dev] --manual sync--> [Staging] --manual sync--> [Production]
Git branching:
main→ Productionstaging→ Stagingdevelop→ Dev
App config:
# Production app
targetRevision: main
path: overlays/production
# Staging app
targetRevision: staging
path: overlays/staging
# Dev app
targetRevision: develop
path: overlays/dev
Multi-Tenant Setup
# Project per team
kind: AppProject
metadata:
name: team-a
spec:
sourceRepos:
- 'https://github.com/team-a/*'
destinations:
- namespace: 'team-a-*'
server: '*'