Skip to content
Published on

[ArgoCD] ApplicationSet Controller Deep Dive

Authors

1. ApplicationSet Overview

ApplicationSet is an ArgoCD extension controller that automatically creates and manages multiple ArgoCD Applications from a single ApplicationSet resource. It enables efficient management of hundreds of Applications in large-scale multi-cluster, multi-tenant environments.

Core Components

ApplicationSet Controller
    |
    +-- Generator: Data source for generating Application lists
    |
    +-- Template: Application resource template
    |
    +-- Sync Policy: Application create/delete/update policies

Basic ApplicationSet Structure

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: my-appset
  namespace: argocd
spec:
  generators:
    - list:
        elements:
          - cluster: staging
            url: https://staging.example.com
          - cluster: production
            url: https://production.example.com
  template:
    metadata:
      name: 'myapp-{{cluster}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/org/myapp.git
        targetRevision: HEAD
        path: 'overlays/{{cluster}}'
      destination:
        server: '{{url}}'
        namespace: myapp

2. Generator Types in Detail

List Generator

The simplest Generator, producing parameters from a static list:

spec:
  generators:
    - list:
        elements:
          - cluster: staging
            url: https://staging.example.com
            revision: develop
          - cluster: production
            url: https://production.example.com
            revision: main

Cluster Generator

Creates Applications based on clusters registered with ArgoCD:

spec:
  generators:
    - clusters:
        selector:
          matchLabels:
            env: production
            region: ap-northeast-2

Cluster Generator parameters:

ParameterDescription
nameCluster name
serverCluster API server URL
metadata.labelsLabels set on the cluster
metadata.annotationsAnnotations set on the cluster

Git Generator - Directory

Scans the directory structure of a Git repository to create Applications:

spec:
  generators:
    - git:
        repoURL: https://github.com/org/gitops-config.git
        revision: HEAD
        directories:
          - path: apps/*
          - path: apps/excluded-app
            exclude: true

Generated parameters:

ParameterExample
pathapps/frontend
path.basenamefrontend
path[0]apps
path[1]frontend
path.basenameNormalizedfrontend (RFC 1123 compliant)

Git Generator - File

Reads parameters from JSON/YAML files in a Git repository:

spec:
  generators:
    - git:
        repoURL: https://github.com/org/gitops-config.git
        revision: HEAD
        files:
          - path: 'clusters/*/config.json'

Example config.json:

{
  "cluster": {
    "name": "production-east",
    "server": "https://prod-east.example.com",
    "environment": "production",
    "region": "us-east-1"
  }
}

Referencing nested fields in templates:

template:
  metadata:
    name: 'app-{{cluster.name}}'
  spec:
    destination:
      server: '{{cluster.server}}'

Matrix Generator

Combines two Generators to produce a Cartesian Product:

