ArgoCD Beyond the Basics: Multi-Cluster GitOps Patterns That Scale
You have ArgoCD running. Now what? App of Apps, ApplicationSets, multi-cluster sync, progressive delivery with Argo Rollouts, and secrets management for production GitOps.
ArgoCD Beyond the Basics: Multi-Cluster GitOps Patterns That Scale
You have ArgoCD running. It syncs a Git repo to a Kubernetes cluster. Applications deploy automatically when you push. Congratulations — you have implemented GitOps 101.
Now what?
The gap between "ArgoCD works on my staging cluster" and "ArgoCD manages 50 microservices across 3 clusters in production" is where most teams get stuck. This guide covers the patterns that bridge that gap.
The App of Apps Pattern
Managing individual ArgoCD Application manifests does not scale. With 30 services, you have 30 Application YAML files to maintain. The App of Apps pattern solves this by creating a parent Application that manages child Applications.
# apps/root-app.yaml — the parent
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
namespace: argocd
spec:
project: default
source:
repoURL: https://git.example.com/infra/argocd-apps
path: apps
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
# apps/api-service.yaml — a child application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: api-service
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: production
source:
repoURL: https://git.example.com/services/api
path: k8s/overlays/production
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: api
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Push a new child Application YAML to the apps/ directory, and ArgoCD automatically picks it up. Delete the YAML, and ArgoCD cleans up the resources.
ApplicationSets: Templated Applications at Scale
App of Apps works, but you still write individual YAML per service. ApplicationSets generate Applications from templates.
Git Directory Generator
Automatically create an Application for every directory in a path:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: services
namespace: argocd
spec:
generators:
- git:
repoURL: https://git.example.com/infra/k8s-manifests
revision: main
directories:
- path: services/*
template:
metadata:
name: '{{path.basename}}'
spec:
project: production
source:
repoURL: https://git.example.com/infra/k8s-manifests
path: '{{path}}'
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: '{{path.basename}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Add a new directory under services/, and ArgoCD creates the Application automatically. Zero manual YAML required.
Get more insights on DevOps
Join 2,000+ engineers who get our weekly deep-dives. No spam, unsubscribe anytime.
Multi-Cluster Generator
Deploy the same application to multiple clusters:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: monitoring-stack
namespace: argocd
spec:
generators:
- clusters:
selector:
matchLabels:
env: production
template:
metadata:
name: 'monitoring-{{name}}'
spec:
project: infrastructure
source:
repoURL: https://git.example.com/infra/monitoring
path: helm
targetRevision: main
helm:
valueFiles:
- 'values/{{metadata.labels.region}}.yaml'
destination:
server: '{{server}}'
namespace: monitoring
This deploys monitoring to every cluster labeled env: production, with region-specific values automatically selected.
Multi-Cluster Management
Registering Clusters
# Add a remote cluster to ArgoCD
argocd cluster add production-us-east \
--name prod-us-east \
--label env=production \
--label region=us-east
argocd cluster add production-eu-west \
--name prod-eu-west \
--label env=production \
--label region=eu-west
Hub-and-Spoke Architecture
Run ArgoCD on a management cluster that syncs to all other clusters:
Management Cluster (ArgoCD)
├── → Production US-East (syncs apps)
├── → Production EU-West (syncs apps)
├── → Staging (syncs apps)
└── → Dev (syncs apps)
ArgoCD connects to remote clusters via kubeconfig or service account tokens. The management cluster has no application workloads — it only runs ArgoCD and related tooling.
Progressive Delivery with Argo Rollouts
Standard Kubernetes deployments are all-or-nothing: the new version replaces the old version. Argo Rollouts adds canary and blue-green deployment strategies.
Canary Deployment
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: api-service
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 10
- pause: { duration: 5m }
- setWeight: 30
- pause: { duration: 5m }
- setWeight: 60
- pause: { duration: 10m }
- setWeight: 100
canaryService: api-canary
stableService: api-stable
trafficRouting:
nginx:
stableIngress: api-ingress
selector:
matchLabels:
app: api-service
template:
metadata:
labels:
app: api-service
spec:
containers:
- name: api
image: registry.example.com/api:v2.1.0
This sends 10% of traffic to the new version, waits 5 minutes, increases to 30%, waits again, and gradually rolls out to 100%. If metrics degrade at any step, it automatically rolls back.
Analysis with Prometheus
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
metrics:
- name: success-rate
interval: 60s
count: 5
successCondition: result[0] >= 0.99
provider:
prometheus:
address: http://prometheus:9090
query: |
sum(rate(http_requests_total{status=~"2.."}[5m]))
/
sum(rate(http_requests_total[5m]))
Attach this to a canary step, and ArgoCD automatically queries Prometheus during the rollout. If the success rate drops below 99%, the rollout is aborted and traffic shifts back to the stable version.
Secrets Management in GitOps
The biggest challenge with GitOps: secrets cannot live in Git (plaintext). Options:
Sealed Secrets
# Encrypt a secret that only the cluster can decrypt
kubeseal --format yaml < secret.yaml > sealed-secret.yaml
# The sealed secret is safe to commit to Git
git add sealed-secret.yaml
git commit -m "Add database credentials"
External Secrets Operator
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: database-creds
spec:
refreshInterval: 1h
secretStoreRef:
name: vault
kind: ClusterSecretStore
target:
name: database-creds
data:
- secretKey: password
remoteRef:
key: production/database
property: password
This pulls secrets from HashiCorp Vault (or AWS Secrets Manager, GCP Secret Manager) at runtime. The Git repo only contains a reference, not the secret value.
SOPS (Mozilla)
# Encrypt specific values in a YAML file
sops --encrypt --age age1... secrets.yaml > secrets.enc.yaml
# ArgoCD decrypts at sync time with the ksops plugin
Free Resource
CI/CD Pipeline Blueprint
Our battle-tested pipeline template covering build, test, security scan, staging, and zero-downtime deployment stages.
Recommendation: For small teams, Sealed Secrets. For teams with existing Vault infrastructure, External Secrets Operator. For everything else, SOPS with age encryption.
Sync Waves and Hooks
Control the order of resource creation:
metadata:
annotations:
argocd.argoproj.io/sync-wave: "-1" # Creates first
---
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0" # Creates second (default)
---
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1" # Creates third
Use sync waves for: namespace before deployments, CRDs before custom resources, migrations before application startup.
Resource Hooks
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: registry.example.com/api:v2.1.0
command: ["python", "manage.py", "migrate"]
restartPolicy: Never
This runs database migrations before the application syncs. If the migration fails, the sync is aborted.
Production Checklist
Before running ArgoCD in production:
- Enable RBAC — restrict who can sync which applications to which clusters
- Use Projects — isolate teams and environments (dev team cannot sync to production namespace)
- Set resource limits — prevent a misconfigured Application from creating unlimited pods
- Enable notifications — Slack/email alerts on sync failures, health degradation
- Backup ArgoCD — the Application definitions are in Git, but ArgoCD state (sync status, history) is in etcd
- Use ApplicationSets over manual Application YAML — they scale better and reduce drift
- Pin image tags — never use :latest in production manifests (use digest or semver)
The Bottom Line
ArgoCD is powerful out of the box. But the real value unlocks at scale: ApplicationSets for templated deployments, multi-cluster management for geographic distribution, Argo Rollouts for progressive delivery, and proper secrets management for security.
The pattern is always the same: declare the desired state in Git, let ArgoCD converge reality to match. The more you lean into this pattern — templates, generators, automated analysis — the less manual work you do and the more reliable your deployments become.
Related Service
Platform Engineering
From CI/CD pipelines to service meshes, we create golden paths for your developers.
Need help with devops?
TechSaaS provides expert consulting and managed services for cloud infrastructure, DevOps, and AI/ML operations.
We Will Build You a Demo Site — For Free
Like it? Pay us. Do not like it? Walk away, zero complaints. You will spend way less than hiring developers or any agency.
No spam. No contracts. Just a free demo.