Services

ArgoCD

Declarative GitOps continuous delivery tool for Kubernetes


ArgoCD is the most popular GitOps continuous delivery tool for Kubernetes. It automates the deployment of applications to specified target environments, ensuring clusters match the desired state defined in Git.

What you'll learn

Related tools

Why ArgoCD?#

ArgoCD brings declarative, GitOps-based continuous delivery to Kubernetes with enterprise-grade features:

FeatureBenefit
Rich Web UIVisual application topology and real-time sync status
Multi-clusterDeploy to multiple clusters from a single control plane
SSO IntegrationOIDC, SAML, LDAP, GitHub, GitLab authentication
RBACFine-grained access control with projects and roles
Auto-syncAutomatic deployment when Git changes
Self-healingDetect and correct configuration drift

Architecture#

1
┌─────────────────────────────────────────────────────────────────┐
2
│ ArgoCD Components │
3
│ │
4
│ ┌─────────────────┐ ┌─────────────────┐ │
5
│ │ API Server │◄───►│ Web UI │ │
6
│ │ (gRPC/REST) │ │ (Dashboard) │ │
7
│ └────────┬────────┘ └─────────────────┘ │
8
│ │ │
9
│ ┌────────▼────────┐ ┌─────────────────┐ │
10
│ │ Repo Server │ │ Application │ │
11
│ │ (Git/Helm/Kust) │ │ Controller │ │
12
│ └─────────────────┘ └────────┬────────┘ │
13
│ │ │
14
│ ┌─────────────────┐ ┌────────▼────────┐ │
15
│ │ Dex (SSO) │ │ Redis Cache │ │
16
│ └─────────────────┘ └─────────────────┘ │
17
└─────────────────────────────────────────────────────────────────┘

Components#

API Server Exposes the ArgoCD API as gRPC and REST endpoints. Handles authentication, RBAC enforcement, and serves the Web UI.

Repository Server Connects to Git repositories and generates Kubernetes manifests. Supports Helm, Kustomize, Jsonnet, and plain YAML.

Application Controller Monitors running applications and compares the current state against the desired state. Triggers sync operations and manages lifecycle.

Redis Caches Git repository state and application manifests for improved performance.

Dex Provides SSO integration with external identity providers.


Installation#

1
#!/bin/bash
2
# ArgoCD installation script
3
4
# Create namespace
5
kubectl create namespace argocd
6
7
# Add ArgoCD Helm repository
8
helm repo add argo https://argoproj.github.io/argo-helm
9
helm repo update
10
11
# Install ArgoCD with custom values
12
helm install argocd argo/argo-cd \
13
--namespace argocd \
14
--values argocd-values.yaml \
15
--wait
16
17
# Get initial admin password
18
kubectl -n argocd get secret argocd-initial-admin-secret \
19
-o jsonpath="{.data.password}" | base64 -d
20
21
echo "ArgoCD installed successfully"

Helm Values Configuration#

1
# argocd-values.yaml
2
global:
3
image:
4
repository: quay.io/argoproj/argocd
5
tag: v2.9.3
6
7
server:
8
replicas: 2
9
10
ingress:
11
enabled: true
12
ingressClassName: nginx
13
hosts:
14
- argocd.example.com
15
tls:
16
- secretName: argocd-tls
17
hosts:
18
- argocd.example.com
19
20
config:
21
url: https://argocd.example.com
22
application.instanceLabelKey: argocd.argoproj.io/instance
23
24
# OIDC configuration
25
oidc.config: |
26
name: Okta
27
issuer: https://company.okta.com/oauth2/default
28
clientID: $oidc.clientId
29
clientSecret: $oidc.clientSecret
30
requestedScopes: ["openid", "profile", "email", "groups"]
31
32
# Repository credentials
33
repositories: |
34
- url: https://github.com/company/gitops-repo.git
35
passwordSecret:
36
name: github-creds
37
key: password
38
usernameSecret:
39
name: github-creds
40
key: username
41
42
rbacConfig:
43
policy.csv: |
44
p, role:org-admin, applications, *, */*, allow
45
p, role:org-admin, clusters, *, *, allow
46
p, role:org-admin, repositories, *, *, allow
47
p, role:developer, applications, get, */*, allow
48
p, role:developer, applications, sync, */*, allow
49
p, role:developer, logs, get, */*, allow
50
g, DevOps, role:org-admin
51
g, Developers, role:developer
52
policy.default: role:readonly
53
54
controller:
55
replicas: 1
56
resources:
57
requests:
58
cpu: 500m
59
memory: 512Mi
60
limits:
61
cpu: 1000m
62
memory: 1Gi
63
64
repoServer:
65
replicas: 2
66
resources:
67
requests:
68
cpu: 250m
69
memory: 256Mi
70
limits:
71
cpu: 500m
72
memory: 512Mi
73
74
redis:
75
enabled: true
76
resources:
77
requests:
78
cpu: 100m
79
memory: 128Mi
80
81
dex:
82
enabled: true
83
84
applicationSet:
85
enabled: true
86
replicas: 1
87
88
notifications:
89
enabled: true
90
argocdUrl: https://argocd.example.com
91
92
notifiers:
93
service.slack: |
94
token: $slack-token
95
service.webhook.github: |
96
url: https://api.github.com
97
headers:
98
- name: Authorization
99
value: token $github-token
100
101
triggers:
102
trigger.on-sync-succeeded: |
103
- when: app.status.sync.status == 'Synced'
104
send: [app-sync-succeeded]
105
trigger.on-sync-failed: |
106
- when: app.status.sync.status == 'Unknown'
107
send: [app-sync-failed]
108
109
templates:
110
template.app-sync-succeeded: |
111
slack:
112
attachments: |
113
[{
114
"color": "#18be52",
115
"title": "{{.app.metadata.name}} synced successfully",
116
"fields": [{
117
"title": "Repository",
118
"value": "{{.app.spec.source.repoURL}}",
119
"short": true
120
}]
121
}]