spec:
  generators:
    - matrix:
        generators:
          - clusters:
              selector:
                matchLabels:
                  env: production
          - git:
              repoURL: https://github.com/org/apps.git
              revision: HEAD
              directories:
                - path: apps/*

Result example:

(cluster=prod-east, path=apps/frontend)
(cluster=prod-east, path=apps/backend)
(cluster=prod-west, path=apps/frontend)
(cluster=prod-west, path=apps/backend)

Merge Generator

Merges results from multiple Generators by a common key:

spec:
  generators:
    - merge:
        mergeKeys:
          - server
        generators:
          - clusters:
              values:
                replicas: '3'
                env: default
          - list:
              elements:
                - server: https://production.example.com
                  values.replicas: '5'
                  values.env: production

Override values are applied for items matching the server key.

PullRequest Generator

Detects PRs from Git hosting services to auto-create preview environments:

spec:
  generators:
    - pullRequest:
        github:
          owner: myorg
          repo: myapp
          labels:
            - preview
        requeueAfterSeconds: 60
  template:
    metadata:
      name: 'preview-{{branch}}-{{number}}'
    spec:
      source:
        repoURL: https://github.com/myorg/myapp.git
        targetRevision: '{{head_sha}}'
        path: deploy/preview
      destination:
        server: https://kubernetes.default.svc
        namespace: 'preview-{{number}}'

PullRequest Generator parameters:

ParameterDescription
numberPR number
branchSource branch name
branch_slugURL-safe branch name
head_shaHEAD commit SHA
head_short_shaShort HEAD SHA
labelsLabels on the PR

SCMProvider Generator

Auto-discovers repositories from SCM (Source Code Management) providers:

spec:
  generators:
    - scmProvider:
        github:
          organization: myorg
          allBranches: false
        filters:
          - repositoryMatch: '^gitops-.*'
            pathsExist:
              - deploy/kustomization.yaml

Supported SCM providers: GitHub, GitLab, Bitbucket Server, Azure DevOps, Gitea

3. Template Rendering Engine

Default Template Syntax

ApplicationSet uses double curly brace syntax for parameter references, substituted with values from Generators.

template:
  metadata:
    name: 'app-{{cluster}}-{{path.basename}}'
    labels:
      env: '{{values.env}}'
  spec:
    source:
      repoURL: '{{url}}'
      path: '{{path}}'
    destination:
      server: '{{server}}'
      namespace: '{{namespace}}'

Go Template Mode

For more complex logic, Go templates can be used:

spec:
  goTemplate: true
  goTemplateOptions: ['missingkey=error']
  template:
    metadata:
      name: 'app-{{ .cluster | lower }}'
    spec:
      source:
        path: '{{ if eq .env "production" }}overlays/prod{{ else }}overlays/dev{{ end }}'

fasttemplate vs Go Template Comparison

Featurefasttemplate (default)Go Template
SyntaxDouble curly braces (variable substitution only)Full Go template syntax
ConditionalsNot possiblePossible (if/else)
LoopsNot possiblePossible (range)
FunctionsNot possibleSprig functions available
PerformanceFastRelatively slower
ConfigDefaultgoTemplate: true required

4. Progressive Sync

Rolling Sync Strategy

ApplicationSet provides progressive synchronization of multiple Applications:

spec:
  strategy:
    type: RollingSync
    rollingSync:
      steps:
        - matchExpressions:
            - key: env
              operator: In
              values:
                - staging
          maxUpdate: 100%
        - matchExpressions:
            - key: env
              operator: In
              values:
                - production
          maxUpdate: 25%

Progressive Sync Flow

Step 1: Sync all Applications with staging label
  -> Wait until all are Healthy

Step 2: Sync only 25% of Applications with production label
  -> Verify Healthy, proceed to next 25%
  -> Repeat until all production Applications are complete

maxUpdate Options

ValueDescription
100%Update all matching Applications simultaneously
25%Update only 25% of matching Applications
1Update only 1 at a time
0No auto-update (manual progression)

5. Cluster Decision Resource

External controllers can determine target clusters for Applications:

spec:
  generators:
    - clusterDecisionResource:
        configMapRef: my-placement-decision
        name: placement-decision
        requeueAfterSeconds: 180

Use cases: Open Cluster Management (OCM) integration, custom cluster selection logic, external policy engine-based routing.

6. Reconciliation Loop

ApplicationSet Controller Reconciliation

Loop:
  1. Watch all ApplicationSet resources (Informer)
  2. For each ApplicationSet:
     a. Execute Generator to produce parameter sets
     b. Render template to produce desired Application list
     c. Query existing Application list
     d. Compare and:
        - Create new Applications
        - Update changed Applications
        - Delete removed Applications (per policy)
  3. Re-execute after requeueAfterSeconds

Requeue Mechanism

spec:
  generators:
    - pullRequest:
        github:
          owner: myorg
          repo: myapp
        requeueAfterSeconds: 60

Event-Driven Reconciliation

The controller responds immediately to:

  • ApplicationSet resource changes
  • ArgoCD cluster Secret changes
  • Git Webhook receipt (Git Generator)

7. Application Lifecycle Management

Deletion Policy

spec:
  syncPolicy:
    preserveResourcesOnDeletion: true # Keep Applications when ApplicationSet is deleted
OptionBehavior
preserveResourcesOnDeletion: falseDelete all Applications when ApplicationSet is deleted
preserveResourcesOnDeletion: trueKeep Applications even when ApplicationSet is deleted

8. Practical Patterns

Multi-Cluster Deployment

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: platform-services
  namespace: argocd
spec:
  generators:
    - matrix:
        generators:
          - clusters:
              selector:
                matchLabels:
                  tier: production
          - git:
              repoURL: https://github.com/org/platform.git
              revision: HEAD
              directories:
                - path: services/*
  template:
    metadata:
      name: '{{name}}-{{path.basename}}'
    spec:
      project: platform
      source:
        repoURL: https://github.com/org/platform.git
        targetRevision: HEAD
        path: '{{path}}'
      destination:
        server: '{{server}}'
        namespace: '{{path.basename}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true

PR Preview Environments

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: preview-envs
  namespace: argocd
spec:
  generators:
    - pullRequest:
        github:
          owner: myorg
          repo: myapp
          labels:
            - deploy-preview
        requeueAfterSeconds: 30
  template:
    metadata:
      name: 'preview-{{number}}'
    spec:
      project: previews
      source:
        repoURL: https://github.com/myorg/myapp.git
        targetRevision: '{{head_sha}}'
        path: deploy/preview
        helm:
          parameters:
            - name: ingress.host
              value: 'pr-{{number}}.preview.example.com'
            - name: image.tag
              value: '{{head_short_sha}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: 'preview-{{number}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true

9. Troubleshooting

Common Issues

Applications not being created:

  • Verify Generator selector is correct
  • Verify Git paths exist
  • Check ApplicationSet Controller logs

Applications unexpectedly deleted:

  • Check preserveResourcesOnDeletion setting
  • Verify if Generator output has changed
  • Review ApplicationSet ownership management

Template rendering errors:

  • Verify parameter names match Generator output
  • Check goTemplate: true is set for Go templates
  • Review goTemplateOptions for missingkey handling

Debugging Commands

# Check ApplicationSet status
kubectl get applicationset -n argocd

# View ApplicationSet details
kubectl describe applicationset my-appset -n argocd

# Check ApplicationSet Controller logs
kubectl logs -n argocd deployment/argocd-applicationset-controller

# List generated Applications
argocd app list

10. Summary

Key elements of the ApplicationSet Controller:

  1. Generators: Produce parameters from diverse data sources (clusters, Git, PR, SCM)
  2. Matrix/Merge: Combine Generators for complex deployment topologies
  3. Template Engine: Render Application resources with fasttemplate or Go templates
  4. Progressive Sync: Safe large-scale deployments with rolling update strategies
  5. Reconciliation: Event-driven + periodic polling for state synchronization
  6. Lifecycle Management: Automatic Application management with create/update/delete policies

Effective use of ApplicationSet enables managing hundreds of Applications from a single resource, dramatically reducing operational complexity in large-scale GitOps environments.