Configure ArgoCD ApplicationSets to automate deployments across multiple environments using GitOps patterns. Learn to create templates, generators, and automated promotion workflows for production-grade Kubernetes deployments.
Prerequisites
- Running Kubernetes cluster with kubectl access
- ArgoCD installed or cluster-admin privileges
- Git repository for storing application configurations
- Basic understanding of Kubernetes manifests and Helm
What this solves
ArgoCD ApplicationSets automate the deployment of applications across multiple environments, clusters, or namespaces using template-based configurations. Instead of manually creating individual ArgoCD Applications for dev, staging, and production environments, ApplicationSets use generators to dynamically create and manage these applications from a single configuration.
Prerequisites
Install ArgoCD if not already present
Skip this step if ArgoCD is already running in your cluster. Otherwise, install ArgoCD in the argocd namespace.
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Wait for ArgoCD components to be ready
Verify all ArgoCD components are running before proceeding with ApplicationSet configuration.
kubectl wait --for=condition=ready pod -l app.kubernetes.io/part-of=argocd -n argocd --timeout=300s
Install ArgoCD ApplicationSet Controller
The ApplicationSet controller is included in recent ArgoCD versions but may need explicit installation on older versions.
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/applicationset/v0.4.1/manifests/install.yaml
Step-by-step configuration
Create Git repository structure
Set up a proper GitOps repository structure to support multi-environment deployments with ApplicationSets.
mkdir -p gitops-demo/{apps,environments/{dev,staging,prod},clusters}
cd gitops-demo
Create base application manifests
Create a base application configuration that will be templated across environments.
apiVersion: v1
kind: Namespace
metadata:
name: nginx-{{.environment}}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: nginx-{{.environment}}
spec:
replicas: {{.replicas}}
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
environment: {{.environment}}
spec:
containers:
- name: nginx
image: nginx:{{.version}}
ports:
- containerPort: 80
resources:
requests:
cpu: {{.cpu_request}}
memory: {{.memory_request}}
limits:
cpu: {{.cpu_limit}}
memory: {{.memory_limit}}
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: nginx-{{.environment}}
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: ClusterIP
Create environment-specific configurations
Define different resource allocations and configurations for each environment.
{
"environment": "dev",
"replicas": 1,
"version": "1.21",
"cpu_request": "100m",
"memory_request": "128Mi",
"cpu_limit": "200m",
"memory_limit": "256Mi",
"cluster": "dev-cluster",
"namespace": "nginx-dev"
}
Create staging environment configuration
Configure staging with higher resource allocation and stable image versions.
{
"environment": "staging",
"replicas": 2,
"version": "1.21",
"cpu_request": "200m",
"memory_request": "256Mi",
"cpu_limit": "500m",
"memory_limit": "512Mi",
"cluster": "staging-cluster",
"namespace": "nginx-staging"
}
Create production environment configuration
Configure production with high availability and resource allocation suitable for production workloads.
{
"environment": "prod",
"replicas": 3,
"version": "1.20",
"cpu_request": "500m",
"memory_request": "512Mi",
"cpu_limit": "1000m",
"memory_limit": "1Gi",
"cluster": "prod-cluster",
"namespace": "nginx-prod"
}
Create cluster configuration files
Define cluster-specific settings that ApplicationSets can reference for multi-cluster deployments.
apiVersion: v1
kind: Secret
metadata:
name: dev-cluster-secret
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
type: Opaque
stringData:
name: dev-cluster
server: https://dev.example.com
config: |
{
"bearerToken": "",
"tlsClientConfig": {
"insecure": false
}
}
Create Git generator ApplicationSet
Create an ApplicationSet that uses Git file generator to automatically discover environments from your repository structure.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: nginx-environments
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/your-org/gitops-demo
revision: HEAD
files:
- path: "environments/*/config.json"
template:
metadata:
name: 'nginx-{{environment}}'
spec:
project: default
source:
repoURL: https://github.com/your-org/gitops-demo
targetRevision: HEAD
path: apps
helm:
valueFiles:
- "../environments/{{environment}}/config.json"
destination:
server: https://kubernetes.default.svc
namespace: 'nginx-{{environment}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Create list generator ApplicationSet for specific clusters
Use list generator when you need explicit control over which clusters and environments to deploy to.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: nginx-multi-cluster
namespace: argocd
spec:
generators:
- list:
elements:
- cluster: dev-cluster
url: https://dev.example.com
environment: dev
replicas: "1"
version: "1.21"
- cluster: staging-cluster
url: https://staging.example.com
environment: staging
replicas: "2"
version: "1.21"
- cluster: prod-cluster
url: https://prod.example.com
environment: prod
replicas: "3"
version: "1.20"
template:
metadata:
name: 'nginx-{{environment}}-{{cluster}}'
spec:
project: default
source:
repoURL: https://github.com/your-org/gitops-demo
targetRevision: HEAD
path: apps
helm:
parameters:
- name: environment
value: '{{environment}}'
- name: replicas
value: '{{replicas}}'
- name: version
value: '{{version}}'
destination:
server: '{{url}}'
namespace: 'nginx-{{environment}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Create cluster generator ApplicationSet
Automatically discover registered clusters and deploy applications to all of them.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: nginx-all-clusters
namespace: argocd
spec:
generators:
- clusters:
selector:
matchLabels:
environment: production
template:
metadata:
name: 'nginx-{{name}}'
spec:
project: default
source:
repoURL: https://github.com/your-org/gitops-demo
targetRevision: HEAD
path: apps
helm:
parameters:
- name: environment
value: '{{metadata.labels.environment}}'
- name: cluster
value: '{{name}}'
destination:
server: '{{server}}'
namespace: nginx
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Apply ApplicationSet configurations
Deploy the ApplicationSets to your cluster and verify they create the expected Application resources.
kubectl apply -f applicationset-git-generator.yaml
kubectl apply -f applicationset-list-generator.yaml
Configure RBAC for ApplicationSets
Set up proper permissions for ApplicationSet controller to manage applications across namespaces.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: applicationset-controller
rules:
- apiGroups: ["argoproj.io"]
resources: ["applications", "applicationsets"]
verbs: ["get", "list", "create", "update", "delete", "patch", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: applicationset-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: applicationset-controller
subjects:
- kind: ServiceAccount
name: applicationset-controller
namespace: argocd
Apply RBAC configuration
Apply the RBAC rules to ensure ApplicationSet controller has necessary permissions.
kubectl apply -f applicationset-rbac.yaml
Create progressive deployment ApplicationSet
Implement automated promotion workflow where successful deployment to dev triggers staging deployment.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: nginx-progressive
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/your-org/gitops-demo
revision: HEAD
files:
- path: "environments/*/config.json"
template:
metadata:
name: 'nginx-{{environment}}'
annotations:
argocd-image-updater.argoproj.io/image-list: nginx=nginx
argocd-image-updater.argoproj.io/write-back-method: git
spec:
project: default
source:
repoURL: https://github.com/your-org/gitops-demo
targetRevision: HEAD
path: apps
destination:
server: https://kubernetes.default.svc
namespace: 'nginx-{{environment}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
syncWindows:
- kind: allow
schedule: '0 2 *'
duration: 1h
applications:
- 'nginx-prod'
Advanced ApplicationSet patterns
Create matrix generator for complex scenarios
Use matrix generator to combine multiple generators for complex deployment scenarios.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: nginx-matrix
namespace: argocd
spec:
generators:
- matrix:
generators:
- git:
repoURL: https://github.com/your-org/gitops-demo
revision: HEAD
directories:
- path: environments/*
- clusters:
selector:
matchLabels:
environment: '{{path.basename}}'
template:
metadata:
name: 'nginx-{{path.basename}}-{{name}}'
spec:
project: default
source:
repoURL: https://github.com/your-org/gitops-demo
targetRevision: HEAD
path: apps
helm:
parameters:
- name: environment
value: '{{path.basename}}'
- name: cluster
value: '{{name}}'
destination:
server: '{{server}}'
namespace: 'nginx-{{path.basename}}'
syncPolicy:
automated:
prune: true
selfHeal: true
Configure ApplicationSet with Helm chart source
Use ApplicationSets with Helm charts for more complex application packaging and configuration.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: nginx-helm
namespace: argocd
spec:
generators:
- list:
elements:
- environment: dev
values: |
replicaCount: 1
image:
tag: "1.21"
resources:
requests:
cpu: 100m
memory: 128Mi
- environment: prod
values: |
replicaCount: 3
image:
tag: "1.20"
resources:
requests:
cpu: 500m
memory: 512Mi
template:
metadata:
name: 'nginx-helm-{{environment}}'
spec:
project: default
source:
repoURL: https://charts.bitnami.com/bitnami
chart: nginx
targetRevision: 13.2.23
helm:
values: '{{values}}'
destination:
server: https://kubernetes.default.svc
namespace: 'nginx-{{environment}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Monitoring and troubleshooting
Set up ApplicationSet monitoring
Create ServiceMonitor for Prometheus to scrape ApplicationSet controller metrics.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: applicationset-controller-metrics
namespace: argocd
spec:
selector:
matchLabels:
app.kubernetes.io/component: applicationset-controller
app.kubernetes.io/name: argocd-applicationset-controller
endpoints:
- port: metrics
Configure logging for ApplicationSet controller
Increase log level for debugging ApplicationSet issues and generator behavior.
kubectl patch deployment argocd-applicationset-controller -n argocd -p '{
"spec": {
"template": {
"spec": {
"containers": [{
"name": "applicationset-controller",
"args": [
"--logLevel", "debug",
"--metrics-addr", "0.0.0.0:8080"
]
}]
}
}
}
}'
Verify your setup
Check that ApplicationSets are creating the expected Applications and that they sync successfully.
# Check ApplicationSet status
kubectl get applicationsets -n argocd
Verify generated Applications
kubectl get applications -n argocd
Check ApplicationSet controller logs
kubectl logs -n argocd deployment/argocd-applicationset-controller
Verify applications are synced
kubectl get applications -n argocd -o jsonpath='{range .items[*]}{.metadata.name}: {.status.sync.status}{"\n"}{end}'
You can also check the ArgoCD UI to see the ApplicationSet and its generated Applications visually.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Applications not created | Generator not finding files/clusters | Check generator paths and cluster labels with kubectl describe applicationset |
| Template parameters not resolved | Missing or incorrect generator field references | Verify generator output fields match template variables |
| ApplicationSet controller crashloop | RBAC permissions missing | Apply comprehensive RBAC rules with cluster-admin if needed for testing |
| Git generator not detecting changes | Repository access issues or path mismatch | Check repository credentials and file paths in git generator |
| Applications stuck in sync | Resource conflicts or namespace issues | Check Application events and sync policy configuration |
| Cluster generator empty results | No clusters match selector labels | Verify cluster secrets have correct labels in argocd namespace |
Next steps
- Configure ArgoCD Image Updater for automated container deployments
- Set up ArgoCD notifications for Slack and Microsoft Teams
- Configure ArgoCD with Vault for secure secrets management
- Implement ArgoCD multi-cluster GitOps with cross-cluster application promotion
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Color definitions
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
SCRIPT_NAME=$(basename "$0")
REPO_URL="${1:-}"
REPO_DIR="${2:-gitops-demo}"
# Usage message
usage() {
echo "Usage: $SCRIPT_NAME <git-repo-url> [repo-directory]"
echo "Example: $SCRIPT_NAME https://github.com/myorg/gitops-demo.git"
exit 1
}
# Cleanup function
cleanup() {
local exit_code=$?
if [ $exit_code -ne 0 ]; then
echo -e "${RED}[ERROR] Installation failed. Cleaning up...${NC}"
kubectl delete namespace argocd --ignore-not-found=true || true
rm -rf "$REPO_DIR" || true
fi
exit $exit_code
}
trap cleanup ERR
# Logging functions
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Check arguments
if [ -z "$REPO_URL" ]; then
usage
fi
# Auto-detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
log_error "Cannot detect distribution. /etc/os-release not found."
exit 1
fi
log_info "Detected distribution: $ID using $PKG_MGR"
# Check prerequisites
echo "[1/10] Checking prerequisites..."
if [ "$EUID" -eq 0 ]; then
log_warning "Running as root. Consider using sudo for specific commands only."
fi
# Check for required tools
command -v kubectl >/dev/null 2>&1 || { log_error "kubectl is required but not installed."; exit 1; }
command -v git >/dev/null 2>&1 || {
log_info "Installing git..."
if [ "$PKG_MGR" = "apt" ]; then
sudo $PKG_UPDATE
fi
sudo $PKG_INSTALL git
}
# Verify kubectl cluster access
echo "[2/10] Verifying Kubernetes cluster access..."
if ! kubectl cluster-info >/dev/null 2>&1; then
log_error "Cannot connect to Kubernetes cluster. Check kubeconfig."
exit 1
fi
log_success "Kubernetes cluster access verified"
# Check if ArgoCD is already installed
echo "[3/10] Checking ArgoCD installation..."
if kubectl get namespace argocd >/dev/null 2>&1; then
log_warning "ArgoCD namespace already exists. Skipping installation."
SKIP_ARGOCD_INSTALL=true
else
SKIP_ARGOCD_INSTALL=false
fi
# Install ArgoCD if not present
if [ "$SKIP_ARGOCD_INSTALL" = "false" ]; then
echo "[4/10] Installing ArgoCD..."
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
log_success "ArgoCD installation initiated"
else
echo "[4/10] Skipping ArgoCD installation (already exists)"
fi
# Wait for ArgoCD components to be ready
echo "[5/10] Waiting for ArgoCD components to be ready..."
kubectl wait --for=condition=ready pod -l app.kubernetes.io/part-of=argocd -n argocd --timeout=300s
log_success "ArgoCD components are ready"
# Install ArgoCD ApplicationSet Controller
echo "[6/10] Installing ArgoCD ApplicationSet Controller..."
if ! kubectl get deployment argocd-applicationset-controller -n argocd >/dev/null 2>&1; then
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/applicationset/v0.4.1/manifests/install.yaml
log_success "ApplicationSet Controller installed"
else
log_warning "ApplicationSet Controller already exists"
fi
# Clone or create GitOps repository structure
echo "[7/10] Setting up GitOps repository structure..."
if [ -d "$REPO_DIR" ]; then
log_warning "Directory $REPO_DIR already exists. Removing it."
rm -rf "$REPO_DIR"
fi
git clone "$REPO_URL" "$REPO_DIR" || {
log_warning "Failed to clone repository. Creating local structure."
mkdir -p "$REPO_DIR"
cd "$REPO_DIR"
git init
}
cd "$REPO_DIR"
mkdir -p apps environments/{dev,staging,prod} clusters
chmod 755 apps environments environments/{dev,staging,prod} clusters
# Create base application manifests
echo "[8/10] Creating base application manifests..."
cat > apps/nginx-base.yaml << 'EOF'
apiVersion: v1
kind: Namespace
metadata:
name: nginx-{{.environment}}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: nginx-{{.environment}}
spec:
replicas: {{.replicas}}
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
environment: {{.environment}}
spec:
containers:
- name: nginx
image: nginx:{{.version}}
ports:
- containerPort: 80
resources:
requests:
cpu: {{.cpu_request}}
memory: {{.memory_request}}
limits:
cpu: {{.cpu_limit}}
memory: {{.memory_limit}}
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: nginx-{{.environment}}
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: ClusterIP
EOF
chmod 644 apps/nginx-base.yaml
# Create environment-specific configurations
echo "[9/10] Creating environment configurations..."
cat > environments/dev/config.json << 'EOF'
{
"environment": "dev",
"replicas": 1,
"version": "1.21",
"cpu_request": "100m",
"memory_request": "128Mi",
"cpu_limit": "200m",
"memory_limit": "256Mi",
"cluster": "in-cluster",
"namespace": "nginx-dev"
}
EOF
cat > environments/staging/config.json << 'EOF'
{
"environment": "staging",
"replicas": 2,
"version": "1.21",
"cpu_request": "200m",
"memory_request": "256Mi",
"cpu_limit": "500m",
"memory_limit": "512Mi",
"cluster": "in-cluster",
"namespace": "nginx-staging"
}
EOF
cat > environments/prod/config.json << 'EOF'
{
"environment": "prod",
"replicas": 3,
"version": "1.20",
"cpu_request": "500m",
"memory_request": "512Mi",
"cpu_limit": "1000m",
"memory_limit": "1Gi",
"cluster": "in-cluster",
"namespace": "nginx-prod"
}
EOF
chmod 644 environments/*/config.json
# Create ApplicationSet manifest
cat > applicationset.yaml << 'EOF'
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: nginx-environments
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/example/gitops-demo.git
revision: HEAD
files:
- path: "environments/*/config.json"
template:
metadata:
name: 'nginx-{{environment}}'
spec:
project: default
source:
repoURL: https://github.com/example/gitops-demo.git
targetRevision: HEAD
path: apps
plugin:
name: argocd-vault-plugin-helm
env:
- name: HELM_VALUES
value: |
environment: {{environment}}
replicas: {{replicas}}
version: {{version}}
cpu_request: {{cpu_request}}
memory_request: {{memory_request}}
cpu_limit: {{cpu_limit}}
memory_limit: {{memory_limit}}
destination:
server: https://kubernetes.default.svc
namespace: nginx-{{environment}}
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
EOF
chmod 644 applicationset.yaml
log_success "GitOps repository structure created"
# Verification
echo "[10/10] Verifying installation..."
kubectl get pods -n argocd --no-headers | while read -r pod status rest; do
if [[ "$status" != "Running" ]]; then
log_warning "Pod $pod is in $status state"
fi
done
if kubectl get deployment argocd-applicationset-controller -n argocd >/dev/null 2>&1; then
log_success "ApplicationSet Controller is deployed"
else
log_error "ApplicationSet Controller not found"
exit 1
fi
log_success "ArgoCD ApplicationSets installation completed successfully!"
echo ""
log_info "Next steps:"
echo "1. Update the repoURL in applicationset.yaml with your actual Git repository"
echo "2. Commit and push the generated files to your Git repository"
echo "3. Apply the ApplicationSet: kubectl apply -f applicationset.yaml"
echo "4. Access ArgoCD UI: kubectl port-forward svc/argocd-server -n argocd 8080:443"
echo "5. Get admin password: kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 -d"
Review the script before running. Execute with: bash install.sh