Application Definitions#

Single Application#

1
# applications/payment-service.yaml
2
apiVersion: argoproj.io/v1alpha1
3
kind: Application
4
metadata:
5
name: payment-service
6
namespace: argocd
7
labels:
8
team: payments
9
environment: production
10
annotations:
11
notifications.argoproj.io/subscribe.on-sync-succeeded.slack: payments-deploys
12
notifications.argoproj.io/subscribe.on-sync-failed.slack: payments-alerts
13
finalizers:
14
- resources-finalizer.argocd.argoproj.io
15
spec:
16
project: payments
17
18
source:
19
repoURL: https://github.com/company/gitops-repo.git
20
targetRevision: main
21
path: apps/payment-service/overlays/production
22
23
destination:
24
server: https://kubernetes.default.svc
25
namespace: payments
26
27
syncPolicy:
28
automated:
29
prune: true
30
selfHeal: true
31
allowEmpty: false
32
syncOptions:
33
- CreateNamespace=true
34
- PrunePropagationPolicy=foreground
35
- PruneLast=true
36
- ApplyOutOfSyncOnly=true
37
retry:
38
limit: 5
39
backoff:
40
duration: 5s
41
factor: 2
42
maxDuration: 3m
43
44
ignoreDifferences:
45
- group: apps
46
kind: Deployment
47
jsonPointers:
48
- /spec/replicas
49
- group: ""
50
kind: ConfigMap
51
jqPathExpressions:
52
- .data.webhook-url
53
54
revisionHistoryLimit: 10

Helm Application#

1
apiVersion: argoproj.io/v1alpha1
2
kind: Application
3
metadata:
4
name: prometheus-stack
5
namespace: argocd
6
spec:
7
project: infrastructure
8
9
source:
10
repoURL: https://prometheus-community.github.io/helm-charts
11
chart: kube-prometheus-stack
12
targetRevision: 55.0.0
13
helm:
14
releaseName: prometheus
15
valueFiles:
16
- values.yaml
17
- values-production.yaml
18
parameters:
19
- name: grafana.adminPassword
20
value: $grafana-admin-password
21
values: |
22
prometheus:
23
prometheusSpec:
24
retention: 30d
25
26
destination:
27
server: https://kubernetes.default.svc
28
namespace: monitoring
29
30
syncPolicy:
31
automated:
32
prune: true
33
selfHeal: true

App of Apps Pattern#

The App of Apps pattern enables managing multiple applications through a single parent application.

1
# applications/root-app.yaml
2
apiVersion: argoproj.io/v1alpha1
3
kind: Application
4
metadata:
5
name: root-application
6
namespace: argocd
7
spec:
8
project: default
9
10
source:
11
repoURL: https://github.com/company/gitops-repo.git
12
targetRevision: main
13
path: applications
14
directory:
15
recurse: true
16
17
destination:
18
server: https://kubernetes.default.svc
19
namespace: argocd
20
21
syncPolicy:
22
automated:
23
prune: true
24
selfHeal: true

Environment-Specific Apps#

