ArgoCD Multi-Cluster Deployment Patterns
Managing GitOps deployments across multiple Kubernetes clusters requires thoughtful architecture. The control plane model provides centralized governance while maintaining flexibility for individual environments.
Architecture Overview
In the control plane model, a central ArgoCD instance manages downstream clusters:
┌─────────────────────────────────────────────────────────┐
│ Control Plane Cluster │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ArgoCD (Hub Instance) │ │
│ │ - ApplicationSets │ │
│ │ - Cluster Secrets │ │
│ │ - RBAC Policies │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ Dev │ │ Staging │ │ Prod │
│ Cluster │ │ Cluster │ │ Cluster │
└───────────┘ └───────────┘ └───────────┘Setting Up the Control Plane
1. Installing ArgoCD
Deploy ArgoCD to your management cluster:
# Create namespace
kubectl create namespace argocd
# Install ArgoCD with HA configuration
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd \
--namespace argocd \
--set server.replicas=2 \
--set controller.replicas=2 \
--set repoServer.replicas=2 \
--set redis-ha.enabled=true
# Get initial admin password
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d2. Registering Target Clusters
Add downstream clusters using secrets or the ArgoCD CLI:
apiVersion: v1
kind: Secret
metadata:
name: prod-cluster
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
environment: production
type: Opaque
stringData:
name: prod-cluster
server: https://prod-cluster.example.com
config: |
{
"bearerToken": "<service-account-token>",
"tlsClientConfig": {
"insecure": false,
"caData": "<base64-encoded-ca-cert>"
}
}ApplicationSets for Multi-Cluster
ApplicationSets enable declarative, template-driven Application generation:
Cluster Generator
Deploy to all clusters matching specific labels:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: platform-services
namespace: argocd
spec:
generators:
- clusters:
selector:
matchLabels:
environment: production
template:
metadata:
name: '{{name}}-platform-services'
spec:
project: platform
source:
repoURL: https://github.com/org/platform-services
targetRevision: HEAD
path: 'clusters/{{name}}'
destination:
server: '{{server}}'
namespace: platform
syncPolicy:
automated:
prune: true
selfHeal: trueGit Directory Generator
Generate Applications based on directory structure:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: team-applications
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/org/app-configs
revision: HEAD
directories:
- path: 'teams/*/apps/*'
template:
metadata:
name: '{{path.basename}}'
spec:
project: '{{path[1]}}' # team name
source:
repoURL: https://github.com/org/app-configs
targetRevision: HEAD
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{path.basename}}'Image Updater Integration
Automate image updates with ArgoCD Image Updater:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
annotations:
argocd-image-updater.argoproj.io/image-list: myapp=ghcr.io/org/myapp
argocd-image-updater.argoproj.io/myapp.update-strategy: semver
argocd-image-updater.argoproj.io/myapp.allow-tags: regexp:^v[0-9]+\.[0-9]+\.[0-9]+$
argocd-image-updater.argoproj.io/write-back-method: git
spec:
project: default
source:
repoURL: https://github.com/org/app-configs
targetRevision: HEAD
path: apps/my-app
destination:
server: https://kubernetes.default.svc
namespace: my-appRBAC and Project Configuration
Define projects to isolate teams and control access:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: team-alpha
namespace: argocd
spec:
description: Team Alpha applications
sourceRepos:
- 'https://github.com/org/team-alpha-*'
destinations:
- namespace: 'team-alpha-*'
server: '*'
clusterResourceWhitelist:
- group: ''
kind: Namespace
namespaceResourceWhitelist:
- group: '*'
kind: '*'
roles:
- name: developer
policies:
- p, proj:team-alpha:developer, applications, *, team-alpha/*, allow
groups:
- team-alpha-developersBest Practices
- Use ApplicationSets over individual Applications - Reduces configuration duplication and enables consistent deployments.
- Implement progressive delivery - Deploy to dev/staging before production using wave annotations or separate ApplicationSets.
- Enable automated sync with safeguards - Use
selfHealandprunebut configure appropriate sync windows for production. - Centralize secrets management - Use external-secrets with AWS Secrets Manager or HashiCorp Vault.
- Monitor sync status - Set up alerts for failed syncs and degraded applications.
Monitoring and Observability
ArgoCD exposes Prometheus metrics for monitoring:
# Sync status
argocd_app_info{sync_status="OutOfSync"}
# Health status
argocd_app_info{health_status="Degraded"}
# Sync duration
argocd_app_sync_total
# Controller queue depth
argocd_app_reconcile_bucketConclusion
The control plane model for ArgoCD provides a scalable approach to multi-cluster GitOps. By centralizing management while distributing workloads, you gain visibility and control without sacrificing flexibility.
ApplicationSets are the key to managing complexity at scale - they transform cluster configuration from imperative scripts to declarative templates that adapt as your infrastructure grows.
Amar Sattaur
Staff DevOps Engineer with experience architecting multi-cluster ArgoCD deployments for enterprise environments.