Advanced ArgoCD Features and Patterns
Beyond basic GitOps deployments, ArgoCD provides advanced capabilities for progressive delivery, multi-tenancy, and sophisticated deployment patterns. These features enable complex production scenarios while maintaining the GitOps philosophy.
Progressive Delivery with Argo Rollouts
Argo Rollouts extends Kubernetes deployments with advanced deployment strategies, integrating with ArgoCD for automated progressive delivery.
Canary Deployments
Gradually shift traffic to new versions:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: api-service
namespace: production
spec:
replicas: 5
revisionHistoryLimit: 3
selector:
matchLabels:
app: api-service
template:
metadata:
labels:
app: api-service
spec:
containers:
- name: api
image: registry.example.com/api-service:v2.0.0
ports:
- containerPort: 8080
strategy:
canary:
steps:
- setWeight: 20
- pause: {duration: 5m}
- analysis:
templates:
- templateName: success-rate
- setWeight: 50
- pause: {duration: 10m}
- analysis:
templates:
- templateName: success-rate
- templateName: latency
- setWeight: 80
- pause: {duration: 10m}
services:
stable: api-service-stable
canary: api-service-canary
The rollout increases traffic to the new version in stages, pausing between steps to analyze metrics. If analysis fails, automatic rollback occurs.
Analysis Templates
Define metric-based analysis for automated decisions:
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
namespace: production
spec:
metrics:
- name: success-rate
interval: 60s
count: 5
successCondition: result >= 0.95
failureLimit: 2
provider:
prometheus:
address: http://prometheus:9090
query: |
sum(rate(http_requests_total{job="api-service",status=~"2.."}[5m]))
/
sum(rate(http_requests_total{job="api-service"}[5m]))
---
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: latency
namespace: production
spec:
metrics:
- name: p95-latency
interval: 60s
count: 5
successCondition: result <= 500
failureLimit: 2
provider:
prometheus:
address: http://prometheus:9090
query: |
histogram_quantile(0.95,
sum(rate(http_request_duration_seconds_bucket{job="api-service"}[5m])) by (le)
) * 1000
Analysis templates query Prometheus for metrics, evaluating success conditions. Failed analysis triggers automatic rollback.
sequenceDiagram
participant Git
participant ArgoCD
participant Rollout
participant Analysis
participant Prometheus
Git->>ArgoCD: New image version
ArgoCD->>Rollout: Update Rollout spec
Rollout->>Rollout: Deploy canary (20%)
Rollout->>Analysis: Start analysis
loop Every 60 seconds
Analysis->>Prometheus: Query success rate
Prometheus->>Analysis: Return metric
Analysis->>Analysis: Evaluate condition
end
alt Analysis passes
Rollout->>Rollout: Increase weight (50%)
else Analysis fails
Rollout->>Rollout: Rollback to stable
end
Blue-Green Deployments
Deploy new version alongside old, then switch traffic:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: api-service
spec:
replicas: 5
strategy:
blueGreen:
activeService: api-service-active
previewService: api-service-preview
autoPromotionEnabled: false
scaleDownDelaySeconds: 300
selector:
matchLabels:
app: api-service
template:
metadata:
labels:
app: api-service
spec:
containers:
- name: api
image: registry.example.com/api-service:v2.0.0
Blue-green deploys the new version to separate pods, allowing validation before switching the active service. Manual or automatic promotion controls the cutover.
# Promote blue-green deployment
kubectl argo rollouts promote api-service
# Abort rollout (switch back to previous version)
kubectl argo rollouts abort api-service
Resource Hooks
Execute actions at specific points in the sync lifecycle using resource hooks.
Pre-Sync Hooks
Run tasks before applying manifests:
apiVersion: batch/v1
kind: Job
metadata:
name: database-migration
namespace: production
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
template:
spec:
containers:
- name: migrate
image: registry.example.com/migrations:v2.0.0
command:
- /bin/sh
- -c
- |
echo "Running database migrations..."
/migrations/migrate up
restartPolicy: Never
backoffLimit: 2
Pre-sync hooks run database migrations, configuration validation, or backups before deploying application changes.
Post-Sync Hooks
Execute tasks after successful sync:
apiVersion: batch/v1
kind: Job
metadata:
name: smoke-tests
namespace: production
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: test
image: registry.example.com/smoke-tests:latest
command:
- /bin/sh
- -c
- |
echo "Running smoke tests..."
/tests/smoke-test.sh
restartPolicy: Never
backoffLimit: 1
Post-sync hooks validate deployments, send notifications, or trigger downstream processes after successful application sync.
Sync Waves
Control resource creation order:
# Create namespace first (wave 0)
apiVersion: v1
kind: Namespace
metadata:
name: production
annotations:
argocd.argoproj.io/sync-wave: "0"
---
# Create secrets next (wave 1)
apiVersion: v1
kind: Secret
metadata:
name: database-credentials
namespace: production
annotations:
argocd.argoproj.io/sync-wave: "1"
---
# Deploy database (wave 2)
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgresql
namespace: production
annotations:
argocd.argoproj.io/sync-wave: "2"
---
# Deploy application last (wave 3)
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-service
namespace: production
annotations:
argocd.argoproj.io/sync-wave: "3"
Sync waves ensure resources deploy in dependency order, preventing failures from missing prerequisites.
graph TD
A[Wave 0: Namespace] --> B[Wave 1: Secrets]
B --> C[Wave 2: Database]
C --> D[Wave 3: Application]
style A fill:#e1f5ff
style B fill:#e8f4f8
style C fill:#f0f7fa
style D fill:#f8fbfc
Multi-Tenancy Patterns
Support multiple teams or customers with isolated ArgoCD environments.
Project-Based Isolation
Restrict resources and repositories per project:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: team-frontend
namespace: argocd
spec:
description: Frontend team applications
# Only these repositories
sourceRepos:
- https://github.com/organization/frontend-*
# Only these namespaces
destinations:
- namespace: frontend-dev
server: https://kubernetes.default.svc
- namespace: frontend-staging
server: https://kubernetes.default.svc
- namespace: frontend-prod
server: https://kubernetes.default.svc
# Denied cluster-scoped resources
clusterResourceBlacklist:
- group: ''
kind: Namespace
- group: rbac.authorization.k8s.io
kind: ClusterRole
# Allowed namespace-scoped resources
namespaceResourceWhitelist:
- group: apps
kind: Deployment
- group: ''
kind: Service
- group: networking.k8s.io
kind: Ingress
# RBAC roles
roles:
- name: developer
description: Frontend developers
policies:
- p, proj:team-frontend:developer, applications, get, team-frontend/*, allow
- p, proj:team-frontend:developer, applications, sync, team-frontend/*, allow
- p, proj:team-frontend:developer, applications, create, team-frontend/*, allow
groups:
- frontend-developers
- name: admin
description: Frontend team leads
policies:
- p, proj:team-frontend:admin, applications, *, team-frontend/*, allow
groups:
- frontend-leads
Projects enforce boundaries, ensuring teams only access their repositories, namespaces, and resource types.
ApplicationSet for Multi-Tenancy
Generate applications per team:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: team-applications
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/organization/team-configs
revision: main
files:
- path: "teams/*/config.json"
template:
metadata:
name: '{{team}}-app'
spec:
project: '{{team}}'
source:
repoURL: '{{repoURL}}'
targetRevision: main
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{team}}-{{environment}}'
syncPolicy:
automated:
prune: true
selfHeal: true
Team configuration files define parameters:
{
"team": "frontend",
"repoURL": "https://github.com/organization/frontend-manifests",
"path": "kubernetes",
"environment": "production"
}
ApplicationSet dynamically creates applications as teams add configuration files, automating onboarding.
Secrets Management Integration
Integrate with external secret management systems for secure credential handling.
External Secrets Operator
Fetch secrets from external systems:
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
namespace: production
spec:
provider:
vault:
server: "https://vault.example.com"
path: "secret"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "argocd-app"
serviceAccountRef:
name: argocd-application-controller
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: api-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: api-credentials
creationPolicy: Owner
data:
- secretKey: api-key
remoteRef:
key: production/api-service
property: api-key
- secretKey: database-password
remoteRef:
key: production/database
property: password
External Secrets Operator fetches credentials from HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault, syncing them into Kubernetes secrets automatically.
Sealed Secrets Integration
Encrypt secrets before storing in Git:
# Install kubeseal
wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.18.0/kubeseal-linux-amd64
sudo install -m 755 kubeseal-linux-amd64 /usr/local/bin/kubeseal
# Create secret manifest
kubectl create secret generic api-credentials \
--from-literal=api-key=secret-value \
--dry-run=client -o yaml > secret.yaml
# Seal the secret
kubeseal -f secret.yaml -w sealed-secret.yaml
# Commit sealed secret to Git
git add sealed-secret.yaml
git commit -m "Add API credentials"
git push
The sealed secret decrypts only in the target cluster, allowing safe storage in Git repositories.
Notification Integrations
Configure notifications for deployment events and status changes.
Slack Notifications
Send sync status to Slack channels:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.slack: |
token: $slack-token
trigger.on-deployed: |
- when: app.status.operationState.phase in ['Succeeded']
send: [app-deployed]
trigger.on-health-degraded: |
- when: app.status.health.status == 'Degraded'
send: [app-health-degraded]
trigger.on-sync-failed: |
- when: app.status.operationState.phase in ['Error', 'Failed']
send: [app-sync-failed]
template.app-deployed: |
message: |
Application {{.app.metadata.name}} deployed successfully!
Environment: {{.app.spec.destination.namespace}}
Revision: {{.app.status.sync.revision}}
Author: {{(call .repo.GetCommitMetadata .app.status.sync.revision).Author}}
slack:
attachments: |
[{
"title": "{{.app.metadata.name}}",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "good",
"fields": [
{"title": "Sync Status", "value": "{{.app.status.sync.status}}", "short": true},
{"title": "Health", "value": "{{.app.status.health.status}}", "short": true}
]
}]
template.app-health-degraded: |
message: |
Application {{.app.metadata.name}} health degraded!
Environment: {{.app.spec.destination.namespace}}
slack:
attachments: |
[{
"title": "{{.app.metadata.name}}",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "danger",
"fields": [
{"title": "Health Status", "value": "{{.app.status.health.status}}", "short": true}
]
}]
template.app-sync-failed: |
message: |
Failed to sync application {{.app.metadata.name}}
Error: {{.app.status.operationState.message}}
slack:
attachments: |
[{
"title": "{{.app.metadata.name}}",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "danger"
}]
Configure secret with Slack token:
kubectl create secret generic argocd-notifications-secret \
-n argocd \
--from-literal=slack-token=xoxb-your-slack-token
Subscribe applications to notifications:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: api-service
annotations:
notifications.argoproj.io/subscribe.on-deployed.slack: team-deployments
notifications.argoproj.io/subscribe.on-health-degraded.slack: team-alerts
notifications.argoproj.io/subscribe.on-sync-failed.slack: team-alerts
Webhook Notifications
Trigger external systems on deployment events:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.webhook.deployment-tracker: |
url: https://deployment-tracker.example.com/api/webhooks
headers:
- name: Authorization
value: Bearer $webhook-token
trigger.on-deployed: |
- when: app.status.operationState.phase in ['Succeeded']
send: [track-deployment]
template.track-deployment: |
webhook:
deployment-tracker:
method: POST
body: |
{
"application": "{{.app.metadata.name}}",
"environment": "{{.app.spec.destination.namespace}}",
"revision": "{{.app.status.sync.revision}}",
"timestamp": "{{.app.status.operationState.finishedAt}}",
"author": "{{(call .repo.GetCommitMetadata .app.status.sync.revision).Author}}"
}
Webhooks enable integration with deployment tracking, incident management, or analytics platforms.
ApplicationSet Advanced Generators
Use sophisticated generators for dynamic application creation.
Git Files Generator
Generate applications from files in Git:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: microservices
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/organization/microservices
revision: main
files:
- path: "services/*/service.yaml"
template:
metadata:
name: '{{service.name}}'
spec:
project: default
source:
repoURL: https://github.com/organization/microservices
targetRevision: main
path: 'services/{{service.name}}/manifests'
destination:
server: https://kubernetes.default.svc
namespace: '{{service.namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
Service definition files:
# services/api-service/service.yaml
service:
name: api-service
namespace: production
replicas: 5
Pull Request Generator
Create preview environments for pull requests:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: pr-previews
namespace: argocd
spec:
generators:
- pullRequest:
github:
owner: organization
repo: frontend-app
tokenRef:
secretName: github-token
key: token
requeueAfterSeconds: 60
template:
metadata:
name: 'frontend-pr-{{number}}'
spec:
project: default
source:
repoURL: https://github.com/organization/frontend-app
targetRevision: '{{head_sha}}'
path: kubernetes
destination:
server: https://kubernetes.default.svc
namespace: 'pr-{{number}}'
syncPolicy:
automated:
prune: true
selfHeal: true
ArgoCD automatically creates applications for open pull requests and deletes them when PRs close.
sequenceDiagram
participant Dev as Developer
participant GitHub
participant AppSet as ApplicationSet
participant ArgoCD
participant K8s
Dev->>GitHub: Create Pull Request
GitHub->>GitHub: PR #123 opened
loop Every 60 seconds
AppSet->>GitHub: List open PRs
GitHub->>AppSet: PR #123
AppSet->>ArgoCD: Create Application (pr-123)
end
ArgoCD->>K8s: Deploy to namespace pr-123
Dev->>GitHub: Close Pull Request
loop Every 60 seconds
AppSet->>GitHub: List open PRs
GitHub->>AppSet: (no PR #123)
AppSet->>ArgoCD: Delete Application (pr-123)
end
ArgoCD->>K8s: Delete namespace pr-123
Common Pitfalls
Rollout Without Analysis: Using Argo Rollouts without analysis templates risks promoting bad deployments. Always configure metric-based analysis for automated decisions.
Hook Resource Leaks: Hooks without proper delete policies accumulate over time. Use BeforeHookCreation or HookSucceeded to clean up hook resources.
Over-Permissive Projects: Granting broad cluster-scoped permissions defeats multi-tenancy isolation. Carefully whitelist resource types and namespaces.
Sealed Secrets Key Loss: Losing the sealing key prevents decryption of all sealed secrets. Back up the sealing key to secure storage immediately after installation.
Key Takeaways
- Argo Rollouts enables progressive delivery with canary and blue-green strategies, using analysis templates for automated metric-based decisions
- Resource hooks execute tasks at sync lifecycle points - pre-sync for migrations, post-sync for validation, with sync waves controlling creation order
- Multi-tenancy uses Projects for RBAC boundaries, ApplicationSet for dynamic generation, and resource whitelisting for isolation
- Integrate secrets management with External Secrets Operator for fetching from vaults or Sealed Secrets for encrypted Git storage
- Configure notifications for Slack channels or webhooks to track deployments, health changes, and sync failures
- Advanced ApplicationSet generators create applications from Git files or pull requests, enabling dynamic preview environments
- Always use analysis templates with rollouts, configure hook delete policies, restrict project permissions carefully, and back up sealing keys