1
# applications/apps/production-apps.yaml
2
apiVersion: argoproj.io/v1alpha1
3
kind: Application
4
metadata:
5
name: production-applications
6
namespace: argocd
7
spec:
8
project: production
9
10
source:
11
repoURL: https://github.com/company/gitops-repo.git
12
targetRevision: main
13
path: environments/production
14
15
destination:
16
server: https://prod-cluster.example.com
17
namespace: argocd
18
19
syncPolicy:
20
automated:
21
prune: true
22
selfHeal: true

ApplicationSets#

ApplicationSets automate the creation of Applications based on generators.

Multi-Environment Deployment#

1
apiVersion: argoproj.io/v1alpha1
2
kind: ApplicationSet
3
metadata:
4
name: microservices
5
namespace: argocd
6
spec:
7
generators:
8
- matrix:
9
generators:
10
# Cluster generator
11
- clusters:
12
selector:
13
matchLabels:
14
environment: production
15
# Git directory generator
16
- git:
17
repoURL: https://github.com/company/gitops-repo.git
18
revision: main
19
directories:
20
- path: apps/*
21
22
template:
23
metadata:
24
name: '{{path.basename}}-{{name}}'
25
labels:
26
app: '{{path.basename}}'
27
cluster: '{{name}}'
28
spec:
29
project: production
30
31
source:
32
repoURL: https://github.com/company/gitops-repo.git
33
targetRevision: main
34
path: '{{path}}/overlays/{{metadata.labels.environment}}'
35
36
destination:
37
server: '{{server}}'
38
namespace: '{{path.basename}}'
39
40
syncPolicy:
41
automated:
42
prune: true
43
selfHeal: true
44
syncOptions:
45
- CreateNamespace=true

Pull Request Preview Environments#

1
apiVersion: argoproj.io/v1alpha1
2
kind: ApplicationSet
3
metadata:
4
name: pr-preview-environments
5
namespace: argocd
6
spec:
7
generators:
8
- pullRequest:
9
github:
10
owner: company
11
repo: application
12
tokenRef:
13
secretName: github-token
14
key: token
15
labels:
16
- preview
17
requeueAfterSeconds: 60
18
19
template:
20
metadata:
21
name: 'pr-{{number}}-{{branch_slug}}'
22
annotations:
23
preview-url: 'https://pr-{{number}}.preview.example.com'
24
spec:
25
project: preview
26
27
source:
28
repoURL: https://github.com/company/application.git
29
targetRevision: '{{head_sha}}'
30
path: deploy/preview
31
helm:
32
parameters:
33
- name: ingress.host
34
value: 'pr-{{number}}.preview.example.com'
35
- name: image.tag
36
value: 'pr-{{number}}'
37
38
destination:
39
server: https://kubernetes.default.svc
40
namespace: 'preview-{{number}}'
41
42
syncPolicy:
43
automated:
44
prune: true
45
selfHeal: true
46
syncOptions:
47
- CreateNamespace=true

List Generator#

1
apiVersion: argoproj.io/v1alpha1
2
kind: ApplicationSet
3
metadata:
4
name: team-applications
5
namespace: argocd
6
spec:
7
generators:
8
- list:
9
elements:
10
- team: payments
11
apps: ["payment-api", "payment-worker", "payment-scheduler"]
12
- team: users
13
apps: ["user-api", "auth-service"]
14
- team: orders
15
apps: ["order-api", "inventory-service"]
16
17
template:
18
metadata:
19
name: '{{team}}-apps'
20
spec:
21
project: '{{team}}'
22
source:
23
repoURL: https://github.com/company/{{team}}-services.git
24
targetRevision: main
25
path: deploy
26
destination:
27
server: https://kubernetes.default.svc
28
namespace: '{{team}}'

Projects#

Projects provide logical grouping of applications with access control.

1
apiVersion: argoproj.io/v1alpha1
2
kind: AppProject
3
metadata:
4
name: payments
5
namespace: argocd
6
spec:
7
description: "Payments team applications"
8
9
# Source repositories allowed
10
sourceRepos:
11
- https://github.com/company/payments-*.git
12
- https://github.com/company/shared-charts.git
13
14
# Destination clusters and namespaces
15
destinations:
16
- namespace: payments-*
17
server: https://kubernetes.default.svc
18
- namespace: payments
19
server: https://prod-cluster.example.com
20
21
# Allowed Kubernetes resources
22
clusterResourceWhitelist:
23
- group: ''
24
kind: Namespace
25
- group: 'networking.k8s.io'
26
kind: Ingress
27
28
namespaceResourceBlacklist:
29
- group: ''
30
kind: Secret
31
name: 'production-*'
32
33
namespaceResourceWhitelist:
34
- group: 'apps'
35
kind: Deployment
36
- group: 'apps'
37
kind: StatefulSet
38
- group: ''
39
kind: Service
40
- group: ''
41
kind: ConfigMap
42
- group: ''
43
kind: Secret
44
- group: 'batch'
45
kind: Job
46
- group: 'batch'
47
kind: CronJob
48
49
# Roles within the project
50
roles:
51
- name: developer
52
description: Developer access to payments project
53
policies:
54
- p, proj:payments:developer, applications, get, payments/*, allow
55
- p, proj:payments:developer, applications, sync, payments/*, allow
56
- p, proj:payments:developer, applications, action/*, payments/*, allow
57
- p, proj:payments:developer, logs, get, payments/*, allow
58
groups:
59
- payments-developers
60
61
- name: admin
62
description: Admin access to payments project
63
policies:
64
- p, proj:payments:admin, applications, *, payments/*, allow
65
- p, proj:payments:admin, repositories, *, payments/*, allow
66
groups:
67
- payments-admins
68
69
# Sync windows for controlled deployments
70
syncWindows:
71
- kind: allow
72
schedule: '0 6-18 * * 1-5' # Weekdays 6am-6pm
73
duration: 12h
74
applications:
75
- '*'
76
namespaces:
77
- '*'
78
- kind: deny
79
schedule: '0 18-6 * * *' # Nights
80
duration: 12h
81
applications:
82
- '*-production'
83
manualSync: true
84
85
# Orphaned resources monitoring
86
orphanedResources:
87
warn: true
88
ignore:
89
- group: ''
90
kind: ConfigMap
91
name: kube-root-ca.crt

Argo Rollouts Integration#

Argo Rollouts provides progressive delivery strategies for ArgoCD.

Canary Deployment#

1
apiVersion: argoproj.io/v1alpha1
2
kind: Rollout
3
metadata:
4
name: payment-service
5
namespace: payments
6
spec:
7
replicas: 10
8
revisionHistoryLimit: 5
9
10
selector:
11
matchLabels:
12
app: payment-service
13
14
template:
15
metadata:
16
labels:
17
app: payment-service
18
spec:
19
containers:
20
- name: payment-service
21
image: company/payment-service:v1.0.0
22
ports:
23
- containerPort: 8080
24
resources:
25
requests:
26
cpu: 100m
27
memory: 128Mi
28
limits:
29
cpu: 500m
30
memory: 512Mi
31
livenessProbe:
32
httpGet:
33
path: /health
34
port: 8080
35
initialDelaySeconds: 30
36
periodSeconds: 10
37
readinessProbe:
38
httpGet:
39
path: /ready
40
port: 8080
41
initialDelaySeconds: 5
42
periodSeconds: 5
43
44
strategy:
45
canary:
46
# Traffic routing with Istio
47
trafficRouting:
48
istio:
49
virtualService:
50
name: payment-service-vsvc
51
routes:
52
- primary
53
destinationRule:
54
name: payment-service-destrule
55
canarySubsetName: canary
56
stableSubsetName: stable
57
58
# Canary steps
59
steps:
60
- setWeight: 5
61
- pause: { duration: 2m }
62
- setWeight: 10
63
- pause: { duration: 5m }
64
- setWeight: 25
65
- pause: { duration: 10m }
66
- setWeight: 50
67
- pause: { duration: 15m }
68
- setWeight: 75
69
- pause: { duration: 10m }
70
- setWeight: 100
71
72
# Analysis for automated promotion/rollback
73
analysis:
74
templates:
75
- templateName: success-rate
76
- templateName: latency
77
startingStep: 2
78
args:
79
- name: service-name
80
value: payment-service
81
82
maxUnavailable: 1
83
maxSurge: 2

Analysis Templates#

1
apiVersion: argoproj.io/v1alpha1
2
kind: AnalysisTemplate
3
metadata:
4
name: success-rate
5
namespace: payments
6
spec:
7
args:
8
- name: service-name
9
metrics:
10
- name: success-rate
11
interval: 1m
12
count: 10
13
successCondition: result[0] >= 0.99
14
failureLimit: 3
15
provider:
16
prometheus:
17
address: http://prometheus.monitoring:9090
18
query: |
19
sum(rate(
20
http_requests_total{
21
service="{{args.service-name}}",
22
status=~"2.."
23
}[5m]
24
)) / sum(rate(
25
http_requests_total{
26
service="{{args.service-name}}"
27
}[5m]
28
))
29
30
---
31
apiVersion: argoproj.io/v1alpha1
32
kind: AnalysisTemplate
33
metadata:
34
name: latency
35
namespace: payments
36
spec:
37
args:
38
- name: service-name
39
metrics:
40
- name: p99-latency
41
interval: 1m
42
count: 10
43
successCondition: result[0] <= 500
44
failureLimit: 3
45
provider:
46
prometheus:
47
address: http://prometheus.monitoring:9090
48
query: |
49
histogram_quantile(0.99,
50
sum(rate(
51
http_request_duration_seconds_bucket{
52
service="{{args.service-name}}"
53
}[5m]
54
)) by (le)
55
) * 1000

Blue-Green Deployment#

1
apiVersion: argoproj.io/v1alpha1
2
kind: Rollout
3
metadata:
4
name: payment-api-bluegreen
5
namespace: payments
6
spec:
7
replicas: 5
8
9
selector:
10
matchLabels:
11
app: payment-api
12
13
template:
14
metadata:
15
labels:
16
app: payment-api
17
spec:
18
containers:
19
- name: payment-api
20
image: company/payment-api:v2.0.0
21
ports:
22
- containerPort: 8080
23
24
strategy:
25
blueGreen:
26
activeService: payment-api-active
27
previewService: payment-api-preview
28
autoPromotionEnabled: false
29
scaleDownDelaySeconds: 300
30
previewReplicaCount: 2
31
prePromotionAnalysis:
32
templates:
33
- templateName: smoke-tests
34
args:
35
- name: service-name
36
value: payment-api-preview
37
postPromotionAnalysis:
38
templates:
39
- templateName: success-rate
40
args:
41
- name: service-name
42
value: payment-api-active

Notifications#

Configure notifications for deployment events.

1
apiVersion: v1
2
kind: ConfigMap
3
metadata:
4
name: argocd-notifications-cm
5
namespace: argocd
6
data:
7
service.slack: |
8
token: $slack-token
9
10
template.app-deployed: |
11
message: |
12
Application {{.app.metadata.name}} is now running version {{.app.status.sync.revision}}.
13
slack:
14
attachments: |
15
[{
16
"color": "#18be52",
17
"title": "{{.app.metadata.name}}",
18
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
19
"fields": [{
20
"title": "Sync Status",
21
"value": "{{.app.status.sync.status}}",
22
"short": true
23
}, {
24
"title": "Repository",
25
"value": "{{.app.spec.source.repoURL}}",
26
"short": true
27
}]
28
}]
29
30
trigger.on-deployed: |
31
- when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status == 'Healthy'
32
send: [app-deployed]
33
34
trigger.on-sync-failed: |
35
- when: app.status.operationState.phase in ['Failed', 'Error']
36
send: [app-sync-failed]
37
38
template.app-sync-failed: |
39
message: |
40
Application {{.app.metadata.name}} sync failed.
41
Error: {{.app.status.operationState.message}}
42
slack:
43
attachments: |
44
[{
45
"color": "#E96D76",
46
"title": "{{.app.metadata.name}} sync failed",
47
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
48
"fields": [{
49
"title": "Error",
50
"value": "{{.app.status.operationState.message}}",
51
"short": false
52
}]
53
}]

Best Practices#

Repository Structure#

1
gitops-repo/
2
├── apps/
3
│ ├── base/
4
│ │ └── payment-service/
5
│ │ ├── deployment.yaml
6
│ │ ├── service.yaml
7
│ │ └── kustomization.yaml
8
│ └── overlays/
9
│ ├── dev/
10
│ ├── staging/
11
│ └── production/
12
├── infrastructure/
13
│ ├── cert-manager/
14
│ ├── ingress-nginx/
15
│ └── monitoring/
16
├── clusters/
17
│ ├── dev/
18
│ ├── staging/
19
│ └── production/
20
└── applications/
21
├── root-app.yaml
22
└── applicationsets/

Security Recommendations#

  1. Enable RBAC - Use projects and roles to limit access
  2. SSO Integration - Use OIDC/SAML instead of local accounts
  3. Sync Windows - Restrict production deployments to business hours
  4. Secret Management - Use Sealed Secrets or External Secrets Operator
  5. Network Policies - Limit ArgoCD's network access

Performance Tuning#

  1. Repository Caching - Enable Git repository caching
  2. Manifest Generation Caching - Cache rendered manifests
  3. Increase Repo Server Replicas - For large deployments
  4. Resource Limits - Set appropriate limits for controllers