Production-grade GitOps patterns: ApplicationSets for multi-env generation, Argo Rollouts for canary and blue-green deployments, Image Updater for automatic tag bumps, and Notifications for Slack alerts on sync events.
Traditional deploy: change image tag → instant switch → if broken, all users affected.
Progressive delivery:
New version built
│
▼
10% of traffic ──► measure error rate + latency
│ healthy? ▼ degraded? rollback ◄──┐
50% of traffic │
│ healthy? ▼ degraded? rollback ─────┘
100% — promotion complete
Real production traffic validates the new version at each step. Automated analysis decides promote or rollback — no human in the loop needed.
Git repo (source of truth)
└── apps/
├── dev/ ──► ArgoCD app: cluster-dev
├── staging/──► ArgoCD app: cluster-staging
└── prod/ ──► ArgoCD app: cluster-prod
│
▼ ApplicationSet generates all three automatically
ArgoCD (cluster-admin)
├── syncs manifests on git push
├── Argo Rollouts controller ──► canary / blue-green traffic splits
└── Image Updater ──► watches Harbor, commits tag bump to git
Without ApplicationSets you'd write one ArgoCD Application per environment.
With ApplicationSets, one template generates all environments from a git directory scan.
# applicationsets/all-envs.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: microservices
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/srujantata/gitops-argocd-advanced.git
revision: HEAD
directories:
- path: apps/* # generates one Application per subdirectory
template:
metadata:
name: "{{path.basename}}" # app name = directory name
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.slack: deployments
spec:
project: default
source:
repoURL: https://github.com/srujantata/gitops-argocd-advanced.git
targetRevision: HEAD
path: "{{path}}"
destination:
server: https://kubernetes.default.svc
namespace: "{{path.basename}}"
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true# rollouts/canary-rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: payment-service
namespace: production
spec:
replicas: 10
selector:
matchLabels:
app: payment-service
template:
metadata:
labels:
app: payment-service
spec:
containers:
- name: payment-service
image: ghcr.io/srujantata/payment-service:1.0.0
resources:
limits:
cpu: 500m
memory: 256Mi
strategy:
canary:
steps:
- setWeight: 10 # 10% of traffic to new version
- pause: {duration: 5m}
- analysis: # automated check before proceeding
templates:
- templateName: error-rate-check
- setWeight: 50
- pause: {duration: 10m}
- analysis:
templates:
- templateName: error-rate-check
- setWeight: 100 # full rollout
canaryService: payment-service-canary
stableService: payment-service-stable# rollouts/error-rate-analysis.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: error-rate-check
spec:
metrics:
- name: error-rate
interval: 1m
successCondition: result[0] < 0.01 # < 1% error rate
failureLimit: 3
provider:
prometheus:
address: http://prometheus.monitoring.svc:9090
query: |
sum(rate(http_requests_total{status=~"5..",app="payment-service"}[2m]))
/ sum(rate(http_requests_total{app="payment-service"}[2m]))If error rate exceeds 1% in 3 consecutive checks → Rollout automatically rolls back.
# rollouts/bluegreen-rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: api-gateway
namespace: production
spec:
replicas: 5
strategy:
blueGreen:
activeService: api-gateway-active # live traffic
previewService: api-gateway-preview # new version (no live traffic)
autoPromotionEnabled: false # require manual approval
scaleDownDelaySeconds: 30 # keep blue around 30s post-promotion
prePromotionAnalysis:
templates:
- templateName: smoke-testWorkflow:
New version deployed ──► preview service (0% live traffic)
│
▼ run smoke tests + QA review
Manual promotion: kubectl argo rollouts promote api-gateway
│
▼
Active service switches to new version (instant, no downtime)
Old version kept 30s ──► then scaled down
Watches Harbor (or any OCI registry) for new image tags and automatically commits the tag bump to Git — GitOps all the way down.
# k8s/image-updater-annotation.yaml
# Add these annotations to your ArgoCD Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: payment-service
namespace: argocd
annotations:
argocd-image-updater.argoproj.io/image-list: >
payment=ghcr.io/srujantata/payment-service
argocd-image-updater.argoproj.io/payment.update-strategy: semver
argocd-image-updater.argoproj.io/payment.allow-tags: ">=1.0.0"
argocd-image-updater.argoproj.io/write-back-method: git
argocd-image-updater.argoproj.io/git-branch: main
spec:
# ... rest of Application specWhen a new v1.2.3 tag is pushed to the registry:
- Image Updater detects it within 2 minutes
- Commits
image: ghcr.io/srujantata/payment-service:v1.2.3to Git - ArgoCD detects the git change and syncs
# argocd-notifications/slack-template.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
trigger.on-sync-succeeded: |
- when: app.status.operationState.phase in ['Succeeded']
send: [app-sync-succeeded]
trigger.on-sync-failed: |
- when: app.status.operationState.phase in ['Failed', 'Error']
send: [app-sync-failed]
template.app-sync-succeeded: |
slack:
attachments: |
[{
"color": "#18be52",
"title": "✅ {{.app.metadata.name}} synced",
"text": "Deployed {{.app.status.sync.revision}} to {{.app.spec.destination.namespace}}",
"footer": "ArgoCD"
}]
template.app-sync-failed: |
slack:
attachments: |
[{
"color": "#E96D76",
"title": "❌ {{.app.metadata.name}} sync failed",
"text": "{{.app.status.operationState.message}}",
"footer": "ArgoCD"
}]
service.slack: |
token: $SLACK_TOKEN# ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd \
-f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Argo Rollouts
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts \
-f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
# Image Updater
kubectl apply -n argocd \
-f https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml
# Apply ApplicationSet
kubectl apply -f applicationsets/all-envs.yaml# Check rollout status
kubectl argo rollouts get rollout payment-service -n production --watch
# Manually promote blue-green
kubectl argo rollouts promote api-gateway -n production
# Rollback immediately
kubectl argo rollouts abort payment-service -n production
# List all rollouts
kubectl argo rollouts list rollouts -A- ArgoCD ApplicationSets for DRY multi-environment GitOps
- Argo Rollouts canary deployment with automated Prometheus-backed analysis
- Blue-green deployment with manual promotion gate
- Automated image tag updates via ArgoCD Image Updater
- Slack notifications for sync success/failure
- GitOps principles: Git as single source of truth, no kubectl apply in CI