ArgoCD
GitOps continuous delivery tool for Kubernetes that declaratively manages applications from Git repositories.
ArgoCD
GitOps continuous delivery tool for Kubernetes that declaratively manages applications from Git repositories.
Overview
ArgoCD is a declarative, GitOps continuous delivery tool for Kubernetes. It automates the deployment of applications by continuously monitoring Git repositories and synchronising the desired application state (defined in Git) with the live state in the cluster. ArgoCD provides a visual dashboard, CLI, and API for managing application deployments, rollbacks, and health monitoring across multiple clusters.
flowchart LR
subgraph "GitOps Workflow"
A[Developer] --> B[Git Repository]
B --> C[ArgoCD Server]
C --> D{Compare}
D -->|Out of Sync| E[Sync to Cluster]
D -->|In Sync| F[Monitor]
E --> G[Kubernetes Cluster]
F --> G
G --> C
end
Installation and Setup
ArgoCD can be installed in various configurations depending on your requirements for high availability and cluster size.
Key Concepts
- Namespace: ArgoCD typically runs in its own namespace (
argocd) - Installation Modes: Non-HA (single replica) or HA (multiple replicas with Redis)
- Core Components: API Server, Repository Server, Application Controller, Dex (SSO), Redis (caching)
graph TB
subgraph "ArgoCD Architecture"
A[API Server] --> B[Repository Server]
A --> C[Application Controller]
C --> B
B --> D[Git Repos]
C --> E[Kubernetes API]
A --> F[Redis]
C --> F
G[Web UI] --> A
H[CLI] --> A
end
Common Commands/Patterns
# Install ArgoCD (non-HA)
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Install ArgoCD (HA)
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/ha/install.yaml
# Install using Helm
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd -n argocd --create-namespace
# Get initial admin password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# Access ArgoCD UI (port-forward)
kubectl port-forward svc/argocd-server -n argocd 8080:443
# Install ArgoCD CLI
# 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/
# macOS
brew install argocd
# Login to ArgoCD
argocd login localhost:8080
# Change admin password
argocd account update-password
Examples
Expose ArgoCD with Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server-ingress
namespace: argocd
annotations:
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
ingressClassName: nginx
rules:
- host: argocd.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
name: https
tls:
- hosts:
- argocd.example.com
secretName: argocd-server-tls
Configure ArgoCD with ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
# Repository credentials
repositories: |
- url: https://github.com/myorg/myrepo
passwordSecret:
name: repo-creds
key: password
usernameSecret:
name: repo-creds
key: username
# OIDC configuration
oidc.config: |
name: Okta
issuer: https://myorg.okta.com
clientID: xxxxxxxxx
clientSecret: $oidc.okta.clientSecret
requestedScopes: ["openid", "profile", "email", "groups"]
# Resource tracking method
application.resourceTrackingMethod: annotation
Concepts: Applications, Projects, and Repositories
Understanding ArgoCD's core concepts is essential for effective GitOps implementation.
Key Concepts
- Application: A group of Kubernetes resources defined by a manifest in a Git repository
- Project: A logical grouping of applications that defines source repos, destination clusters, and permissions
- Repository: A Git repository containing application manifests (YAML, Helm, Kustomize)
- Destination: The target cluster and namespace where resources are deployed
graph TD
subgraph "ArgoCD Resource Hierarchy"
A[AppProject] --> B[Application 1]
A --> C[Application 2]
A --> D[Application 3]
B --> E[Git Repo]
B --> F[Destination Cluster]
C --> E
C --> G[Another Cluster]
D --> H[Helm Repo]
D --> F
end
AppProject Configuration
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: production
namespace: argocd
spec:
# Project description
description: Production applications
# Allowed source repositories
sourceRepos:
- 'https://github.com/myorg/*'
- 'https://charts.helm.sh/stable'
# Allowed destination clusters and namespaces
destinations:
- namespace: 'prod-*'
server: https://kubernetes.default.svc
- namespace: '*'
server: https://prod-cluster.example.com
# Allowed cluster resources
clusterResourceWhitelist:
- group: ''
kind: Namespace
- group: 'rbac.authorization.k8s.io'
kind: ClusterRole
- group: 'rbac.authorization.k8s.io'
kind: ClusterRoleBinding
# Denied namespaced resources
namespaceResourceBlacklist:
- group: ''
kind: ResourceQuota
- group: ''
kind: LimitRange
# Roles for RBAC
roles:
- name: developer
description: Developer access
policies:
- p, proj:production:developer, applications, get, production/*, allow
- p, proj:production:developer, applications, sync, production/*, allow
groups:
- developers
- name: admin
description: Admin access
policies:
- p, proj:production:admin, applications, *, production/*, allow
groups:
- platform-team
# Sync windows (maintenance windows)
syncWindows:
- kind: allow
schedule: '0 22 * * *'
duration: 1h
applications:
- '*'
- kind: deny
schedule: '0 9 * * 1-5'
duration: 8h
applications:
- 'prod-*'
Repository Management
# Add a Git repository
argocd repo add https://github.com/myorg/myrepo \
--username myuser \
--password mytoken
# Add a private repository with SSH
argocd repo add git@github.com:myorg/private-repo \
--ssh-private-key-path ~/.ssh/id_rsa
# Add a Helm repository
argocd repo add https://charts.helm.sh/stable \
--type helm \
--name stable
# Add OCI Helm repository
argocd repo add registry.example.com/charts \
--type helm \
--name myregistry \
--enable-oci
# List repositories
argocd repo list
# Remove a repository
argocd repo rm https://github.com/myorg/myrepo
Examples
Repository credentials secret:
apiVersion: v1
kind: Secret
metadata:
name: private-repo-creds
namespace: argocd
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
url: https://github.com/myorg/private-repo
username: git
password: ghp_xxxxxxxxxxxx
SSH key repository secret:
apiVersion: v1
kind: Secret
metadata:
name: private-repo-ssh
namespace: argocd
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
url: git@github.com:myorg/private-repo.git
sshPrivateKey: |
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
Application CRD and Manifests
The Application CRD is the primary resource for defining how applications are deployed.
Key Concepts
- Source: Where to get the application manifests (Git repo, Helm chart, or path)
- Destination: Where to deploy the application (cluster and namespace)
- Sync Policy: How and when to synchronise the application
- Health Status: Whether the application resources are healthy
Application Manifest Structure
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
# Finalizer ensures resources are cleaned up
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
# Project the application belongs to
project: default
# Source of the application manifests
source:
repoURL: https://github.com/myorg/myapp
targetRevision: HEAD
path: kubernetes/overlays/production
# Destination cluster and namespace
destination:
server: https://kubernetes.default.svc
namespace: production
# Sync policy configuration
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
# Ignore differences in specific fields
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas
- group: ''
kind: ConfigMap
name: my-config
jsonPointers:
- /data/key
Source Types
Directory of YAML files:
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: manifests/
directory:
recurse: true
exclude: '{config.json,*.txt}'
include: '*.yaml'
Helm chart from Git:
source:
repoURL: https://github.com/myorg/helm-charts
targetRevision: main
path: charts/myapp
helm:
releaseName: myapp
valueFiles:
- values.yaml
- values-production.yaml
values: |
replicaCount: 3
image:
tag: v1.2.3
parameters:
- name: service.type
value: LoadBalancer
Helm chart from repository:
source:
repoURL: https://charts.bitnami.com/bitnami
chart: nginx
targetRevision: 13.2.10
helm:
releaseName: my-nginx
values: |
replicaCount: 2
Kustomize:
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: overlays/production
kustomize:
namePrefix: prod-
nameSuffix: -v1
images:
- myapp=myregistry/myapp:v1.2.3
commonLabels:
environment: production
commonAnnotations:
team: platform
Examples
Multi-source application (Helm + values from Git):
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-multisource
namespace: argocd
spec:
project: default
sources:
- repoURL: https://charts.bitnami.com/bitnami
chart: nginx
targetRevision: 13.2.10
helm:
valueFiles:
- $values/nginx/production-values.yaml
- repoURL: https://github.com/myorg/config
targetRevision: main
ref: values
destination:
server: https://kubernetes.default.svc
namespace: production
Application with resource hooks:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-with-hooks
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: manifests/
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
---
# Hook resource (in your Git repo)
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: ["./migrate.sh"]
restartPolicy: Never
Git Repository Setup and Sync
Configuring Git repositories and understanding the synchronisation process.
Key Concepts
sequenceDiagram
participant Git as Git Repository
participant Repo as Repo Server
participant Ctrl as App Controller
participant K8s as Kubernetes
Ctrl->>Repo: Request manifests
Repo->>Git: Clone/Fetch
Git-->>Repo: Return files
Repo->>Repo: Render manifests
Repo-->>Ctrl: Return manifests
Ctrl->>K8s: Get live state
K8s-->>Ctrl: Return resources
Ctrl->>Ctrl: Compare desired vs live
Ctrl->>K8s: Apply changes
- Target Revision: The Git branch, tag, or commit to track
- Path: The directory within the repository containing manifests
- Refresh: Fetching the latest state from Git
- Hard Refresh: Invalidating the cache and re-fetching
Common Commands/Patterns
# Create an application from CLI
argocd app create myapp \
--repo https://github.com/myorg/myapp \
--path kubernetes/production \
--dest-server https://kubernetes.default.svc \
--dest-namespace production \
--revision main
# Create from file
argocd app create -f application.yaml
# List applications
argocd app list
# Get application details
argocd app get myapp
# Sync an application
argocd app sync myapp
# Sync with specific revision
argocd app sync myapp --revision v1.2.3
# Sync with prune
argocd app sync myapp --prune
# Sync specific resources only
argocd app sync myapp --resource :Service:myapp-service
argocd app sync myapp --resource apps:Deployment:myapp
# Preview sync (dry run)
argocd app sync myapp --dry-run
# Force sync (replace resources)
argocd app sync myapp --force
# Refresh application
argocd app get myapp --refresh
# Hard refresh (invalidate cache)
argocd app get myapp --hard-refresh
# Delete application
argocd app delete myapp
# Delete application and resources
argocd app delete myapp --cascade
Webhook Configuration
# GitHub webhook secret
apiVersion: v1
kind: Secret
metadata:
name: github-webhook-secret
namespace: argocd
stringData:
webhook.github.secret: mysecrettoken
---
# ArgoCD ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
webhook.github.secret: mysecrettoken
Examples
Application tracking a specific tag:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-release
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp
targetRevision: v1.2.3 # Git tag
path: manifests/
destination:
server: https://kubernetes.default.svc
namespace: production
Application tracking a specific commit:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-pinned
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp
targetRevision: a1b2c3d4e5f6 # Commit SHA
path: manifests/
destination:
server: https://kubernetes.default.svc
namespace: staging
Sync Policies
Sync policies control how and when ArgoCD synchronises applications with the cluster.
Key Concepts
- Manual Sync: User-initiated synchronisation
- Automated Sync: ArgoCD automatically syncs when changes are detected
- Self-Heal: Automatically fix drift from the desired state
- Prune: Remove resources that are no longer in Git
- Sync Windows: Time-based restrictions on when syncs can occur
stateDiagram-v2
[*] --> OutOfSync: New commit detected
OutOfSync --> Syncing: Auto/Manual sync
Syncing --> Synced: Success
Syncing --> SyncFailed: Error
SyncFailed --> Syncing: Retry
Synced --> OutOfSync: Git change
Synced --> OutOfSync: Manual change (drift)
OutOfSync --> Syncing: Self-heal
Sync Policy Options
syncPolicy:
# Automated sync configuration
automated:
# Prune resources that no longer exist in Git
prune: true
# Automatically sync when drift is detected
selfHeal: true
# Only sync if the app is OutOfSync
allowEmpty: false
# Sync options
syncOptions:
# Create namespace if it doesn't exist
- CreateNamespace=true
# Use server-side apply
- ServerSideApply=true
# Validate resources before applying
- Validate=true
# Apply out of sync only
- ApplyOutOfSyncOnly=true
# Prune last (after other resources)
- PruneLast=true
# Respect ignore differences
- RespectIgnoreDifferences=true
# Fail sync on shared resource
- FailOnSharedResource=true
# Replace resources instead of applying
- Replace=true
# Prune propagation policy
- PrunePropagationPolicy=foreground
# Retry configuration
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
# Managed namespace metadata
managedNamespaceMetadata:
labels:
env: production
annotations:
team: platform
Resource Hooks
# PreSync hook - runs before sync
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: pre-sync
image: alpine
command: ["/bin/sh", "-c", "echo Pre-sync task"]
restartPolicy: Never
---
# Sync hook - runs during sync
apiVersion: batch/v1
kind: Job
metadata:
name: sync-job
annotations:
argocd.argoproj.io/hook: Sync
argocd.argoproj.io/sync-wave: "0"
spec:
template:
spec:
containers:
- name: sync
image: alpine
command: ["/bin/sh", "-c", "echo Sync task"]
restartPolicy: Never
---
# PostSync hook - runs after successful sync
apiVersion: batch/v1
kind: Job
metadata:
name: post-sync-job
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
template:
spec:
containers:
- name: post-sync
image: alpine
command: ["/bin/sh", "-c", "echo Post-sync task"]
restartPolicy: Never
---
# SyncFail hook - runs when sync fails
apiVersion: batch/v1
kind: Job
metadata:
name: sync-fail-job
annotations:
argocd.argoproj.io/hook: SyncFail
spec:
template:
spec:
containers:
- name: notify
image: curlimages/curl
command: ["curl", "-X", "POST", "https://hooks.slack.com/..."]
restartPolicy: Never
Sync Waves
# Wave -1: Create namespace and RBAC first
apiVersion: v1
kind: Namespace
metadata:
name: myapp
annotations:
argocd.argoproj.io/sync-wave: "-1"
---
# Wave 0: Deploy ConfigMaps and Secrets
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
namespace: myapp
annotations:
argocd.argoproj.io/sync-wave: "0"
data:
config.yaml: |
key: value
---
# Wave 1: Deploy main application
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: myapp
annotations:
argocd.argoproj.io/sync-wave: "1"
spec:
replicas: 3
# ...
---
# Wave 2: Deploy dependent services
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-worker
namespace: myapp
annotations:
argocd.argoproj.io/sync-wave: "2"
spec:
replicas: 2
# ...
Examples
Conservative production sync policy:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: production-app
namespace: argocd
spec:
project: production
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
# Manual sync only - no automated
syncOptions:
- Validate=true
- PruneLast=true
- RespectIgnoreDifferences=true
retry:
limit: 3
backoff:
duration: 10s
factor: 2
maxDuration: 5m
Aggressive staging sync policy:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: staging-app
namespace: argocd
spec:
project: staging
source:
repoURL: https://github.com/myorg/myapp
targetRevision: develop
path: overlays/staging
destination:
server: https://kubernetes.default.svc
namespace: staging
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
- ApplyOutOfSyncOnly=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
Health Assessment
ArgoCD monitors the health of application resources to determine overall application health.
Key Concepts
- Health Status: Healthy, Progressing, Degraded, Suspended, Missing, Unknown
- Built-in Health Checks: Standard checks for Kubernetes resources
- Custom Health Checks: User-defined health assessments using Lua scripts
stateDiagram-v2
[*] --> Progressing: Deployment started
Progressing --> Healthy: All conditions met
Progressing --> Degraded: Timeout/Error
Healthy --> Progressing: Update initiated
Healthy --> Degraded: Resource failure
Degraded --> Progressing: Recovery attempt
Degraded --> Healthy: Issue resolved
Health Status Types
| Status | Description |
|---|---|
| Healthy | Resource is fully operational |
| Progressing | Resource is in a transitional state (e.g., rolling update) |
| Degraded | Resource is not healthy (e.g., pod crash, failed probe) |
| Suspended | Resource is paused (e.g., suspended deployment) |
| Missing | Resource is not present in the cluster |
| Unknown | Health status cannot be determined |
Custom Health Checks
# argocd-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
# Custom health check for CronJob
resource.customizations.health.batch_CronJob: |
hs = {}
if obj.status ~= nil then
if obj.status.lastScheduleTime ~= nil then
hs.status = "Healthy"
hs.message = "CronJob is scheduled"
else
hs.status = "Progressing"
hs.message = "Waiting for first schedule"
end
else
hs.status = "Progressing"
hs.message = "Waiting for status"
end
return hs
# Custom health check for Certificate (cert-manager)
resource.customizations.health.cert-manager.io_Certificate: |
hs = {}
if obj.status ~= nil then
if obj.status.conditions ~= nil then
for i, condition in ipairs(obj.status.conditions) do
if condition.type == "Ready" and condition.status == "False" then
hs.status = "Degraded"
hs.message = condition.message
return hs
end
if condition.type == "Ready" and condition.status == "True" then
hs.status = "Healthy"
hs.message = condition.message
return hs
end
end
end
end
hs.status = "Progressing"
hs.message = "Waiting for certificate"
return hs
# Custom health check for Rollout (Argo Rollouts)
resource.customizations.health.argoproj.io_Rollout: |
hs = {}
if obj.status ~= nil then
if obj.status.phase == "Healthy" then
hs.status = "Healthy"
hs.message = obj.status.message
elseif obj.status.phase == "Paused" then
hs.status = "Suspended"
hs.message = obj.status.message
elseif obj.status.phase == "Degraded" then
hs.status = "Degraded"
hs.message = obj.status.message
else
hs.status = "Progressing"
hs.message = obj.status.message
end
end
return hs
Ignore Resource Updates
# argocd-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
# Ignore specific resource updates for health checks
resource.customizations.ignoreDifferences.admissionregistration.k8s.io_MutatingWebhookConfiguration: |
jqPathExpressions:
- '.webhooks[]?.clientConfig.caBundle'
resource.customizations.ignoreDifferences.apiextensions.k8s.io_CustomResourceDefinition: |
jqPathExpressions:
- '.spec.conversion.webhook.clientConfig.caBundle'
Examples
Check application health via CLI:
# Get application with health details
argocd app get myapp
# Get health status in JSON format
argocd app get myapp -o json | jq '.status.health'
# List only unhealthy applications
argocd app list --health-status Degraded
# Watch application health
argocd app get myapp --watch
# Get resource tree with health
argocd app resources myapp --tree
Diff and Sync Status
Understanding the differences between desired and live state.
Key Concepts
- Sync Status: Synced, OutOfSync, Unknown
- Diff: The differences between Git (desired) and cluster (live) state
- Compare Options: How ArgoCD compares resources
Common Commands/Patterns
# View application diff
argocd app diff myapp
# Diff with local manifests
argocd app diff myapp --local ./manifests/
# Diff specific revision
argocd app diff myapp --revision v1.2.3
# Show diff in JSON
argocd app diff myapp --output json
# Get sync status
argocd app get myapp -o json | jq '.status.sync'
# List out of sync applications
argocd app list --sync-status OutOfSync
# Get detailed resource status
argocd app resources myapp
Ignore Differences
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: manifests/
destination:
server: https://kubernetes.default.svc
namespace: production
ignoreDifferences:
# Ignore replica count managed by HPA
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas
# Ignore specific ConfigMap key
- group: ""
kind: ConfigMap
name: myapp-config
jsonPointers:
- /data/dynamic-key
# Ignore using JQ path expressions
- group: apps
kind: Deployment
jqPathExpressions:
- .spec.template.spec.containers[].resources
# Ignore managed fields (server-side apply)
- group: "*"
kind: "*"
managedFieldsManagers:
- kube-controller-manager
Global Ignore Differences
# argocd-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
resource.compareoptions: |
# Ignore aggregated cluster roles
ignoreAggregatedRoles: true
# Respect ignore differences in sync
respectIgnoreDifferences: true
Examples
Application with extensive ignore differences:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-production
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
ignoreDifferences:
# Ignore HPA-managed replicas
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas
# Ignore auto-generated fields
- group: ""
kind: Service
jsonPointers:
- /spec/clusterIP
- /spec/clusterIPs
# Ignore webhook CA bundles
- group: admissionregistration.k8s.io
kind: MutatingWebhookConfiguration
jqPathExpressions:
- .webhooks[]?.clientConfig.caBundle
# Ignore Kustomize build metadata
- group: ""
kind: ConfigMap
jsonPointers:
- /metadata/annotations/kubectl.kubernetes.io~1last-applied-configuration
Multi-Cluster Management
Managing applications across multiple Kubernetes clusters.
Key Concepts
- Cluster Registration: Adding external clusters to ArgoCD
- Cluster Credentials: ServiceAccount tokens or kubeconfig
- Destination Server: The API server URL of the target cluster
graph TB
subgraph "ArgoCD Management Cluster"
A[ArgoCD Server]
B[App Controller]
end
subgraph "Production Cluster"
C[Kubernetes API]
D[Production Apps]
end
subgraph "Staging Cluster"
E[Kubernetes API]
F[Staging Apps]
end
subgraph "Development Cluster"
G[Kubernetes API]
H[Dev Apps]
end
A --> B
B --> C
B --> E
B --> G
C --> D
E --> F
G --> H
Common Commands/Patterns
# Add a cluster (uses current kubeconfig context)
argocd cluster add my-cluster-context
# Add cluster with specific name
argocd cluster add my-cluster-context --name production
# Add cluster with service account
argocd cluster add my-cluster-context \
--name production \
--service-account argocd-manager \
--system-namespace kube-system
# List clusters
argocd cluster list
# Get cluster details
argocd cluster get https://production-cluster.example.com
# Rotate cluster credentials
argocd cluster rotate-auth https://production-cluster.example.com
# Remove a cluster
argocd cluster rm https://production-cluster.example.com
Cluster Secret Configuration
# External cluster configuration
apiVersion: v1
kind: Secret
metadata:
name: production-cluster
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
stringData:
name: production
server: https://production-cluster.example.com
config: |
{
"bearerToken": "eyJhbGciOiJSUzI1NiIs...",
"tlsClientConfig": {
"insecure": false,
"caData": "LS0tLS1CRUdJTi..."
}
}
# Cluster with AWS IAM authentication
apiVersion: v1
kind: Secret
metadata:
name: eks-cluster
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
stringData:
name: eks-production
server: https://XXXXX.gr7.eu-west-1.eks.amazonaws.com
config: |
{
"awsAuthConfig": {
"clusterName": "my-eks-cluster",
"roleARN": "arn:aws:iam::123456789012:role/argocd-manager"
},
"tlsClientConfig": {
"insecure": false,
"caData": "LS0tLS1CRUdJTi..."
}
}
Examples
Application targeting external cluster:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-production
namespace: argocd
spec:
project: production
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: overlays/production
destination:
# External cluster server URL
server: https://production-cluster.example.com
namespace: myapp
syncPolicy:
automated:
prune: true
selfHeal: true
Multi-environment deployment with app-of-apps:
# Parent application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-all-envs
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: argocd-apps/
destination:
server: https://kubernetes.default.svc
namespace: argocd
---
# Child applications in argocd-apps/ directory
# argocd-apps/staging.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-staging
namespace: argocd
spec:
project: staging
source:
repoURL: https://github.com/myorg/myapp
targetRevision: develop
path: overlays/staging
destination:
server: https://staging-cluster.example.com
namespace: myapp
---
# argocd-apps/production.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-production
namespace: argocd
spec:
project: production
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: overlays/production
destination:
server: https://production-cluster.example.com
namespace: myapp
ApplicationSet Patterns
ApplicationSets enable automated generation of Applications from templates.
Key Concepts
- Generator: Produces parameters for application templates
- Template: Defines the Application structure with parameter placeholders
- Sync Policy: Controls how generated applications are managed
flowchart TD
subgraph "ApplicationSet"
A[Generator] --> B[Parameters]
B --> C[Template]
C --> D[Generated Applications]
end
D --> E[App: dev-myapp]
D --> F[App: staging-myapp]
D --> G[App: prod-myapp]
Generator Types
List Generator:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: myapp
namespace: argocd
spec:
generators:
- list:
elements:
- cluster: dev
url: https://dev-cluster.example.com
namespace: myapp-dev
- cluster: staging
url: https://staging-cluster.example.com
namespace: myapp-staging
- cluster: production
url: https://production-cluster.example.com
namespace: myapp-prod
template:
metadata:
name: 'myapp-{{cluster}}'
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: 'overlays/{{cluster}}'
destination:
server: '{{url}}'
namespace: '{{namespace}}'
Git Generator (Directory):
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-addons
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/myorg/cluster-addons
revision: main
directories:
- path: addons/*
- path: addons/exclude/*
exclude: true
template:
metadata:
name: '{{path.basename}}'
spec:
project: default
source:
repoURL: https://github.com/myorg/cluster-addons
targetRevision: main
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{path.basename}}'
Git Generator (Files):
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: myapp-envs
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/myorg/myapp
revision: main
files:
- path: "config/**/config.json"
template:
metadata:
name: 'myapp-{{environment}}'
labels:
env: '{{environment}}'
team: '{{team}}'
spec:
project: '{{project}}'
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: 'overlays/{{environment}}'
helm:
values: |
image:
tag: {{image.tag}}
destination:
server: '{{cluster.server}}'
namespace: '{{namespace}}'
Cluster Generator:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: monitoring
namespace: argocd
spec:
generators:
- clusters:
selector:
matchLabels:
monitoring: enabled
values:
revision: main
template:
metadata:
name: 'monitoring-{{name}}'
spec:
project: infrastructure
source:
repoURL: https://github.com/myorg/monitoring
targetRevision: '{{values.revision}}'
path: stack
destination:
server: '{{server}}'
namespace: monitoring
Matrix Generator (Combining Generators):
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: myapp-matrix
namespace: argocd
spec:
generators:
- matrix:
generators:
- git:
repoURL: https://github.com/myorg/myapp
revision: main
directories:
- path: apps/*
- clusters:
selector:
matchLabels:
environment: production
template:
metadata:
name: '{{path.basename}}-{{name}}'
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: '{{path}}'
destination:
server: '{{server}}'
namespace: '{{path.basename}}'
Merge Generator:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: myapp-merge
namespace: argocd
spec:
generators:
- merge:
mergeKeys:
- cluster
generators:
- clusters:
values:
version: default
- list:
elements:
- cluster: production
version: v1.2.3
- cluster: staging
version: latest
template:
metadata:
name: 'myapp-{{name}}'
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp
targetRevision: '{{values.version}}'
path: manifests
destination:
server: '{{server}}'
namespace: myapp
ApplicationSet Sync Policy
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: myapp
namespace: argocd
spec:
generators:
- list:
elements:
- env: dev
- env: staging
- env: prod
template:
metadata:
name: 'myapp-{{env}}'
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp
targetRevision: main
path: 'overlays/{{env}}'
destination:
server: https://kubernetes.default.svc
namespace: 'myapp-{{env}}'
syncPolicy:
# Preserve resources when ApplicationSet is deleted
preserveResourcesOnDeletion: true
# Application sync policy
applicationsSync: create-update
Examples
Progressive delivery ApplicationSet:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: myapp-progressive
namespace: argocd
spec:
generators:
- list:
elements:
- env: dev
autosync: "true"
branch: develop
- env: staging
autosync: "true"
branch: main
- env: production
autosync: "false"
branch: main
template:
metadata:
name: 'myapp-{{env}}'
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.slack: deployments
spec:
project: '{{env}}'
source:
repoURL: https://github.com/myorg/myapp
targetRevision: '{{branch}}'
path: 'overlays/{{env}}'
destination:
server: https://kubernetes.default.svc
namespace: 'myapp-{{env}}'
syncPolicy:
automated:
prune: '{{autosync}}'
selfHeal: '{{autosync}}'
Common Troubleshooting Scenarios
Diagnosing and resolving common ArgoCD issues.
Key Concepts
- Application Logs: Logs from ArgoCD components
- Events: Kubernetes events related to ArgoCD resources
- Sync Failures: Common causes and solutions
Common Commands/Patterns
# View ArgoCD server logs
kubectl logs -n argocd deployment/argocd-server -f
# View application controller logs
kubectl logs -n argocd deployment/argocd-application-controller -f
# View repo server logs
kubectl logs -n argocd deployment/argocd-repo-server -f
# Get application events
kubectl get events -n argocd --field-selector involvedObject.name=myapp
# Describe application
kubectl describe application myapp -n argocd
# Get sync operation details
argocd app get myapp --show-operation
# Get resource tree
argocd app resources myapp --tree
# Check cluster connectivity
argocd cluster get https://production-cluster.example.com
# Validate application manifest
argocd app create myapp --dry-run --validate -f application.yaml
# Debug repository access
argocd repo get https://github.com/myorg/myapp
Common Issues and Solutions
| Issue | Cause | Solution |
|---|---|---|
ComparisonError: failed to unmarshal |
Invalid YAML/JSON in manifests | Validate manifests with kubectl apply --dry-run=client |
rpc error: code = Unknown desc = authentication required |
Invalid or expired repository credentials | Update repository credentials in ArgoCD |
Unable to create application: permission denied |
Project restrictions | Check AppProject source repos and destinations |
Sync failed: context deadline exceeded |
Slow repository clone or large manifests | Increase timeout or optimise repository |
Namespace not found |
Target namespace doesn't exist | Add CreateNamespace=true sync option |
Resource already exists |
Resource managed by another tool | Use Replace=true sync option or resolve ownership |
OutOfSync but sync shows no changes |
Ignored differences or cache issue | Hard refresh or check ignoreDifferences |
Unknown health status |
Custom resource without health check | Add custom health check in argocd-cm |
Cluster connection failed |
Network or credential issues | Check cluster secret and network connectivity |
Invalid Helm chart |
Chart validation failure | Run helm lint and helm template locally |
Debugging Tips
# Reset application to force re-sync
argocd app sync myapp --force
# Terminate stuck operation
argocd app terminate-op myapp
# Clear repository cache
kubectl delete secret -n argocd -l argocd.argoproj.io/secret-type=repository
# Restart ArgoCD components
kubectl rollout restart deployment -n argocd argocd-server
kubectl rollout restart deployment -n argocd argocd-repo-server
kubectl rollout restart deployment -n argocd argocd-application-controller
# Check Redis connection
kubectl exec -it -n argocd deployment/argocd-redis -- redis-cli ping
# Verify RBAC configuration
argocd admin rbac validate -f argocd-rbac-cm.yaml
# Export application for debugging
argocd app get myapp -o yaml > myapp-export.yaml
# Check application conditions
kubectl get application myapp -n argocd -o jsonpath='{.status.conditions}'
Log Analysis
# Find sync errors in controller logs
kubectl logs -n argocd deployment/argocd-application-controller | grep -i error
# Find authentication issues
kubectl logs -n argocd deployment/argocd-repo-server | grep -i "auth\|permission\|denied"
# Monitor real-time sync activity
kubectl logs -n argocd deployment/argocd-application-controller -f | grep myapp
# Check for resource conflicts
kubectl logs -n argocd deployment/argocd-application-controller | grep "already exists"
Examples
Troubleshooting repository issues:
# Test repository access
argocd repo get https://github.com/myorg/myapp
# Re-add repository with debugging
argocd repo add https://github.com/myorg/myapp \
--username myuser \
--password mytoken \
--insecure-skip-server-verification
# Check repository secret
kubectl get secret -n argocd -l argocd.argoproj.io/secret-type=repository
# View repo server manifest generation
argocd app manifests myapp --source live
argocd app manifests myapp --source git
Troubleshooting sync issues:
# Get detailed sync status
argocd app get myapp --show-operation
# View sync result
kubectl get application myapp -n argocd -o jsonpath='{.status.operationState}'
# Check for resource pruning issues
argocd app sync myapp --prune --dry-run
# Sync with verbose output
argocd app sync myapp --verbose
Quick Reference
| Command | Description |
|---|---|
argocd login <server> |
Login to ArgoCD server |
argocd app create <name> |
Create an application |
argocd app get <name> |
Get application details |
argocd app list |
List all applications |
argocd app sync <name> |
Sync an application |
argocd app diff <name> |
Show application diff |
argocd app delete <name> |
Delete an application |
argocd app history <name> |
Show application history |
argocd app rollback <name> <id> |
Rollback to previous version |
argocd app resources <name> |
List application resources |
argocd app set <name> |
Update application settings |
argocd repo add <url> |
Add a Git repository |
argocd repo list |
List repositories |
argocd cluster add <context> |
Add a cluster |
argocd cluster list |
List clusters |
argocd proj create <name> |
Create a project |
argocd proj list |
List projects |
argocd account list |
List accounts |
argocd admin settings resource-overrides |
View resource customisations |
Useful Flags
| Flag | Description |
|---|---|
--grpc-web |
Use gRPC-web protocol |
--insecure |
Skip TLS verification |
-o json/yaml/wide |
Output format |
--refresh |
Force cache refresh |
--hard-refresh |
Invalidate cache completely |
--prune |
Remove resources not in Git |
--dry-run |
Preview changes without applying |
--force |
Force resource updates |
--async |
Don't wait for operation to complete |
--cascade |
Delete resources when deleting app |
Sync Status Values
| Status | Description |
|---|---|
| Synced | Live state matches desired state |
| OutOfSync | Live state differs from desired state |
| Unknown | Sync status cannot be determined |
Health Status Values
| Status | Description |
|---|---|
| Healthy | All resources are healthy |
| Progressing | Resources are in progress |
| Degraded | One or more resources are degraded |
| Suspended | Resources are suspended |
| Missing | Resources are missing |
| Unknown | Health cannot be determined |
Related Topics
The following topics complement ArgoCD and are commonly used together in GitOps workflows:
- Kubernetes - Understanding Kubernetes resources is essential for effective ArgoCD application management
- Helm - ArgoCD natively supports Helm charts as application sources for templated deployments
- Kustomize - ArgoCD supports Kustomize overlays for environment-specific configurations
- git - Fundamental for GitOps workflows and understanding repository operations
- Prometheus/Grafana - Monitoring ArgoCD metrics and creating dashboards for deployment visibility
- CI/CD Patterns - Understanding continuous integration workflows that feed into ArgoCD deployments