
Argocd Advanced
- 49 installs
- 6 repo stars
- Updated July 22, 2026
- julianobarbosa/claude-code-skills
Helps with ai & agent building tasks.
About
argocd-advanced is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- argocd-advanced
- AI & Agent Building
- AI-coding skill
Argocd Advanced by the numbers
- 49 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #7,391 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/julianobarbosa/claude-code-skills --skill argocd-advancedAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 49 |
|---|---|
| repo stars | ★ 6 |
| Last updated | July 22, 2026 |
| Repository | julianobarbosa/claude-code-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
ArgoCD Cluster Bootstrapping
Operational skill for bootstrapping ArgoCD clusters using the app-of-apps pattern with Kustomize-curated ApplicationSets. Covers diagnosing sync failures from missing CRDs, creating root Applications for GitOps lifecycle management, and onboarding new clusters to existing ApplicationSet generators.
Workflow Routing
| Workflow | Trigger | File |
|---|---|---|
| DiagnoseSyncFailure | "sync failed", "missing CRD", "argocd error", "OutOfSync" | Workflows/DiagnoseSyncFailure.md |
| CreateRootApplication | "root application", "app-of-apps", "bootstrap argocd", "manage applicationsets" | Workflows/CreateRootApplication.md |
| OnboardCluster | "add cluster", "onboard cluster", "new environment" | Workflows/OnboardCluster.md |
Examples
Example 1: Diagnose a sync failure caused by missing CRD
User: "cafehyna-hub-adp-agent is SyncFailed with missing AzureKeyVaultSecret CRD"
-> Invokes DiagnoseSyncFailure workflow
-> Traces dependency chain: adp-agent needs akv2k8s CRDs
-> Checks if akv2k8s ApplicationSet exists on cluster
-> Identifies root cause: ApplicationSet never deployed
-> Recommends fix via root Application or manual applyExample 2: Create a root Application for GitOps ApplicationSet management
User: "Create a root Application to manage all ApplicationSets via GitOps"
-> Invokes CreateRootApplication workflow
-> Audits applicationset directory for active vs inactive files
-> Creates kustomization.yaml with curated list
-> Creates root-applicationsets.yaml Application
-> Provides bootstrap instructions for ArgoCD UIExample 3: Add a new cluster to existing ApplicationSets
User: "Onboard cafehyna-prd cluster to the otel ApplicationSet"
-> Invokes OnboardCluster workflow
-> Reads existing ApplicationSet generator list
-> Adds new cluster element with correct URL, project, branch
-> Creates values file in argo-cd-helm-values repo
-> Validates with kustomize buildKey Patterns
- App-of-Apps via Kustomize: Root Application watches
infra-team/applicationset/withkustomization.yamlfor explicit curation - Multi-source Helm: ApplicationSets combine chart repo + Git values repo using
$valuesref - Sync waves: Dependencies deploy first (e.g., akv2k8s at wave
-5, consumers at wave+5) - ServerSideApply: Prevents adoption conflicts when bringing existing resources under GitOps
- Bootstrap chicken-and-egg: Root Application must be applied once via ArgoCD UI, then self-manages
- Pure GitOps: No
kubectl apply/patch/edit/delete— all changes via Git commits
Architecture Reference
root-applicationsets (Application)
└── watches: infra-team/applicationset/ (Kustomize)
├── akv2k8s.yaml (ApplicationSet)
├── adp-agent.yaml (ApplicationSet)
├── otel.yaml (ApplicationSet)
└── ... (curated list in kustomization.yaml)Quick Reference
- Root Application path:
infra-team/bootstrap/root-applicationsets.yaml - ApplicationSet directory:
infra-team/applicationset/ - Kustomization file:
infra-team/applicationset/kustomization.yaml - Values repo:
argo-cd-helm-values/kube-addons/{addon}/{cluster}/values.yaml - Git repo URL:
https://hyperadevops@dev.azure.com/hyperadevops/devops-team/_git/argocd
Full documentation: See workflow files in Workflows/ directory.
ArgoCD App Install
Create ArgoCD ApplicationSets for new workloads following the Cafehyna multi-repository GitOps pattern. Uses the standardized TEMPLATE.yaml with list generator, multi-source Helm configuration, and Kustomize registration.
Customization
Before executing, check for user customizations at: ~/.claude/skills/PAI/USER/SKILLCUSTOMIZATIONS/ArgocdAppInstall/
If this directory exists, load and apply any PREFERENCES.md, configurations, or resources found there. These override default behavior. If the directory does not exist, proceed with skill defaults.
Voice Notification
When executing a workflow, do BOTH:
1. Send voice notification:
curl -s -X POST http://localhost:8888/notify \
-H "Content-Type: application/json" \
-d '{"message": "Running WORKFLOWNAME in ArgocdAppInstall"}' \
> /dev/null 2>&1 &2. Output text notification:
Running the **WorkflowName** workflow in the **ArgocdAppInstall** skill to ACTION...Full documentation: ~/.claude/skills/PAI/THENOTIFICATIONSYSTEM.md
Workflow Routing
| Workflow | Trigger | File |
|---|---|---|
| CreateApplicationSet | "add service", "new applicationset", "deploy workload", "create appset" | Workflows/CreateApplicationSet.md |
| ValidateApplicationSet | "validate appset", "check applicationset", "verify deployment" | Workflows/ValidateApplicationSet.md |
Examples
Example 1: Add a new monitoring service
User: "Add grafana-oncall to the ArgoCD platform"
-> Invokes CreateApplicationSet workflow
-> Copies TEMPLATE.yaml to grafana-oncall.yaml
-> Replaces placeholders (chart, repo, namespace, component)
-> Creates values files per cluster in argo-cd-helm-values/
-> Registers in kustomization.yaml
-> Runs pre-commit validationExample 2: Validate an existing ApplicationSet
User: "Validate the robusta applicationset is correct"
-> Invokes ValidateApplicationSet workflow
-> Checks YAML syntax, cluster URLs, values file existence
-> Verifies kustomization.yaml registration
-> Reports any issues foundExample 3: Add service to specific clusters only
User: "Deploy phpmyadmin only to dev clusters"
-> Invokes CreateApplicationSet workflow
-> Removes production/hub clusters from generator list
-> Only includes cafehyna-dev, loyalty-dev entries
-> Ensures spot tolerations in dev valuesQuick Reference
Key Paths:
- Template:
infra-team/applicationset/TEMPLATE.yaml - ApplicationSets:
infra-team/applicationset/ - Values:
argo-cd-helm-values/kube-addons/<service>/<cluster>/values.yaml - Kustomization:
infra-team/applicationset/kustomization.yaml
Sync Wave Order: -10 core infra, -5 security, 0 default, 5 apps, 10 monitoring
Cluster Details: SkillSearch('argocdappinstall cluster') -> loads ClusterInventory.md
ArgoCD ApplicationSet Skill
Comprehensive guide for implementing, configuring, and operating ArgoCD ApplicationSet - the powerful Kubernetes controller that automates Argo CD Application generation for multi-cluster, multi-tenant, and GitOps deployments.
ArgoCD Version: 2.9+ (ApplicationSet is built-in since v2.3) API Version: argoproj.io/v1alpha1
Overview
ApplicationSet is a Kubernetes controller that adds support for the ApplicationSet CustomResourceDefinition (CRD), enabling:
- Multi-Cluster Deployment: Deploy applications across multiple Kubernetes clusters from a single manifest
- Monorepo Support: Generate applications from directory structures or configuration files in Git
- Multi-Tenant Self-Service: Allow developers to create Applications without cluster-admin intervention
- GitOps Automation: Automatically create, update, and delete Argo CD Applications based on generators
Quick Reference
| Resource | Path |
|---|---|
| Generator Examples | references/generators/ |
| Template Patterns | references/templates/ |
| Common Patterns | references/patterns/ |
| Troubleshooting | references/troubleshooting/ |
---
1. ApplicationSet Structure
Basic Structure
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: my-applicationset
namespace: argocd
spec:
# Generators produce parameters for templates
generators:
- list:
elements:
- cluster: dev
url: https://dev.example.com
- cluster: prod
url: https://prod.example.com
# Template defines the Application to create
template:
metadata:
name: '{{.cluster}}-myapp'
spec:
project: default
source:
repoURL: https://github.com/org/repo.git
targetRevision: HEAD
path: apps/myapp
destination:
server: '{{.url}}'
namespace: myapp
# Optional: Sync policy for application lifecycle
syncPolicy:
preserveResourcesOnDeletion: false
applicationsSync: sync
# Optional: Enable Go templating (recommended)
goTemplate: true
goTemplateOptions: ["missingkey=error"]Key Fields
| Field | Description | Required |
|---|---|---|
generators | List of generators that produce parameters | Yes |
template | Application template with parameter placeholders | Yes |
syncPolicy | Controls application creation/update/deletion behavior | No |
goTemplate | Enable Go text templating (recommended) | No |
goTemplateOptions | Go template parsing options | No |
strategy | Progressive sync strategy (RollingSync) | No |
preservedFields | Fields to preserve during updates | No |
ignoreApplicationDifferences | Fields to ignore during comparison | No |
---
2. Generators
Generators produce parameters that are substituted into the ApplicationSet template. Multiple generators can be combined.
2.1 List Generator
Creates applications from a fixed list of key/value pairs.
generators:
- list:
elements:
- cluster: engineering-dev
url: https://kubernetes.default.svc
environment: development
- cluster: engineering-prod
url: https://prod.example.com
environment: productionUse Cases:
- Fixed set of deployment targets
- Environment-specific configurations
- Simple multi-cluster deployments
2.2 Cluster Generator
Automatically discovers clusters registered in Argo CD.
generators:
- clusters:
# Select all clusters
selector: {}
# Or filter by labels
selector:
matchLabels:
environment: production
matchExpressions:
- key: region
operator: In
values:
- us-east
- us-west
# Pass additional values
values:
revision: HEAD
helmValues: productionGenerated Parameters:
{{.name}}- Cluster name{{.nameNormalized}}- DNS-safe cluster name{{.server}}- Cluster API server URL{{.metadata.labels.<key>}}- Cluster labels{{.metadata.annotations.<key>}}- Cluster annotations
Including Local Cluster: The local cluster (in-cluster) doesn't have a Secret by default. To include it in label selectors, edit the cluster in Argo CD UI to create its Secret.
2.3 Git Generator - Directory
Generates applications based on directory structure in a Git repository.
generators:
- git:
repoURL: https://github.com/org/gitops-repo.git
revision: HEAD
directories:
# Include all directories under clusters/
- path: clusters/*
# Exclude specific directories
- path: clusters/deprecated/*
exclude: trueGenerated Parameters:
{{.path.path}}- Full directory path (e.g.,clusters/dev){{.path.basename}}- Directory name (e.g.,dev){{.path.basenameNormalized}}- DNS-safe directory name{{index .path.segments N}}- Path segment at index N
2.4 Git Generator - File
Generates applications from JSON/YAML configuration files.
generators:
- git:
repoURL: https://github.com/org/gitops-repo.git
revision: HEAD
files:
- path: "config/**/config.json"Example config.json:
{
"cluster": {
"owner": "team-a",
"name": "production",
"address": "https://prod.example.com"
},
"app": {
"name": "myapp",
"namespace": "default"
}
}Generated Parameters:
- All JSON fields are flattened:
{{.cluster.name}},{{.app.namespace}} - Path parameters:
{{.path.path}},{{.path.basename}},{{.path.filename}}
2.5 Matrix Generator
Combines two generators, creating every permutation of their outputs.
generators:
- matrix:
generators:
# First generator: Git directories (apps)
- git:
repoURL: https://github.com/org/apps.git
revision: HEAD
directories:
- path: apps/*
# Second generator: Clusters
- clusters:
selector:
matchLabels:
environment: productionResult: If Git finds 3 apps and Cluster finds 2 clusters, Matrix produces 6 Applications.
Restrictions:
- Maximum 2 child generators
- Only 1 level of nesting (no nested Matrix within Matrix)
- Child generators cannot have template overrides
2.6 Merge Generator
Merges parameters from multiple generators using merge keys.
generators:
- merge:
mergeKeys:
- cluster
generators:
# Base generator: All clusters
- clusters:
values:
helmValues: default
# Override for specific clusters
- clusters:
selector:
matchLabels:
environment: production
values:
helmValues: production
# Exception for specific cluster
- list:
elements:
- cluster: special-cluster
helmValues: customOverride Precedence: Bottom-to-top (later generators override earlier ones)
2.7 SCM Provider Generator
Discovers repositories from SCM platforms (GitHub, GitLab, Azure DevOps, Bitbucket).
generators:
- scmProvider:
# GitHub Organization
github:
organization: myorg
tokenRef:
secretName: github-token
key: token
allBranches: false
# Filter repositories
filters:
- repositoryMatch: ^microservice-.*
- pathsExist:
- kubernetes/
- labelMatch: deploy-enabled
cloneProtocol: https
requeueAfterSeconds: 300Azure DevOps Configuration:
generators:
- scmProvider:
azureDevOps:
organization: myorg
teamProject: MyProject
accessTokenRef:
secretName: azure-devops-token
key: token
allBranches: true
filters:
- repositoryMatch: ^app-.*Generated Parameters:
{{.organization}}- Organization/owner name{{.repository}}- Repository name{{.url}}- Clone URL{{.branch}}- Branch name{{.sha}}- Commit SHA{{.short_sha}}- Short commit SHA{{.labels}}- Repository labels/topics
2.8 Pull Request Generator
Generates applications for open pull requests.
generators:
- pullRequest:
github:
owner: myorg
repo: myrepo
tokenRef:
secretName: github-token
key: token
labels:
- preview
requeueAfterSeconds: 300Azure DevOps Configuration:
generators:
- pullRequest:
azuredevops:
organization: myorg
project: MyProject
repo: myrepo
tokenRef:
secretName: azure-devops-token
key: tokenGenerated Parameters:
{{.number}}- PR number{{.branch}}- Source branch name{{.branch_slug}}- DNS-safe branch name{{.target_branch}}- Target branch{{.head_sha}}- Head commit SHA{{.head_short_sha}}- Short head SHA{{.author}}- PR author{{.title}}- PR title
2.9 Plugin Generator
Custom generator using external RPC HTTP requests.
generators:
- plugin:
configMapRef:
name: my-plugin
input:
parameters:
key1: value1
requeueAfterSeconds: 300---
3. Templates
3.1 Basic Template
template:
metadata:
name: '{{.cluster}}-{{.app}}'
labels:
app: '{{.app}}'
environment: '{{.environment}}'
annotations:
notifications.argoproj.io/subscribe.on-sync-failed.slack: alerts
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: '{{.repoURL}}'
targetRevision: '{{.revision}}'
path: '{{.path}}'
destination:
server: '{{.url}}'
namespace: '{{.namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true3.2 Multi-Source Template
Combine Helm charts with external values files.
template:
metadata:
name: '{{.cluster}}-{{.app}}'
spec:
project: default
sources:
# Source 1: Helm chart from public repository
- chart: '{{.chart}}'
repoURL: '{{.chartRepo}}'
targetRevision: '{{.chartVersion}}'
helm:
releaseName: '{{.app}}'
valueFiles:
- $values/{{.valuesPath}}/values.yaml
# Source 2: Values from Git repository
- repoURL: '{{.valuesRepo}}'
targetRevision: '{{.valuesRevision}}'
ref: values
destination:
server: '{{.url}}'
namespace: '{{.namespace}}'3.3 Generator-Level Template Override
Override specific template fields per generator.
generators:
- list:
elements:
- cluster: dev
url: https://dev.example.com
# Override for this generator only
template:
spec:
source:
targetRevision: develop
- list:
elements:
- cluster: prod
url: https://prod.example.com
template:
spec:
source:
targetRevision: main
# Base template (can be overridden)
template:
metadata:
name: '{{.cluster}}-myapp'
spec:
project: default
source:
repoURL: https://github.com/org/repo.git
targetRevision: HEAD # Overridden by generator templates
path: apps/myapp
destination:
server: '{{.url}}'
namespace: myapp3.4 Template Patch (Advanced)
For non-string fields, use templatePatch with Go templating.
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- list:
elements:
- cluster: dev
replicas: 1
- cluster: prod
replicas: 3
template:
metadata:
name: '{{.cluster}}-myapp'
spec:
project: default
source:
repoURL: https://github.com/org/repo.git
path: apps/myapp
destination:
server: '{{.url}}'
templatePatch: |
spec:
source:
helm:
parameters:
- name: replicas
value: "{{.replicas}}"---
4. Go Templating
Enable Go templating for advanced functionality.
4.1 Configuration
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"] # Recommended: fail on undefined4.2 Available Functions
Sprig Functions (except env, expandenv, getHostByName):
- String:
lower,upper,trim,replace,contains,hasPrefix,hasSuffix - Lists:
list,first,last,index,slice - Math:
add,sub,mul,div - Date:
now,date,dateModify - Crypto:
sha256sum,b64enc,b64dec
Custom Functions:
normalize- Sanitize to DNS-compliant name (lowercase, alphanumeric, hyphens, dots)slugify- Smart truncation without cutting wordstoYaml/fromYaml/fromYamlArray- YAML conversion
4.3 Common Patterns
# Conditional with default
name: '{{.cluster}}{{dig "suffix" "" .}}'
# String manipulation
name: '{{ .cluster | lower | replace "_" "-" }}'
# Index access for labels with special characters
env: '{{ index .metadata.labels "env-type" }}'
# Conditional logic
{{- if eq .environment "production" }}
replicas: 3
{{- else }}
replicas: 1
{{- end }}
# List iteration (in templatePatch)
{{- range .namespaces }}
- namespace: {{ . }}
{{- end }}4.4 Migration from FastTemplate
| FastTemplate | Go Template |
|---|---|
{{ value }} | {{ .value }} |
{{ path }} | {{ .path.path }} |
{{ path.basename }} | {{ .path.basename }} |
{{ path[0] }} | {{ index .path.segments 0 }} |
{{ metadata.labels.my-label }} | {{ index .metadata.labels "my-label" }} |
---
5. Sync Policies
5.1 Application Sync Policy
Control how generated Applications are synced.
spec:
syncPolicy:
# Prevent deletion of child resources when ApplicationSet is deleted
preserveResourcesOnDeletion: true
# Control application lifecycle: sync, create-only, create-update, create-delete
applicationsSync: syncapplicationsSync Options:
| Value | Create | Update | Delete |
|---|---|---|---|
sync (default) | Yes | Yes | Yes |
create-only | Yes | No | No |
create-update | Yes | Yes | No |
create-delete | Yes | No | Yes |
5.2 Progressive Syncs (Rolling Updates)
Deploy applications in controlled stages.
spec:
# Enable progressive syncs (requires controller flag)
strategy:
type: RollingSync
rollingSync:
steps:
# Step 1: Dev environments first
- matchExpressions:
- key: environment
operator: In
values:
- dev
maxUpdate: 100% # All dev at once
# Step 2: Staging
- matchExpressions:
- key: environment
operator: In
values:
- staging
maxUpdate: 50% # Half at a time
# Step 3: Production (careful rollout)
- matchExpressions:
- key: environment
operator: In
values:
- production
maxUpdate: 1 # One at a timeEnable Progressive Syncs:
# Via environment variable
ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS=true
# Via ConfigMap
kubectl patch cm argocd-cmd-params-cm -n argocd --type merge -p '{"data":{"applicationsetcontroller.enable.progressive.syncs":"true"}}'---
6. Ignore Differences
Prevent ApplicationSet from overwriting certain Application fields.
spec:
ignoreApplicationDifferences:
# Ignore replica count changes (for HPA)
- jsonPointers:
- /spec/replicas
# Ignore specific annotations
- jqPathExpressions:
- .metadata.annotations["kubectl.kubernetes.io/last-applied-configuration"]
# Ignore for specific applications only
- name: "prod-*"
jsonPointers:
- /spec/source/targetRevision---
7. Security Considerations
7.1 Access Control
CRITICAL: Only admins should have permission to create, update, or delete ApplicationSets.
# RBAC Policy - Restrict ApplicationSet access
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
namespace: argocd
data:
policy.csv: |
# Only admins can manage ApplicationSets
p, role:admin, applicationsets, *, */*, allow
# Developers can only view
p, role:developer, applicationsets, get, */*, allow7.2 Project Field Security
WARNING: If the project field is templated from Git sources, ensure:
- Repository write access is restricted to admins
- PRs require admin approval
- Use non-scoped repositories (blank project in Argo CD)
# DANGEROUS - Project templated from Git
spec:
template:
spec:
project: '{{.project}}' # Could be exploited!
# SAFER - Fixed project
spec:
template:
spec:
project: my-restricted-project7.3 Token Management
Store SCM tokens securely in Kubernetes Secrets.
apiVersion: v1
kind: Secret
metadata:
name: github-token
namespace: argocd
type: Opaque
stringData:
token: ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx---
8. Common Patterns
8.1 Multi-Cluster Deployment
Deploy to all registered clusters.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: multi-cluster-app
namespace: argocd
spec:
goTemplate: true
generators:
- clusters:
selector:
matchLabels:
deploy: "true"
template:
metadata:
name: '{{.name}}-myapp'
spec:
project: default
source:
repoURL: https://github.com/org/repo.git
targetRevision: HEAD
path: apps/myapp
destination:
server: '{{.server}}'
namespace: myapp
syncPolicy:
automated:
prune: true
selfHeal: true8.2 Monorepo with Directory Structure
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: monorepo-apps
namespace: argocd
spec:
goTemplate: true
generators:
- git:
repoURL: https://github.com/org/monorepo.git
revision: HEAD
directories:
- path: apps/*
- path: apps/deprecated/*
exclude: true
template:
metadata:
name: '{{.path.basename}}'
spec:
project: default
source:
repoURL: https://github.com/org/monorepo.git
targetRevision: HEAD
path: '{{.path.path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{.path.basename}}'8.3 Preview Environments for Pull Requests
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: pr-preview
namespace: argocd
spec:
goTemplate: true
generators:
- pullRequest:
github:
owner: myorg
repo: myapp
tokenRef:
secretName: github-token
key: token
labels:
- preview
requeueAfterSeconds: 60
template:
metadata:
name: 'preview-{{.number}}'
labels:
app: myapp
pr: '{{.number}}'
spec:
project: previews
source:
repoURL: https://github.com/myorg/myapp.git
targetRevision: '{{.head_sha}}'
path: kubernetes
destination:
server: https://kubernetes.default.svc
namespace: 'preview-{{.number}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true8.4 Helm Chart with Multi-Source Values
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: helm-multi-source
namespace: argocd
spec:
goTemplate: true
generators:
- list:
elements:
- cluster: cafehyna-dev
url: https://dev-cluster.example.com
environment: development
branch: main
- cluster: cafehyna-prod
url: https://prod-cluster.example.com
environment: production
branch: main
template:
metadata:
name: '{{.cluster}}-myapp'
spec:
project: default
sources:
# Helm chart from public repo
- chart: myapp
repoURL: https://charts.example.com
targetRevision: 1.0.0
helm:
releaseName: myapp
valueFiles:
- $values/helm-values/myapp/{{.cluster}}/values.yaml
# Values from Git
- repoURL: https://github.com/org/gitops-values.git
targetRevision: '{{.branch}}'
ref: values
destination:
server: '{{.url}}'
namespace: myapp8.5 App-of-Apps Pattern
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: app-of-apps
namespace: argocd
spec:
goTemplate: true
generators:
- git:
repoURL: https://github.com/org/gitops.git
revision: HEAD
files:
- path: "environments/*/apps.yaml"
template:
metadata:
name: '{{.environment}}-apps'
spec:
project: default
source:
repoURL: https://github.com/org/gitops.git
targetRevision: HEAD
path: 'environments/{{.environment}}'
destination:
server: '{{.cluster.server}}'
namespace: argocd---
9. Troubleshooting
9.1 Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Applications not created | Generator returns empty results | Check generator filters, verify source data exists |
| Template substitution errors | Missing or undefined parameters | Use goTemplateOptions: ["missingkey=error"] to debug |
| Applications deleted unexpectedly | Generator no longer matches | Check syncPolicy, use preserveResourcesOnDeletion |
| Duplicate applications | Multiple generators produce same name | Add unique prefixes/suffixes to names |
| Rate limiting from SCM | Too frequent polling | Increase requeueAfterSeconds, use webhooks |
9.2 Debug Commands
# Check ApplicationSet status
kubectl get applicationsets -n argocd
# Describe ApplicationSet for events/errors
kubectl describe applicationset <name> -n argocd
# View generated Applications
kubectl get applications -n argocd -l app.kubernetes.io/instance=<appset-name>
# Check ApplicationSet controller logs
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-applicationset-controller -f
# Dry-run to see what would be generated (via argocd CLI)
argocd appset generate <appset.yaml>9.3 Webhook Configuration
Reduce polling by configuring webhooks.
GitHub Webhook:
- URL:
https://argocd.example.com/api/webhook - Content Type:
application/json - Events:
Push,Pull Request - Secret: Configure in
argocd-secret
# argocd-secret
apiVersion: v1
kind: Secret
metadata:
name: argocd-secret
namespace: argocd
stringData:
webhook.github.secret: your-webhook-secret---
10. Best Practices
1. Always use Go templating with goTemplate: true and goTemplateOptions: ["missingkey=error"]
2. Use descriptive Application names that include cluster/environment identifiers
3. Add labels to generated Applications for filtering and grouping
4. Configure finalizers for proper cleanup: resources-finalizer.argocd.argoproj.io
5. Use progressive syncs for production deployments to reduce blast radius
6. Restrict ApplicationSet RBAC - only admins should create/modify ApplicationSets
7. Never template the project field from untrusted sources
8. Use webhooks instead of polling for faster response to changes
9. Set appropriate requeue intervals to balance responsiveness and API rate limits
10. Use ignoreApplicationDifferences for fields managed by other controllers (HPA, etc.)
---
11. Reference Files
Additional templates and examples are in the references/ directory:
Generators:
references/generators/list-generator.yamlreferences/generators/cluster-generator.yamlreferences/generators/git-directory-generator.yamlreferences/generators/git-file-generator.yamlreferences/generators/matrix-generator.yamlreferences/generators/merge-generator.yamlreferences/generators/scm-provider-generator.yamlreferences/generators/pull-request-generator.yaml
Templates:
references/templates/basic-template.yamlreferences/templates/multi-source-template.yamlreferences/templates/helm-values-template.yaml
Patterns:
references/patterns/multi-cluster.yamlreferences/patterns/monorepo.yamlreferences/patterns/preview-environments.yamlreferences/patterns/progressive-rollout.yamlreferences/patterns/azure-devops-integration.yaml
Troubleshooting:
references/troubleshooting/common-issues.mdreferences/troubleshooting/debug-checklist.md
---
Related Skills
argocd-skill- General ArgoCD operationsgitops-principles-skill- GitOps methodologykargo-skill- Progressive delivery with Kargohelm-skill- Helm chart management
# =============================================================================
# Cluster Generator Examples
# =============================================================================
# The Cluster generator automatically discovers clusters registered in ArgoCD
# and generates Applications for each. Uses cluster secrets in argocd namespace.
# =============================================================================
# -----------------------------------------------------------------------------
# Basic Cluster Generator - Deploy to All Clusters
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-all-example
namespace: argocd
spec:
generators:
- clusters: {} # Empty selector = all clusters including in-cluster
template:
metadata:
name: '{{name}}-monitoring'
spec:
project: default
source:
repoURL: https://github.com/org/monitoring.git
targetRevision: HEAD
path: base
destination:
# Use the 'server' parameter from cluster secret
server: '{{server}}'
namespace: monitoring
---
# -----------------------------------------------------------------------------
# Cluster Generator - Label Selector
# -----------------------------------------------------------------------------
# Only target clusters with specific labels (set on cluster secrets)
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-selector-example
namespace: argocd
spec:
generators:
- clusters:
selector:
matchLabels:
# Only clusters labeled as production
environment: production
# With specific cloud provider
cloud: azure
# Optional: Additional values to include from cluster secret annotations
values:
clusterType: aks
template:
metadata:
name: '{{name}}-security-tools'
labels:
cluster: '{{name}}'
environment: '{{metadata.labels.environment}}'
spec:
project: production
source:
repoURL: https://github.com/org/security.git
targetRevision: HEAD
path: overlays/production
destination:
server: '{{server}}'
namespace: security
---
# -----------------------------------------------------------------------------
# Cluster Generator - Match Expressions
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-match-expressions-example
namespace: argocd
spec:
generators:
- clusters:
selector:
matchExpressions:
# Clusters in dev OR staging environments
- key: environment
operator: In
values:
- dev
- staging
# Exclude deprecated clusters
- key: status
operator: NotIn
values:
- deprecated
- decommissioning
template:
metadata:
name: '{{name}}-feature-flags'
spec:
project: default
source:
repoURL: https://github.com/org/feature-flags.git
targetRevision: HEAD
path: 'clusters/{{metadata.labels.environment}}'
destination:
server: '{{server}}'
namespace: feature-flags
---
# -----------------------------------------------------------------------------
# Cluster Generator - With Values Override
# -----------------------------------------------------------------------------
# Add custom values that can be used in templates
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-values-example
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- clusters:
selector:
matchLabels:
tier: critical
# Custom values to add to each cluster's parameters
values:
alertChannel: critical-alerts
retentionDays: "90"
replicaCount: "3"
template:
metadata:
name: '{{ .name }}-logging'
annotations:
alert-channel: '{{ .values.alertChannel }}'
spec:
project: infrastructure
source:
repoURL: https://github.com/org/logging.git
targetRevision: HEAD
path: base
helm:
parameters:
- name: retention.days
value: '{{ .values.retentionDays }}'
- name: replicas
value: '{{ .values.replicaCount }}'
destination:
server: '{{ .server }}'
namespace: logging
---
# -----------------------------------------------------------------------------
# Cluster Generator - Available Parameters
# -----------------------------------------------------------------------------
# Parameters available from cluster secrets:
#
# {{name}} - Cluster name (from secret name)
# {{nameNormalized}} - RFC 1123 compliant name
# {{server}} - Cluster API server URL
# {{metadata.labels.<key>}} - Labels from cluster secret
# {{metadata.annotations.<key>}} - Annotations from cluster secret
#
# Special cluster name:
# - 'in-cluster' refers to the cluster where ArgoCD is installed
# =============================================================================
# =============================================================================
# Git Generator Examples
# =============================================================================
# Git generators create Applications based on Git repository structure.
# Two types: Directory (folder-based) and File (config file-based)
# =============================================================================
# -----------------------------------------------------------------------------
# Git Directory Generator - Basic Monorepo
# -----------------------------------------------------------------------------
# Creates one Application per directory matching the path pattern
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: git-directory-basic
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/org/monorepo.git
revision: HEAD
directories:
# Include all directories under apps/
- path: apps/*
template:
metadata:
# {{path}} = full path, {{path.basename}} = directory name only
name: '{{path.basename}}'
spec:
project: default
source:
repoURL: https://github.com/org/monorepo.git
targetRevision: HEAD
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{path.basename}}'
---
# -----------------------------------------------------------------------------
# Git Directory Generator - With Excludes
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: git-directory-exclude
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/org/monorepo.git
revision: HEAD
directories:
# Include all under clusters/
- path: clusters/*
# Exclude specific directories
- path: clusters/deprecated
exclude: true
- path: clusters/test-*
exclude: true
template:
metadata:
name: 'cluster-{{path.basename}}'
spec:
project: default
source:
repoURL: https://github.com/org/monorepo.git
targetRevision: HEAD
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{path.basename}}'
---
# -----------------------------------------------------------------------------
# Git Directory Generator - Nested Paths (Two-Level)
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: git-directory-nested
namespace: argocd
spec:
goTemplate: true
generators:
- git:
repoURL: https://github.com/org/monorepo.git
revision: HEAD
directories:
# Match pattern: environments/{env}/apps/{app}
- path: environments/*/apps/*
template:
metadata:
# path[0]=environments, path[1]=env, path[2]=apps, path[3]=app
name: '{{ index .path.segments 1 }}-{{ index .path.segments 3 }}'
labels:
environment: '{{ index .path.segments 1 }}'
app: '{{ index .path.segments 3 }}'
spec:
project: default
source:
repoURL: https://github.com/org/monorepo.git
targetRevision: HEAD
path: '{{ .path.path }}'
destination:
server: https://kubernetes.default.svc
namespace: '{{ index .path.segments 3 }}'
---
# -----------------------------------------------------------------------------
# Git File Generator - JSON Config Files
# -----------------------------------------------------------------------------
# Creates Applications based on config files in the repository
# Supports JSON and YAML files
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: git-file-json
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/org/config-repo.git
revision: HEAD
files:
- path: "apps/**/config.json"
template:
metadata:
name: '{{app.name}}'
labels:
team: '{{app.team}}'
tier: '{{app.tier}}'
spec:
project: '{{app.project}}'
source:
repoURL: '{{app.source.repoURL}}'
targetRevision: '{{app.source.targetRevision}}'
path: '{{app.source.path}}'
destination:
server: '{{app.destination.server}}'
namespace: '{{app.destination.namespace}}'
# Example config.json:
# {
# "app": {
# "name": "my-application",
# "team": "platform",
# "tier": "critical",
# "project": "production",
# "source": {
# "repoURL": "https://github.com/org/app.git",
# "targetRevision": "v1.2.0",
# "path": "deploy/production"
# },
# "destination": {
# "server": "https://prod-cluster:6443",
# "namespace": "my-app"
# }
# }
# }
---
# -----------------------------------------------------------------------------
# Git File Generator - YAML Config Files
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: git-file-yaml
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: https://github.com/org/app-config.git
revision: HEAD
files:
- path: "clusters/*/apps.yaml"
# Values from files outside the matched path
values:
clusterConfigPath: '{{ .path.filenameNormalized }}'
template:
metadata:
name: '{{ .cluster }}-{{ .name }}'
annotations:
config-source: '{{ .path.path }}'
spec:
project: '{{ .project | default "default" }}'
source:
repoURL: '{{ .repoURL }}'
targetRevision: '{{ .revision | default "HEAD" }}'
path: '{{ .sourcePath }}'
helm:
valueFiles:
- values.yaml
- 'values-{{ .cluster }}.yaml'
destination:
server: '{{ .server }}'
namespace: '{{ .namespace }}'
# Example apps.yaml:
# cluster: production-east
# server: https://prod-east.example.com:6443
# apps:
# - name: frontend
# repoURL: https://github.com/org/frontend.git
# sourcePath: deploy
# namespace: frontend
# - name: backend
# repoURL: https://github.com/org/backend.git
# sourcePath: charts/backend
# namespace: backend
---
# -----------------------------------------------------------------------------
# Git Generator - Available Parameters
# -----------------------------------------------------------------------------
# Directory Generator Parameters:
# {{path}} - Full directory path
# {{path.path}} - Same as {{path}} (Go template)
# {{path.basename}} - Directory name only
# {{path.basenameNormalized}} - RFC 1123 compliant basename
# {{path.segments}} - Array of path segments (Go template)
#
# File Generator Parameters:
# All fields from the JSON/YAML file are available
# {{path.path}} - Path to the config file
# {{path.filename}} - Config filename
# {{path.filenameNormalized}} - RFC 1123 compliant filename
# {{path.basenameNormalized}} - Parent directory, normalized
# =============================================================================
# =============================================================================
# List Generator Examples
# =============================================================================
# The List generator generates Applications based on a fixed list of
# cluster/URL values. Most straightforward generator - explicitly define
# what Applications to generate.
# =============================================================================
# -----------------------------------------------------------------------------
# Basic List Generator - Multi-Cluster Deployment
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: list-basic-example
namespace: argocd
spec:
generators:
- list:
elements:
# Development cluster
- cluster: dev
url: https://kubernetes.default.svc
environment: development
region: eastus
# Staging cluster
- cluster: staging
url: https://staging.example.com:6443
environment: staging
region: eastus
# Production cluster
- cluster: production
url: https://prod.example.com:6443
environment: production
region: westus
template:
metadata:
name: '{{cluster}}-myapp'
labels:
environment: '{{environment}}'
region: '{{region}}'
spec:
project: default
source:
repoURL: https://github.com/example/app.git
targetRevision: HEAD
path: 'environments/{{environment}}'
destination:
server: '{{url}}'
namespace: myapp
---
# -----------------------------------------------------------------------------
# List Generator - Multi-Source with Helm Values
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: list-multi-source-example
namespace: argocd
spec:
generators:
- list:
elements:
- cluster: cafehyna-dev
url: https://aks-cafehyna-dev.privatelink.eastus.azmk8s.io:443
project: kube-addons
branch: main
environment: development
urlSuffix: dev
- cluster: cafehyna-prd
url: https://aks-cafehyna-prd.privatelink.eastus.azmk8s.io:443
project: kube-addons
branch: main
environment: production
urlSuffix: prd
template:
metadata:
name: '{{cluster}}-app'
labels:
environment: '{{environment}}'
annotations:
notifications.argoproj.io/subscribe.on-sync-failed.slack: argocd-alerts
spec:
project: '{{project}}'
sources:
# Helm chart from public repository
- chart: myapp
repoURL: https://charts.example.com
targetRevision: 1.0.0
helm:
releaseName: myapp
valueFiles:
- $values/helm-values/myapp/{{cluster}}/values.yaml
# Values repository reference
- repoURL: https://github.com/org/argocd-values.git
targetRevision: '{{branch}}'
ref: values
destination:
server: '{{url}}'
namespace: myapp
---
# -----------------------------------------------------------------------------
# List Generator - Dynamic Element Embedding (elementsYaml)
# -----------------------------------------------------------------------------
# Note: elementsYaml allows referencing elements from ConfigMaps/Secrets
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: list-elements-yaml-example
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- list:
# Reference elements from a ConfigMap
elementsYaml: "{{ .clusters | toYaml }}"
# The ConfigMap 'cluster-config' should have key 'clusters' with YAML array
template:
metadata:
name: '{{ .name }}-app'
spec:
project: default
source:
repoURL: https://github.com/example/app.git
targetRevision: HEAD
path: deploy
destination:
server: '{{ .url }}'
namespace: '{{ .namespace }}'
# =============================================================================
# Matrix and Merge Generator Examples
# =============================================================================
# Matrix: Combines two generators into Cartesian product
# Merge: Combines generators with merge semantics (key-based override)
# =============================================================================
# -----------------------------------------------------------------------------
# Matrix Generator - Clusters x Applications
# -----------------------------------------------------------------------------
# Creates Applications for every combination of cluster and app
# Total apps = clusters * apps (e.g., 3 clusters x 5 apps = 15 Applications)
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: matrix-cluster-apps
namespace: argocd
spec:
generators:
- matrix:
generators:
# First generator: Clusters
- clusters:
selector:
matchLabels:
environment: production
# Second generator: Applications from Git
- git:
repoURL: https://github.com/org/apps.git
revision: HEAD
directories:
- path: apps/*
template:
metadata:
# Combines cluster name with app name
name: '{{name}}-{{path.basename}}'
labels:
cluster: '{{name}}'
app: '{{path.basename}}'
spec:
project: production
source:
repoURL: https://github.com/org/apps.git
targetRevision: HEAD
path: '{{path}}'
destination:
server: '{{server}}'
namespace: '{{path.basename}}'
---
# -----------------------------------------------------------------------------
# Matrix Generator - Environments x Services
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: matrix-env-services
namespace: argocd
spec:
goTemplate: true
generators:
- matrix:
generators:
# Environments with their configurations
- list:
elements:
- env: dev
cluster: https://dev.example.com:6443
replicas: "1"
- env: staging
cluster: https://staging.example.com:6443
replicas: "2"
- env: production
cluster: https://prod.example.com:6443
replicas: "3"
# Services to deploy
- list:
elements:
- service: api
port: "8080"
- service: web
port: "3000"
- service: worker
port: "9000"
template:
metadata:
name: '{{ .env }}-{{ .service }}'
spec:
project: default
source:
repoURL: https://github.com/org/services.git
targetRevision: HEAD
path: 'services/{{ .service }}'
helm:
parameters:
- name: replicas
value: '{{ .replicas }}'
- name: service.port
value: '{{ .port }}'
destination:
server: '{{ .cluster }}'
namespace: '{{ .service }}'
---
# -----------------------------------------------------------------------------
# Matrix Generator - Nested (Three Levels)
# -----------------------------------------------------------------------------
# Note: Nested matrices allow 3+ dimensions but increase complexity
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: matrix-nested
namespace: argocd
spec:
goTemplate: true
generators:
- matrix:
generators:
# Outer matrix: regions x environments
- matrix:
generators:
- list:
elements:
- region: us-east
regionCode: use
- region: us-west
regionCode: usw
- list:
elements:
- env: dev
- env: prod
# Inner: applications
- git:
repoURL: https://github.com/org/apps.git
revision: HEAD
directories:
- path: apps/*
template:
metadata:
name: '{{ .regionCode }}-{{ .env }}-{{ .path.basename }}'
labels:
region: '{{ .region }}'
environment: '{{ .env }}'
app: '{{ .path.basename }}'
spec:
project: default
source:
repoURL: https://github.com/org/apps.git
targetRevision: HEAD
path: '{{ .path.path }}'
destination:
server: 'https://{{ .regionCode }}-{{ .env }}.example.com:6443'
namespace: '{{ .path.basename }}'
---
# -----------------------------------------------------------------------------
# Merge Generator - Override Defaults
# -----------------------------------------------------------------------------
# Merge combines generators using a key field for matching
# Later generators override earlier ones for matching keys
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: merge-override-example
namespace: argocd
spec:
goTemplate: true
generators:
- merge:
# Key field(s) used to match/merge entries
mergeKeys:
- cluster
generators:
# Base configuration for all clusters
- clusters:
selector:
matchLabels:
managed: "true"
values:
# Default values for all clusters
replicas: "2"
logLevel: info
memoryLimit: 512Mi
# Override specific clusters with different values
- list:
elements:
# Production cluster gets higher resources
- cluster: production
values:
replicas: "5"
logLevel: warn
memoryLimit: 2Gi
# Staging needs debug logging
- cluster: staging
values:
logLevel: debug
template:
metadata:
name: '{{ .name }}-app'
spec:
project: default
source:
repoURL: https://github.com/org/app.git
targetRevision: HEAD
path: deploy
helm:
parameters:
- name: replicas
value: '{{ .values.replicas }}'
- name: logging.level
value: '{{ .values.logLevel }}'
- name: resources.limits.memory
value: '{{ .values.memoryLimit }}'
destination:
server: '{{ .server }}'
namespace: myapp
---
# -----------------------------------------------------------------------------
# Merge Generator - Multiple Keys
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: merge-multi-key
namespace: argocd
spec:
goTemplate: true
generators:
- merge:
mergeKeys:
- env
- region
generators:
# Global defaults
- list:
elements:
- env: dev
region: us
replicas: "1"
resources: small
- env: dev
region: eu
replicas: "1"
resources: small
- env: prod
region: us
replicas: "3"
resources: large
- env: prod
region: eu
replicas: "3"
resources: large
# Region-specific overrides
- list:
elements:
# EU production needs more replicas for GDPR compliance
- env: prod
region: eu
replicas: "5"
resources: xlarge
template:
metadata:
name: '{{ .env }}-{{ .region }}-app'
spec:
project: default
source:
repoURL: https://github.com/org/app.git
targetRevision: HEAD
path: deploy
destination:
server: 'https://{{ .env }}-{{ .region }}.example.com:6443'
namespace: myapp
---
# -----------------------------------------------------------------------------
# Matrix vs Merge - When to Use Each
# -----------------------------------------------------------------------------
#
# USE MATRIX WHEN:
# - You need Cartesian product (all combinations)
# - Every combination should create an Application
# - Example: Deploy all apps to all clusters
#
# USE MERGE WHEN:
# - You have defaults that need selective overrides
# - Not all combinations should exist
# - Example: Base config with environment-specific exceptions
#
# NESTING LIMITS:
# - Matrix can nest other Matrix generators (but avoid deep nesting)
# - Merge cannot contain other Merge generators directly
# - Both can contain any single generator type
# =============================================================================
# =============================================================================
# SCM Provider and Pull Request Generator Examples
# =============================================================================
# SCM Provider: Auto-discover repositories from SCM platforms
# Pull Request: Create preview environments for PRs
# =============================================================================
# -----------------------------------------------------------------------------
# SCM Provider - GitHub Organization
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: scm-github-org
namespace: argocd
spec:
generators:
- scmProvider:
github:
organization: my-org
# Optional: Filter by topics
# topics: ["argocd", "kubernetes"]
# Optional: Authentication for private repos
tokenRef:
secretName: github-token
key: token
# Optional: GitHub Enterprise
# api: https://github.mycompany.com/api/v3/
# allBranches: true
# Filter repositories
filters:
# Only repos with specific path
- pathsExist:
- deploy/
# Match repository name pattern
- repositoryMatch: "^app-.*"
# Optional: Branch filter
# - branchMatch: "^main$"
template:
metadata:
name: '{{repository}}'
spec:
project: default
source:
repoURL: '{{url}}'
targetRevision: '{{branch}}'
path: deploy
destination:
server: https://kubernetes.default.svc
namespace: '{{repository}}'
---
# -----------------------------------------------------------------------------
# SCM Provider - GitLab Group
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: scm-gitlab-group
namespace: argocd
spec:
generators:
- scmProvider:
gitlab:
group: my-group
# Include subgroups
includeSubgroups: true
# Include shared projects
includeSharedProjects: false
# Authentication
tokenRef:
secretName: gitlab-token
key: token
# Optional: Self-hosted GitLab
# api: https://gitlab.mycompany.com/
filters:
- pathsExist:
- kubernetes/
- labelMatch: "deploy=true"
template:
metadata:
name: '{{repository}}'
spec:
project: default
source:
repoURL: '{{url}}'
targetRevision: '{{branch}}'
path: kubernetes
destination:
server: https://kubernetes.default.svc
namespace: '{{repository}}'
---
# -----------------------------------------------------------------------------
# SCM Provider - Azure DevOps
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: scm-azure-devops
namespace: argocd
spec:
generators:
- scmProvider:
azureDevOps:
organization: my-org
# Optional: Specific team project
teamProject: my-project
# Authentication (PAT token)
accessTokenRef:
secretName: azure-devops-token
key: token
# Optional: Azure DevOps Server (on-prem)
# api: https://dev.azure.com/
filters:
- pathsExist:
- charts/
- repositoryMatch: "^service-.*"
template:
metadata:
name: '{{repository}}'
labels:
organization: '{{organization}}'
spec:
project: default
source:
repoURL: '{{url}}'
targetRevision: '{{branch}}'
path: charts
destination:
server: https://kubernetes.default.svc
namespace: '{{repository}}'
---
# -----------------------------------------------------------------------------
# SCM Provider - Bitbucket Cloud
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: scm-bitbucket
namespace: argocd
spec:
generators:
- scmProvider:
bitbucket:
owner: my-workspace
# Authentication
appPasswordRef:
secretName: bitbucket-creds
key: password
user: bitbucket-user
filters:
- pathsExist:
- k8s/
template:
metadata:
name: '{{repository}}'
spec:
project: default
source:
repoURL: '{{url}}'
targetRevision: '{{branch}}'
path: k8s
destination:
server: https://kubernetes.default.svc
namespace: '{{repository}}'
---
# -----------------------------------------------------------------------------
# Pull Request Generator - GitHub
# -----------------------------------------------------------------------------
# Creates preview environments for open Pull Requests
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: pr-preview-github
namespace: argocd
spec:
generators:
- pullRequest:
github:
owner: my-org
repo: my-app
# Authentication for private repos
tokenRef:
secretName: github-token
key: token
# Optional: Only PRs with specific labels
labels:
- preview
- deploy
# Optional: GitHub Enterprise
# api: https://github.mycompany.com/api/v3/
# How often to check for changes (default 3m)
requeueAfterSeconds: 180
template:
metadata:
name: 'pr-{{number}}-{{branch_slug}}'
labels:
app.kubernetes.io/instance: 'pr-{{number}}'
annotations:
# Link back to PR
github.com/pull-request: '{{head_short_sha}}'
spec:
project: preview
source:
repoURL: 'https://github.com/my-org/my-app.git'
# Deploy from the PR branch
targetRevision: '{{head_sha}}'
path: deploy
helm:
parameters:
- name: image.tag
value: 'pr-{{number}}'
- name: ingress.host
value: 'pr-{{number}}.preview.example.com'
destination:
server: https://kubernetes.default.svc
namespace: 'preview-pr-{{number}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# -----------------------------------------------------------------------------
# Pull Request Generator - GitLab
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: pr-preview-gitlab
namespace: argocd
spec:
generators:
- pullRequest:
gitlab:
project: my-group/my-project
# Authentication
tokenRef:
secretName: gitlab-token
key: token
# Optional: Only MRs with specific labels
labels:
- deploy-preview
# MR state filter (default: opened)
pullRequestState: opened
requeueAfterSeconds: 180
template:
metadata:
name: 'mr-{{number}}'
spec:
project: preview
source:
repoURL: 'https://gitlab.com/my-group/my-project.git'
targetRevision: '{{head_sha}}'
path: deploy
destination:
server: https://kubernetes.default.svc
namespace: 'preview-mr-{{number}}'
---
# -----------------------------------------------------------------------------
# Pull Request Generator - Azure DevOps
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: pr-preview-azure
namespace: argocd
spec:
generators:
- pullRequest:
azuredevops:
organization: my-org
project: my-project
repo: my-repo
# Authentication
tokenRef:
secretName: azure-devops-token
key: token
# Optional: Filter by labels
labels:
- deploy
template:
metadata:
name: 'pr-{{number}}'
spec:
project: preview
source:
repoURL: 'https://dev.azure.com/my-org/my-project/_git/my-repo'
targetRevision: '{{head_sha}}'
path: deploy
destination:
server: https://kubernetes.default.svc
namespace: 'preview-pr-{{number}}'
---
# -----------------------------------------------------------------------------
# Available Parameters
# -----------------------------------------------------------------------------
# SCM Provider Parameters:
# {{organization}} - SCM organization/group name
# {{repository}} - Repository name
# {{url}} - Repository clone URL
# {{branch}} - Default branch name
# {{sha}} - Latest commit SHA
# {{short_sha}} - Short commit SHA (first 7 chars)
# {{labels}} - Repository labels/topics
#
# Pull Request Parameters:
# {{number}} - PR/MR number
# {{branch}} - Source branch name
# {{branch_slug}} - URL-safe branch name
# {{target_branch}} - Target/base branch
# {{target_branch_slug}} - URL-safe target branch
# {{head_sha}} - Full commit SHA
# {{head_short_sha}} - Short commit SHA
# {{head_short_sha_7}} - 7-char commit SHA
# {{labels}} - PR labels (array)
# =============================================================================
# =============================================================================
# App-of-Apps Pattern with ApplicationSets
# =============================================================================
# Bootstrap entire environments or clusters with a single ApplicationSet.
# Creates hierarchical application management with parent-child relationships.
# =============================================================================
# -----------------------------------------------------------------------------
# Pattern 1: Root ApplicationSet (Bootstrap)
# -----------------------------------------------------------------------------
# Single ApplicationSet that bootstraps all cluster components
#
# Repository structure:
# bootstrap/
# ├── argocd/ # ArgoCD itself
# ├── infrastructure/
# │ └── applicationset.yaml # Creates infra apps
# └── applications/
# └── applicationset.yaml # Creates business apps
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-bootstrap
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: https://github.com/org/gitops-bootstrap.git
revision: HEAD
directories:
- path: bootstrap/*
template:
metadata:
name: 'bootstrap-{{ .path.basename }}'
labels:
app.kubernetes.io/part-of: cluster-bootstrap
layer: bootstrap
spec:
project: bootstrap
source:
repoURL: https://github.com/org/gitops-bootstrap.git
targetRevision: HEAD
path: '{{ .path.path }}'
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# -----------------------------------------------------------------------------
# Pattern 2: Infrastructure Layer ApplicationSet
# -----------------------------------------------------------------------------
# Manages infrastructure components (cert-manager, ingress, monitoring, etc.)
#
# Repository structure:
# infrastructure/
# ├── cert-manager/
# │ └── config.yaml
# ├── external-dns/
# │ └── config.yaml
# ├── ingress-nginx/
# │ └── config.yaml
# └── monitoring/
# └── config.yaml
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: infrastructure
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: https://github.com/org/infrastructure.git
revision: HEAD
files:
- path: "*/config.yaml"
template:
metadata:
name: 'infra-{{ .name }}'
labels:
app.kubernetes.io/part-of: infrastructure
layer: infrastructure
component: '{{ .name }}'
annotations:
# Sync wave for ordering
argocd.argoproj.io/sync-wave: '{{ .syncWave | default "0" }}'
spec:
project: infrastructure
source:
chart: '{{ .chart }}'
repoURL: '{{ .repoURL }}'
targetRevision: '{{ .version }}'
helm:
releaseName: '{{ .name }}'
values: |
{{ .values | toYaml | nindent 12 }}
destination:
server: https://kubernetes.default.svc
namespace: '{{ .namespace }}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
---
# Example config.yaml for cert-manager:
# name: cert-manager
# chart: cert-manager
# repoURL: https://charts.jetstack.io
# version: "1.13.0"
# namespace: cert-manager
# syncWave: "-2"
# values:
# installCRDs: true
# prometheus:
# enabled: true
---
# -----------------------------------------------------------------------------
# Pattern 3: Application Layer with Dependencies
# -----------------------------------------------------------------------------
# Applications that depend on infrastructure components
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: applications
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: https://github.com/org/applications.git
revision: HEAD
files:
- path: "apps/*/app.yaml"
template:
metadata:
name: '{{ .name }}'
labels:
app.kubernetes.io/name: '{{ .name }}'
app.kubernetes.io/part-of: applications
layer: application
team: '{{ .team }}'
annotations:
# Applications sync after infrastructure
argocd.argoproj.io/sync-wave: '{{ .syncWave | default "10" }}'
notifications.argoproj.io/subscribe.on-sync-failed.slack: '{{ .team }}-alerts'
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: '{{ .project | default "default" }}'
sources:
- chart: '{{ .chart }}'
repoURL: '{{ .chartRepo }}'
targetRevision: '{{ .chartVersion }}'
helm:
releaseName: '{{ .name }}'
valueFiles:
- $values/{{ .name }}/values.yaml
- repoURL: https://github.com/org/helm-values.git
targetRevision: main
ref: values
destination:
server: https://kubernetes.default.svc
namespace: '{{ .namespace }}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# -----------------------------------------------------------------------------
# Pattern 4: Multi-Cluster App-of-Apps
# -----------------------------------------------------------------------------
# Bootstrap multiple clusters from a single ApplicationSet
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: multi-cluster-bootstrap
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- matrix:
generators:
# Target clusters
- clusters:
selector:
matchLabels:
bootstrap: enabled
# Components to deploy
- git:
repoURL: https://github.com/org/cluster-bootstrap.git
revision: HEAD
directories:
- path: components/*
template:
metadata:
name: '{{ .name }}-{{ .path.basename }}'
labels:
cluster: '{{ .name }}'
component: '{{ .path.basename }}'
spec:
project: cluster-bootstrap
source:
repoURL: https://github.com/org/cluster-bootstrap.git
targetRevision: HEAD
path: '{{ .path.path }}'
helm:
parameters:
- name: cluster.name
value: '{{ .name }}'
- name: cluster.server
value: '{{ .server }}'
destination:
server: '{{ .server }}'
namespace: '{{ .path.basename }}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# -----------------------------------------------------------------------------
# Pattern 5: Progressive Sync App-of-Apps
# -----------------------------------------------------------------------------
# Roll out applications progressively with RollingSync
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: progressive-rollout
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- clusters:
selector:
matchLabels:
environment: production
# Add rollout metadata
values:
rolloutGroup: production
# Progressive sync strategy
strategy:
type: RollingSync
rollingSync:
steps:
# Step 1: Canary cluster (10% traffic)
- matchExpressions:
- key: tier
operator: In
values:
- canary
maxUpdate: 1
# Step 2: Non-critical clusters
- matchExpressions:
- key: tier
operator: In
values:
- standard
maxUpdate: 2
# Step 3: Critical clusters (one at a time)
- matchExpressions:
- key: tier
operator: In
values:
- critical
maxUpdate: 1
template:
metadata:
name: '{{ .name }}-platform'
spec:
project: production
source:
repoURL: https://github.com/org/platform.git
targetRevision: HEAD
path: platform
destination:
server: '{{ .server }}'
namespace: platform
---
# -----------------------------------------------------------------------------
# Pattern 6: Environment-Based Hierarchy
# -----------------------------------------------------------------------------
# Structure: Root -> Environment -> Applications
#
# ApplicationSet hierarchy:
# root-bootstrap
# └── env-applicationsets (dev, staging, prod)
# └── app-applicationsets (per environment)
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: environment-bootstrap
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- list:
elements:
- env: dev
cluster: https://dev.example.com:6443
autoSync: "true"
project: development
- env: staging
cluster: https://staging.example.com:6443
autoSync: "true"
project: staging
- env: production
cluster: https://prod.example.com:6443
autoSync: "false" # Manual sync for production
project: production
template:
metadata:
name: '{{ .env }}-apps'
labels:
environment: '{{ .env }}'
layer: environment
spec:
project: '{{ .project }}'
source:
repoURL: https://github.com/org/gitops.git
targetRevision: HEAD
path: 'environments/{{ .env }}'
destination:
server: '{{ .cluster }}'
namespace: argocd
# Conditional sync policy
{{ if eq .autoSync "true" }}
syncPolicy:
automated:
prune: true
selfHeal: true
{{ end }}
---
# -----------------------------------------------------------------------------
# Supporting: AppProject for Bootstrap
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: bootstrap
namespace: argocd
spec:
description: Bootstrap project for cluster initialization
sourceRepos:
- https://github.com/org/*
destinations:
- namespace: '*'
server: '*'
# Allow creating other ApplicationSets
clusterResourceWhitelist:
- group: 'argoproj.io'
kind: ApplicationSet
- group: 'argoproj.io'
kind: Application
- group: 'argoproj.io'
kind: AppProject
- group: ''
kind: Namespace
---
# -----------------------------------------------------------------------------
# Best Practices for App-of-Apps
# -----------------------------------------------------------------------------
# 1. Layer Organization:
# Layer 0: Bootstrap (ArgoCD itself, base CRDs)
# Layer 1: Infrastructure (cert-manager, ingress, monitoring)
# Layer 2: Platform (databases, message queues, caches)
# Layer 3: Applications (business applications)
#
# 2. Sync Wave Ordering:
# -3: CRDs and cluster-wide resources
# -2: Certificate managers, secrets operators
# -1: Ingress controllers, DNS operators
# 0: Default (most applications)
# 10: Applications dependent on infrastructure
#
# 3. Dependency Management:
# - Use sync-waves to order deployments
# - Consider using sync hooks for critical dependencies
# - Use health checks to verify readiness
#
# 4. Project Isolation:
# - Separate projects per layer/environment
# - Limit cluster resources per project
# - Use RBAC to control access
#
# 5. Repository Structure:
# gitops-repo/
# ├── bootstrap/
# │ ├── argocd/
# │ └── root-applicationsets/
# ├── infrastructure/
# │ ├── cert-manager/
# │ └── ingress-nginx/
# ├── platform/
# │ ├── postgresql/
# │ └── redis/
# └── applications/
# ├── api-gateway/
# └── user-service/
# =============================================================================
# =============================================================================
# Monorepo Deployment Pattern
# =============================================================================
# Manage multiple applications from a single repository using Git generators.
# Supports automatic discovery based on directory structure.
# =============================================================================
# -----------------------------------------------------------------------------
# Pattern 1: Simple Directory Discovery
# -----------------------------------------------------------------------------
# Automatically create Applications for each app directory
#
# Repository structure:
# apps/
# ├── api-gateway/
# │ ├── kustomization.yaml
# │ └── ...
# ├── user-service/
# │ └── kustomization.yaml
# └── order-service/
# └── kustomization.yaml
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: monorepo-apps-discovery
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: https://github.com/org/monorepo.git
revision: HEAD
directories:
- path: apps/*
# Exclude specific directories
- path: apps/deprecated-*
exclude: true
template:
metadata:
name: '{{ .path.basename }}'
labels:
app.kubernetes.io/name: '{{ .path.basename }}'
app.kubernetes.io/part-of: monorepo
spec:
project: default
source:
repoURL: https://github.com/org/monorepo.git
targetRevision: HEAD
path: '{{ .path.path }}'
destination:
server: https://kubernetes.default.svc
namespace: '{{ .path.basename }}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# -----------------------------------------------------------------------------
# Pattern 2: Environment Overlays with Kustomize
# -----------------------------------------------------------------------------
# Repository structure:
# services/
# ├── api-gateway/
# │ ├── base/
# │ │ └── kustomization.yaml
# │ └── overlays/
# │ ├── dev/
# │ │ └── kustomization.yaml
# │ ├── staging/
# │ │ └── kustomization.yaml
# │ └── production/
# │ │ └── kustomization.yaml
# └── user-service/
# ├── base/
# └── overlays/
# ├── dev/
# ├── staging/
# └── production/
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: monorepo-kustomize-overlays
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: https://github.com/org/monorepo.git
revision: HEAD
directories:
# Match: services/{service}/overlays/{env}
- path: services/*/overlays/*
template:
metadata:
# segments: [0]=services, [1]=service-name, [2]=overlays, [3]=env
name: '{{ index .path.segments 3 }}-{{ index .path.segments 1 }}'
labels:
service: '{{ index .path.segments 1 }}'
environment: '{{ index .path.segments 3 }}'
spec:
project: '{{ index .path.segments 3 }}'
source:
repoURL: https://github.com/org/monorepo.git
targetRevision: HEAD
path: '{{ .path.path }}'
destination:
server: https://kubernetes.default.svc
namespace: '{{ index .path.segments 1 }}'
syncPolicy:
automated:
prune: true
selfHeal: true
---
# -----------------------------------------------------------------------------
# Pattern 3: Config File Discovery (JSON/YAML)
# -----------------------------------------------------------------------------
# Repository structure:
# apps/
# ├── api-gateway/
# │ └── config.yaml
# ├── user-service/
# │ └── config.yaml
# └── order-service/
# └── config.yaml
#
# config.yaml format:
# name: api-gateway
# team: platform
# namespace: gateway
# chart: nginx-ingress
# repoURL: https://kubernetes.github.io/ingress-nginx
# version: "4.8.0"
# values:
# controller:
# replicaCount: 3
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: monorepo-config-files
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: https://github.com/org/monorepo.git
revision: HEAD
files:
- path: apps/*/config.yaml
template:
metadata:
name: '{{ .name }}'
labels:
app.kubernetes.io/name: '{{ .name }}'
team: '{{ .team }}'
annotations:
notifications.argoproj.io/subscribe.on-sync-failed.slack: '{{ .team }}-alerts'
spec:
project: default
source:
chart: '{{ .chart }}'
repoURL: '{{ .repoURL }}'
targetRevision: '{{ .version }}'
helm:
releaseName: '{{ .name }}'
values: |
{{ .values | toYaml | nindent 12 }}
destination:
server: https://kubernetes.default.svc
namespace: '{{ .namespace }}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# -----------------------------------------------------------------------------
# Pattern 4: Matrix - Apps x Environments
# -----------------------------------------------------------------------------
# Deploy all apps to all environments
#
# Repository structure:
# apps/
# │ └── */deploy/ # App definitions
# environments/
# │ └── */config.yaml # Environment configs
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: monorepo-apps-envs-matrix
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- matrix:
generators:
# Applications
- git:
repoURL: https://github.com/org/monorepo.git
revision: HEAD
directories:
- path: apps/*/deploy
# Environments (from config files)
- git:
repoURL: https://github.com/org/monorepo.git
revision: HEAD
files:
- path: environments/*/config.yaml
template:
metadata:
# path.segments from first generator, env from second
name: '{{ .env }}-{{ index .path.segments 1 }}'
labels:
app: '{{ index .path.segments 1 }}'
environment: '{{ .env }}'
spec:
project: '{{ .env }}'
source:
repoURL: https://github.com/org/monorepo.git
targetRevision: HEAD
path: '{{ .path.path }}'
kustomize:
# Apply environment-specific patches
patches:
- target:
kind: Deployment
patch: |
- op: replace
path: /spec/replicas
value: {{ .replicas }}
destination:
server: '{{ .clusterUrl }}'
namespace: '{{ index .path.segments 1 }}'
---
# -----------------------------------------------------------------------------
# Pattern 5: Helm Charts in Monorepo
# -----------------------------------------------------------------------------
# Repository structure:
# charts/
# ├── api-gateway/
# │ ├── Chart.yaml
# │ ├── values.yaml
# │ └── templates/
# ├── user-service/
# │ ├── Chart.yaml
# │ ├── values.yaml
# │ └── templates/
# values/
# ├── dev/
# │ ├── api-gateway.yaml
# │ └── user-service.yaml
# └── prd/
# ├── api-gateway.yaml
# └── user-service.yaml
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: monorepo-helm-charts
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- matrix:
generators:
# Discover Helm charts
- git:
repoURL: https://github.com/org/monorepo.git
revision: HEAD
directories:
- path: charts/*
# Environments
- list:
elements:
- env: dev
cluster: https://dev.example.com:6443
- env: prd
cluster: https://prd.example.com:6443
template:
metadata:
name: '{{ .env }}-{{ .path.basename }}'
spec:
project: '{{ .env }}'
source:
repoURL: https://github.com/org/monorepo.git
targetRevision: HEAD
path: '{{ .path.path }}'
helm:
releaseName: '{{ .path.basename }}'
valueFiles:
# Chart default values + environment override
- values.yaml
- ../../values/{{ .env }}/{{ .path.basename }}.yaml
destination:
server: '{{ .cluster }}'
namespace: '{{ .path.basename }}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# -----------------------------------------------------------------------------
# Pattern 6: Nested Directories (Deep Monorepo)
# -----------------------------------------------------------------------------
# Repository structure:
# platform/
# ├── us-east/
# │ ├── dev/
# │ │ ├── api-gateway/
# │ │ └── user-service/
# │ └── prd/
# │ ├── api-gateway/
# │ └── user-service/
# └── eu-west/
# ├── dev/
# └── prd/
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: monorepo-nested-directories
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: https://github.com/org/monorepo.git
revision: HEAD
directories:
# Match: platform/{region}/{env}/{app}
- path: platform/*/*/**
template:
metadata:
# segments: [0]=platform, [1]=region, [2]=env, [3]=app
name: '{{ index .path.segments 1 }}-{{ index .path.segments 2 }}-{{ index .path.segments 3 }}'
labels:
region: '{{ index .path.segments 1 }}'
environment: '{{ index .path.segments 2 }}'
app: '{{ index .path.segments 3 }}'
spec:
project: '{{ index .path.segments 2 }}'
source:
repoURL: https://github.com/org/monorepo.git
targetRevision: HEAD
path: '{{ .path.path }}'
destination:
server: 'https://{{ index .path.segments 1 }}-{{ index .path.segments 2 }}.example.com:6443'
namespace: '{{ index .path.segments 3 }}'
---
# -----------------------------------------------------------------------------
# Best Practices for Monorepo Pattern
# -----------------------------------------------------------------------------
# 1. Directory Structure Conventions:
# - Use consistent naming (kebab-case)
# - Separate apps from shared configs
# - Group by logical boundaries (team, domain, environment)
#
# 2. Use .argocd-allow-deny for control:
# .argocd-allow-deny:
# allow:
# - path/to/allowed/*
# deny:
# - path/to/denied/*
#
# 3. Path Segments for naming:
# - index .path.segments N - Access specific directory level
# - .path.basename - Last directory name
# - .path.path - Full path
# - .path.filenameNormalized - Filename without extension
#
# 4. Exclude patterns for flexibility:
# directories:
# - path: apps/*
# - path: apps/legacy-*
# exclude: true
#
# 5. Config file validation:
# - Use JSON Schema to validate config.yaml files
# - Add pre-commit hooks to catch errors early
# =============================================================================
# =============================================================================
# Multi-Cluster Deployment Pattern
# =============================================================================
# Deploy applications across multiple Kubernetes clusters with environment-
# specific configurations. Uses Cluster generator with label selectors.
# =============================================================================
# -----------------------------------------------------------------------------
# Pattern 1: Environment-Based Multi-Cluster
# -----------------------------------------------------------------------------
# Deploy same app to dev/staging/production clusters
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: multi-cluster-by-environment
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- clusters:
selector:
matchLabels:
argocd.argoproj.io/secret-type: cluster
# Add custom values per cluster via labels
values:
helmValuesRepo: https://github.com/org/helm-values.git
template:
metadata:
name: '{{ .name }}-nginx'
labels:
app.kubernetes.io/name: nginx
cluster: '{{ .name }}'
environment: '{{ index .metadata.labels "environment" }}'
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: '{{ index .metadata.labels "environment" | default "default" }}'
sources:
# Helm chart from public repo
- chart: nginx
repoURL: https://charts.bitnami.com/bitnami
targetRevision: 15.0.0
helm:
releaseName: nginx
valueFiles:
# Base values
- $values/nginx/base/values.yaml
# Environment-specific values
- $values/nginx/{{ index .metadata.labels "environment" }}/values.yaml
# Cluster-specific values
- $values/nginx/clusters/{{ .name }}/values.yaml
# Values repository
- repoURL: '{{ .values.helmValuesRepo }}'
targetRevision: main
ref: values
destination:
server: '{{ .server }}'
namespace: nginx
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
---
# -----------------------------------------------------------------------------
# Pattern 2: Regional Multi-Cluster with Matrix
# -----------------------------------------------------------------------------
# Deploy apps to clusters organized by region and environment
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: regional-multi-cluster
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- matrix:
generators:
# Clusters by region
- clusters:
selector:
matchExpressions:
- key: region
operator: In
values:
- us-east
- us-west
- eu-west
# Applications to deploy
- list:
elements:
- app: api-gateway
namespace: gateway
chart: kong
repoURL: https://charts.konghq.com
version: "2.26.0"
- app: cert-manager
namespace: cert-manager
chart: cert-manager
repoURL: https://charts.jetstack.io
version: "1.13.0"
template:
metadata:
name: '{{ .name }}-{{ .app }}'
labels:
cluster: '{{ .name }}'
region: '{{ index .metadata.labels "region" }}'
app: '{{ .app }}'
spec:
project: infrastructure
source:
chart: '{{ .chart }}'
repoURL: '{{ .repoURL }}'
targetRevision: '{{ .version }}'
helm:
releaseName: '{{ .app }}'
destination:
server: '{{ .server }}'
namespace: '{{ .namespace }}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# -----------------------------------------------------------------------------
# Pattern 3: Cluster Groups with Merge Override
# -----------------------------------------------------------------------------
# Base config for all clusters with overrides for specific groups
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-groups-merge
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- merge:
mergeKeys:
- name
generators:
# Base configuration for all production clusters
- clusters:
selector:
matchLabels:
environment: production
values:
replicas: "3"
resources: standard
monitoring: enabled
logLevel: info
# Override for high-traffic clusters
- clusters:
selector:
matchLabels:
environment: production
tier: high-traffic
values:
replicas: "10"
resources: large
autoscaling: enabled
# Override for compliance clusters (PCI, HIPAA, etc.)
- clusters:
selector:
matchLabels:
environment: production
compliance: required
values:
logLevel: debug
auditLogging: enabled
encryptionAtRest: enabled
template:
metadata:
name: '{{ .name }}-workload'
annotations:
replicas: '{{ .values.replicas }}'
monitoring: '{{ .values.monitoring }}'
spec:
project: production
source:
repoURL: https://github.com/org/workloads.git
targetRevision: HEAD
path: workload
helm:
parameters:
- name: replicas
value: '{{ .values.replicas }}'
- name: resources.preset
value: '{{ .values.resources }}'
- name: logging.level
value: '{{ .values.logLevel }}'
destination:
server: '{{ .server }}'
namespace: workload
---
# -----------------------------------------------------------------------------
# Cluster Registration (Secret Format)
# -----------------------------------------------------------------------------
# Clusters must be registered as Secrets in ArgoCD namespace
# =============================================================================
apiVersion: v1
kind: Secret
metadata:
name: cluster-cafehyna-dev
namespace: argocd
labels:
# Required label for cluster discovery
argocd.argoproj.io/secret-type: cluster
# Custom labels for selection
environment: development
region: us-east
tier: standard
team: platform
type: Opaque
stringData:
name: cafehyna-dev
server: https://aks-dev.privatelink.eastus.azmk8s.io:443
# For clusters with bearer token auth
config: |
{
"bearerToken": "<token>",
"tlsClientConfig": {
"insecure": false,
"caData": "<base64-ca-cert>"
}
}
---
# Production cluster with compliance labels
apiVersion: v1
kind: Secret
metadata:
name: cluster-cafehyna-prd
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
environment: production
region: us-east
tier: high-traffic
compliance: required
team: platform
type: Opaque
stringData:
name: cafehyna-prd
server: https://aks-prd.privatelink.eastus.azmk8s.io:443
config: |
{
"bearerToken": "<token>",
"tlsClientConfig": {
"insecure": false,
"caData": "<base64-ca-cert>"
}
}
---
# -----------------------------------------------------------------------------
# Best Practices for Multi-Cluster
# -----------------------------------------------------------------------------
# 1. Use meaningful cluster labels:
# - environment: dev/staging/production
# - region: us-east/us-west/eu-west
# - tier: standard/high-traffic/critical
# - compliance: pci/hipaa/sox (if applicable)
# - team: platform/application/security
#
# 2. Organize values files hierarchically:
# helm-values/
# ├── base/
# │ └── values.yaml # Shared across all
# ├── dev/
# │ └── values.yaml # Dev environment
# ├── staging/
# │ └── values.yaml # Staging environment
# ├── production/
# │ └── values.yaml # Production environment
# └── clusters/
# ├── cafehyna-dev/
# │ └── values.yaml # Cluster-specific
# └── cafehyna-prd/
# └── values.yaml # Cluster-specific
#
# 3. Use projects for access control:
# - Different projects per environment
# - Restrict which clusters each project can deploy to
#
# 4. Progressive rollout:
# - Deploy to dev first, then staging, then production
# - Use Progressive Syncs (rollingSync) for safer deployments
# =============================================================================
# =============================================================================
# Pull Request Preview Environment Pattern
# =============================================================================
# Automatically create preview/ephemeral environments for Pull Requests.
# Supports GitHub, GitLab, Azure DevOps, and Bitbucket.
# =============================================================================
# -----------------------------------------------------------------------------
# Pattern 1: GitHub PR Preview
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: github-pr-preview
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- pullRequest:
github:
owner: my-org
repo: my-app
# Only PRs with these labels get preview environments
labels:
- preview
- deploy
# Authentication for private repos
tokenRef:
secretName: github-token
key: token
# GitHub Enterprise (optional)
# api: https://github.mycompany.com/api/v3/
# Check for new/closed PRs every 3 minutes
requeueAfterSeconds: 180
template:
metadata:
name: 'pr-{{ .number }}-{{ .branch_slug }}'
labels:
app.kubernetes.io/name: my-app
app.kubernetes.io/instance: 'pr-{{ .number }}'
preview: "true"
annotations:
# Link back to PR for easy navigation
github.com/pull-request-number: '{{ .number }}'
github.com/pull-request-sha: '{{ .head_sha }}'
github.com/pull-request-branch: '{{ .branch }}'
# Auto-cleanup when PR is closed
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: preview
source:
repoURL: https://github.com/my-org/my-app.git
# Deploy from the PR branch head
targetRevision: '{{ .head_sha }}'
path: deploy
helm:
releaseName: 'pr-{{ .number }}'
parameters:
# Dynamic image tag for PR
- name: image.tag
value: 'pr-{{ .number }}'
# Unique ingress hostname
- name: ingress.enabled
value: "true"
- name: ingress.hostname
value: 'pr-{{ .number }}.preview.example.com'
# Reduced resources for previews
- name: replicaCount
value: "1"
- name: resources.requests.memory
value: "256Mi"
- name: resources.requests.cpu
value: "100m"
values: |
# Preview-specific config
env:
ENVIRONMENT: preview
PR_NUMBER: "{{ .number }}"
BRANCH: "{{ .branch }}"
destination:
server: https://kubernetes.default.svc
namespace: 'preview-pr-{{ .number }}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- PruneLast=true
# Managed namespace with labels
managedNamespaceMetadata:
labels:
preview: "true"
pr-number: '{{ .number }}'
---
# -----------------------------------------------------------------------------
# Pattern 2: GitLab MR Preview
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: gitlab-mr-preview
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- pullRequest:
gitlab:
project: my-group/my-project
# Only open MRs
pullRequestState: opened
# Only MRs with these labels
labels:
- deploy-preview
tokenRef:
secretName: gitlab-token
key: token
# Self-hosted GitLab (optional)
# api: https://gitlab.mycompany.com/
requeueAfterSeconds: 180
template:
metadata:
name: 'mr-{{ .number }}'
labels:
app.kubernetes.io/instance: 'mr-{{ .number }}'
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: preview
source:
repoURL: https://gitlab.com/my-group/my-project.git
targetRevision: '{{ .head_sha }}'
path: kubernetes
kustomize:
nameSuffix: '-pr{{ .number }}'
images:
- 'my-app=registry.gitlab.com/my-group/my-project:{{ .head_short_sha }}'
destination:
server: https://kubernetes.default.svc
namespace: 'preview-mr-{{ .number }}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# -----------------------------------------------------------------------------
# Pattern 3: Azure DevOps PR Preview
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: azure-devops-pr-preview
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- pullRequest:
azuredevops:
organization: my-org
project: my-project
repo: my-repo
labels:
- preview
tokenRef:
secretName: azure-devops-token
key: token
requeueAfterSeconds: 180
template:
metadata:
name: 'pr-{{ .number }}'
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: preview
source:
repoURL: https://dev.azure.com/my-org/my-project/_git/my-repo
targetRevision: '{{ .head_sha }}'
path: deploy
destination:
server: https://kubernetes.default.svc
namespace: 'preview-pr-{{ .number }}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# -----------------------------------------------------------------------------
# Pattern 4: Full-Stack Preview (Multiple Services)
# -----------------------------------------------------------------------------
# Deploy multiple services for each PR using Matrix
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: fullstack-pr-preview
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- matrix:
generators:
# PRs
- pullRequest:
github:
owner: my-org
repo: my-fullstack-app
labels:
- preview
tokenRef:
secretName: github-token
key: token
# Services to deploy per PR
- list:
elements:
- service: frontend
path: services/frontend
port: "3000"
- service: backend
path: services/backend
port: "8080"
- service: database
path: services/database
port: "5432"
template:
metadata:
name: 'pr-{{ .number }}-{{ .service }}'
labels:
pr-number: '{{ .number }}'
service: '{{ .service }}'
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: preview
source:
repoURL: https://github.com/my-org/my-fullstack-app.git
targetRevision: '{{ .head_sha }}'
path: '{{ .path }}'
helm:
parameters:
- name: image.tag
value: 'pr-{{ .number }}'
# Service discovery within the preview namespace
- name: service.port
value: '{{ .port }}'
destination:
server: https://kubernetes.default.svc
# All services share the same namespace
namespace: 'preview-pr-{{ .number }}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# -----------------------------------------------------------------------------
# Pattern 5: Preview with External Database
# -----------------------------------------------------------------------------
# Connect PR previews to shared preview database
# =============================================================================
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: pr-preview-with-db
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- pullRequest:
github:
owner: my-org
repo: my-app
labels:
- preview
tokenRef:
secretName: github-token
key: token
template:
metadata:
name: 'pr-{{ .number }}'
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: preview
sources:
# Application
- repoURL: https://github.com/my-org/my-app.git
targetRevision: '{{ .head_sha }}'
path: deploy
helm:
releaseName: 'pr-{{ .number }}'
valueFiles:
- $values/preview-values.yaml
parameters:
- name: image.tag
value: 'pr-{{ .number }}'
# Use PR-specific database schema
- name: database.schema
value: 'pr_{{ .number }}'
- name: database.host
value: preview-db.example.com
# Shared preview values
- repoURL: https://github.com/my-org/helm-values.git
targetRevision: main
ref: values
destination:
server: https://kubernetes.default.svc
namespace: 'preview-pr-{{ .number }}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# -----------------------------------------------------------------------------
# Supporting Resources: ArgoCD Project for Previews
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: preview
namespace: argocd
spec:
description: Preview environments for Pull Requests
sourceRepos:
- https://github.com/my-org/*
destinations:
# Only allow preview namespaces
- namespace: 'preview-*'
server: https://kubernetes.default.svc
# Limited cluster resources for previews
clusterResourceWhitelist: []
namespaceResourceWhitelist:
- group: ''
kind: '*'
- group: 'apps'
kind: '*'
- group: 'networking.k8s.io'
kind: '*'
# Orphaned resource monitoring
orphanedResources:
warn: true
---
# -----------------------------------------------------------------------------
# GitHub Token Secret
# -----------------------------------------------------------------------------
apiVersion: v1
kind: Secret
metadata:
name: github-token
namespace: argocd
type: Opaque
stringData:
token: ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
---
# -----------------------------------------------------------------------------
# Available PR Parameters Reference
# -----------------------------------------------------------------------------
# {{number}} - PR/MR number
# {{branch}} - Source branch name
# {{branch_slug}} - URL-safe branch name (lowercase, dashes)
# {{target_branch}} - Target/base branch (e.g., main)
# {{target_branch_slug}} - URL-safe target branch
# {{head_sha}} - Full commit SHA (40 chars)
# {{head_short_sha}} - Short commit SHA (first 8 chars)
# {{head_short_sha_7}} - 7-character commit SHA
# {{labels}} - Array of PR labels
#
# Best Practices:
# 1. Use {{head_sha}} for targetRevision (immutable reference)
# 2. Use {{number}} for resource naming (unique identifier)
# 3. Use {{branch_slug}} when you need branch info in names
# 4. Always add finalizers for cleanup
# 5. Use dedicated project with limited permissions
# 6. Set resource limits to prevent preview sprawl
# 7. Consider TTL/auto-cleanup for old previews
# =============================================================================
# =============================================================================
# Basic Template Examples
# =============================================================================
# Templates define the Application structure. These examples cover common
# template patterns from simple to advanced.
# =============================================================================
# -----------------------------------------------------------------------------
# Minimal Template - Git Source
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: minimal-git-template
namespace: argocd
spec:
generators:
- list:
elements:
- name: app1
path: apps/app1
- name: app2
path: apps/app2
template:
metadata:
name: '{{name}}'
spec:
project: default
source:
repoURL: https://github.com/org/repo.git
targetRevision: HEAD
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{name}}'
---
# -----------------------------------------------------------------------------
# Helm Chart Template
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: helm-template
namespace: argocd
spec:
generators:
- list:
elements:
- app: nginx
chart: nginx
version: "15.0.0"
namespace: web
- app: redis
chart: redis
version: "18.0.0"
namespace: cache
template:
metadata:
name: '{{app}}'
spec:
project: default
source:
# Helm chart from repository
chart: '{{chart}}'
repoURL: https://charts.bitnami.com/bitnami
targetRevision: '{{version}}'
helm:
releaseName: '{{app}}'
# Inline values
values: |
replicaCount: 2
resources:
requests:
memory: 256Mi
cpu: 100m
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
---
# -----------------------------------------------------------------------------
# Template with Full Metadata
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: full-metadata-template
namespace: argocd
spec:
generators:
- list:
elements:
- name: frontend
team: ui
tier: web
oncall: frontend-team
- name: backend
team: api
tier: service
oncall: backend-team
template:
metadata:
name: '{{name}}'
labels:
app.kubernetes.io/name: '{{name}}'
app.kubernetes.io/managed-by: argocd
team: '{{team}}'
tier: '{{tier}}'
annotations:
# Notification subscriptions
notifications.argoproj.io/subscribe.on-sync-succeeded.slack: '{{oncall}}'
notifications.argoproj.io/subscribe.on-sync-failed.slack: '{{oncall}}'
notifications.argoproj.io/subscribe.on-health-degraded.slack: '{{oncall}}'
# Custom annotations
support-team: '{{team}}'
# Finalizers for cleanup
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/org/apps.git
targetRevision: HEAD
path: 'apps/{{name}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{name}}'
# Info links for ArgoCD UI
info:
- name: Documentation
value: 'https://docs.example.com/{{name}}'
- name: Runbook
value: 'https://runbooks.example.com/{{name}}'
- name: Dashboard
value: 'https://grafana.example.com/d/{{name}}'
---
# -----------------------------------------------------------------------------
# Template with Sync Policy
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: sync-policy-template
namespace: argocd
spec:
generators:
- list:
elements:
- name: critical-app
autoSync: "true"
prune: "true"
- name: manual-app
autoSync: "false"
prune: "false"
template:
metadata:
name: '{{name}}'
spec:
project: default
source:
repoURL: https://github.com/org/apps.git
targetRevision: HEAD
path: '{{name}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{name}}'
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
syncOptions:
- Validate=true
- CreateNamespace=true
- PrunePropagationPolicy=foreground
- PruneLast=true
- ApplyOutOfSyncOnly=true
- ServerSideApply=true
# Managed namespace metadata
managedNamespaceMetadata:
labels:
managed-by: argocd
app: '{{name}}'
---
# -----------------------------------------------------------------------------
# Template with Ignore Differences
# -----------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: ignore-diff-template
namespace: argocd
spec:
generators:
- list:
elements:
- name: stateful-app
template:
metadata:
name: '{{name}}'
spec:
project: default
source:
repoURL: https://github.com/org/apps.git
targetRevision: HEAD
path: '{{name}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{name}}'
ignoreDifferences:
# Ignore deployment replicas (managed by HPA)
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas
# Ignore dynamic annotations
- group: apps
kind: Deployment
jqPathExpressions:
- .metadata.annotations["deployment.kubernetes.io/revision"]
- .metadata.annotations["kubectl.kubernetes.io/last-applied-configuration"]
# Ignore Service cluster IPs
- group: ""
kind: Service
jsonPointers:
- /spec/clusterIP
- /spec/clusterIPs
# Ignore specific field in named resource
- group: ""
kind: ConfigMap
name: dynamic-config
jsonPointers:
- /data/lastUpdated
# Ignore PVC capacity (Azure disk resizing)
- group: ""
kind: PersistentVolumeClaim
jsonPointers:
- /spec/resources/requests/storage
# Ignore StatefulSet VolumeClaimTemplate drift
- group: apps
kind: StatefulSet
jqPathExpressions:
- .spec.volumeClaimTemplates[]?.apiVersion
- .spec.volumeClaimTemplates[]?.kind
- .spec.volumeClaimTemplates[]?.status
CreateRootApplication Workflow
Create a root ArgoCD Application (app-of-apps pattern) that manages ApplicationSets via Kustomize for GitOps lifecycle management.
Step 1: Audit the ApplicationSet Directory
List all YAML files in the ApplicationSet directory:
ls infra-team/applicationset/*.yamlCategorize each file:
- Active: Currently deployed on the cluster (verify with
kubectl get applicationset -n argocd) - Template: Contains placeholders like
<SERVICE_NAME>(e.g.,TEMPLATE.yaml) - WIP: Work-in-progress files (e.g.,
*-wip.yaml) - Duplicate: Files defining the same ApplicationSet name as another file
CRITICAL: Only active files go in the kustomization. Including templates or WIP files would deploy broken resources.
Step 2: Check for Name Conflicts
Scan all ApplicationSet files for duplicate metadata.name values:
grep -h "^ name:" infra-team/applicationset/*.yaml | sort | uniq -dIf duplicates exist, determine which file is the canonical one (usually the one matching the cluster state) and exclude the other.
Step 3: Create kustomization.yaml
Create infra-team/applicationset/kustomization.yaml with only the curated active files:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# Active ApplicationSets managed by the root-applicationsets Application.
# Only files listed here are deployed to ArgoCD.
# To add a new ApplicationSet: create the YAML, add it here, commit and push.
resources:
- addon-one.yaml
- addon-two.yaml
# NOTE: template.yaml and wip files are excludedWhy Kustomize over raw directory?
- Explicit control over what gets deployed
- Safe exclusion of templates, WIP, and experimental files
- Adding/removing is a single-line change in Git
prune: truemeans removing from the list also removes from the cluster
Step 4: Create the Root Application
Create infra-team/bootstrap/root-applicationsets.yaml:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-applicationsets
namespace: argocd
labels:
app.kubernetes.io/name: root-applicationsets
app.kubernetes.io/part-of: argocd-bootstrap
app.kubernetes.io/component: applicationset-management
app.kubernetes.io/managed-by: argocd
annotations:
argocd.argoproj.io/sync-wave: "-10"
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: <GIT_REPO_URL>
targetRevision: main
path: infra-team/applicationset
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- ServerSideApply=true
- CreateNamespace=false
- Validate=true
- ApplyOutOfSyncOnly=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3mKey design decisions:
- sync-wave: "-10": Deploys before any ApplicationSet (which default to wave 0)
- prune: true: Removing a file from kustomization.yaml deletes the ApplicationSet
- ServerSideApply: Prevents conflicts when adopting existing ApplicationSets
- ApplyOutOfSyncOnly: Avoids unnecessary re-syncing of unchanged resources
- project: default: Root app uses default project for maximum permissions
Step 5: Validate with Kustomize Build
kustomize build infra-team/applicationset/ | head -50Verify:
- All listed resources are valid YAML
- No template placeholders remain
- No duplicate resource names
Step 6: Run Pre-Commit Checks
pre-commit run --all-filesFix any yamllint or validation errors before committing.
Step 7: Commit and Push
git add infra-team/applicationset/kustomization.yaml infra-team/bootstrap/root-applicationsets.yaml
git commit -m "feat(argocd): add root Application for GitOps ApplicationSet management"
git pushStep 8: Bootstrap (One-Time Manual Step)
The root Application must be applied ONCE to ArgoCD. After this, all future changes are via Git.
Option A: ArgoCD UI 1. ArgoCD UI > + NEW APP 2. Paste the YAML from infra-team/bootstrap/root-applicationsets.yaml 3. Click CREATE
Option B: ArgoCD CLI (if available)
argocd app create -f infra-team/bootstrap/root-applicationsets.yamlStep 9: Verify
# Root app synced
KUBECONFIG=~/.kube/<config> kubectl get application root-applicationsets -n argocd
# All ApplicationSets present
KUBECONFIG=~/.kube/<config> kubectl get applicationset -n argocd
# No orphaned ApplicationSets (all managed by root app)
KUBECONFIG=~/.kube/<config> kubectl get applicationset -n argocd -o json | jq '.items[].metadata.ownerReferences'Future Workflow
To add a new ApplicationSet after root app is deployed: 1. Create the YAML in infra-team/applicationset/ 2. Add the filename to infra-team/applicationset/kustomization.yaml 3. Commit and push — ArgoCD auto-deploys it
To remove an ApplicationSet: 1. Remove the filename from kustomization.yaml 2. Commit and push — ArgoCD auto-prunes it (if prune: true)