Argo CD ApplicationSet Controller: Multi-Cluster GitOps Automation Explained
The Argo CD ApplicationSet controller is a Kubernetes controller that watches the ApplicationSet custom resource and automatically reconciles a fleet of Argo CD Application objects using generators, templates, and progressive sync policies.
The Argo CD ApplicationSet controller, housed in the argoproj/argo-cd repository, extends Argo CD’s capabilities by enabling declarative management of multiple Application resources across clusters and environments. Unlike the standard Application controller which manages individual deployments, this controller implements a reconcile loop that generates, validates, and synchronizes entire sets of applications based on dynamic data sources such as Git repositories, cluster lists, or SCM providers.
How the Argo CD ApplicationSet Controller Works
The controller implements a standard Kubernetes controller pattern through a five-stage reconcile loop defined in applicationset/controllers/applicationset_controller.go:
- Read the
ApplicationSetspec to extract generator configurations and templates. - Generate desired
Applicationresources by invoking configured generators and executingtemplate.GenerateApplicationsfromapplicationset/template/template.go. - Validate generated applications against project existence, destination validity, and duplicate application names.
- Reconcile the current cluster state by creating new applications, updating changed ones via
createOrUpdateInCluster, and deleting stale resources. - Update the
ApplicationSetstatus usingupdateResourcesStatusandsetAppSetApplicationStatusto reflect resource health, progressive sync progress, and error conditions.
Core Architecture and Implementation
Reconciliation Logic in applicationset_controller.go
The primary entry point is the Reconcile(ctx, req) method in applicationset/controllers/applicationset_controller.go. This method drives the entire lifecycle process, handling resource deletion, progressive synchronization, and status migration. It manages complex scenarios such as invalid destinations through removeFinalizerOnInvalidDestination, which ensures finalizers are cleaned up when target clusters become unreachable, preventing deletion deadlocks.
Generator Plugin System
The controller delegates application generation to pluggable generators located in applicationset/generators/. Each generator—whether List, Git, Cluster, or SCM—produces parameter sets that the controller passes to template.GenerateApplications. This architecture allows the ApplicationSet to dynamically create Application manifests based on external data sources, such as discovering directories in a Git repository or listing available clusters from cluster secrets.
Progressive Sync and Rollout Management
The experimental progressive sync feature, implemented in applicationset/progressivesync, enables phased rollouts of applications across clusters. When the controller starts with the --enable-progressive-syncs flag, it executes the steps defined in spec.progressiveSync (such as pause or sync) sequentially rather than simultaneously. The controller updates the ApplicationSet status with rollout progress, allowing for canary-style deployments or maintenance windows.
Ownership and Finalizer Management
The controller establishes strict ownership relationships by adding the ApplicationSet as an OwnerReference to each generated Application. This ensures Kubernetes garbage collection removes dependent applications when the parent ApplicationSet is deleted. The finalizer logic guarantees safe deletion even when destination clusters become invalid, using removeFinalizerOnInvalidDestination to clean up resources that can no longer reach their targets.
Deployment and Operational Configuration
Controller Flags and Runtime Options
The controller runs as the binary argocd-applicationset-controller, typically deployed as a separate pod (argocd-applicationset-controller) with its own ServiceAccount and RBAC bindings. Key operational flags include:
--concurrent-application-updates: Controls parallelism for application modifications (default varies by version).--enable-progressive-syncs: Activates the experimental progressive rollout feature.--metrics-addr: Exposes Prometheus metrics viaApplicationsetMetrics(default:8080).
Documentation for these flags is maintained in docs/operator-manual/server-commands/argocd-applicationset-controller.md.
RBAC and Kubernetes Resources
Deployment manifests reside in manifests/base/applicationset-controller/, defining the controller’s Deployment, ServiceAccount, Role, and ClusterRole bindings. The Custom Resource Definition for the ApplicationSet API, including all generator and sync policy specifications, is defined in manifests/crds/applicationset-crd.yaml. Detailed specification documentation is available in docs/operator-manual/applicationset/applicationset-specification.md.
Practical Implementation Examples
Basic List Generator Configuration
The following manifest uses the list generator to create two Application resources—one for development and one for production—from a single template:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- list:
elements:
- cluster: dev
url: https://k8s.dev.example.com
- cluster: prod
url: https://k8s.prod.example.com
template:
metadata:
name: '{{cluster}}-guestbook'
spec:
project: default
source:
repoURL: https://github.com/argoproj/guestbook
path: helm
targetRevision: HEAD
destination:
server: '{{url}}'
namespace: guestbook
The controller processes the list elements and generates two separate Application objects, substituting {{cluster}} and {{url}} with the respective values.
Progressive Sync with Rolling Strategy
To enable phased rollouts across multiple applications, configure the progressiveSync field and ensure the controller runs with --enable-progressive-syncs:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: rolling-demo
spec:
syncPolicy:
syncOptions:
- CreateNamespace=true
progressiveSync:
steps:
- pause: {}
- sync: {}
generators:
- git:
repoURL: https://github.com/example/applications
revision: main
directories:
- path: '*'
template:
metadata:
name: '{{path.basename}}'
spec:
project: default
source:
repoURL: https://github.com/example/applications
targetRevision: main
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: default
This configuration pauses before syncing each application discovered in the Git repository, allowing for manual verification or automated checks between steps.
Running the Controller Locally
For development or debugging outside of cluster deployments, execute the controller directly with specific flags:
# Start the controller inside the cluster (usually launched by the Helm chart)
argocd-applicationset-controller \
--loglevel info \
--concurrent-application-updates 5 \
--enable-progressive-syncs \
--metrics-addr :8080
This command exposes metrics on port 8080 and limits concurrent updates to five applications to prevent API server throttling.
Summary
- The Argo CD ApplicationSet controller automates the creation and management of multiple Application resources from a single declarative specification, turning high-level descriptions into concrete Argo CD applications.
- It implements a reconcile loop in
applicationset/controllers/applicationset_controller.gothat generates applications via pluggable generators, validates them against project and destination constraints, and reconciles cluster state. - The controller supports advanced rollout strategies through progressive sync, managed via the
applicationset/progressivesyncpackage, when enabled with the--enable-progressive-syncsflag. - It handles resource ownership through Kubernetes owner references and finalizers to ensure safe deletion and prevent orphaned resources.
- Deployed as the
argocd-applicationset-controllerbinary with dedicated RBAC, it operates independently from the main Argo CD server and exposes metrics viaApplicationsetMetrics.
Frequently Asked Questions
What is the difference between Application and ApplicationSet in Argo CD?
An Application is a single deployable unit targeting one specific cluster and source repository, while an ApplicationSet is a parent resource that generates and manages multiple Application objects across clusters or environments. The ApplicationSet controller watches the ApplicationSet CR and reconciles the desired state of the underlying Application fleet, enabling template-based multi-cluster deployments.
How does the ApplicationSet controller handle application deletion?
When an ApplicationSet is deleted, the controller uses Kubernetes owner references to ensure all generated Application resources are garbage collected. Additionally, the removeFinalizerOnInvalidDestination function in applicationset_controller.go removes finalizers from applications when their target clusters become unreachable, preventing deletion deadlocks and ensuring clean resource removal.
What generators are available in the Argo CD ApplicationSet controller?
The controller supports multiple generators defined in applicationset/generators/, including the List generator (for static parameter sets), Git generator (for directories or files in repositories), Cluster generator (for discovered clusters from secrets), and SCM generator (for pull requests in source control providers). Each generator produces parameter sets that feed into the Application template rendering process.
Is progressive sync production-ready in Argo CD?
Progressive sync remains an experimental feature as implemented in the applicationset/progressivesync package. It requires explicitly enabling the --enable-progressive-syncs flag on the argocd-applicationset-controller binary and defining rollout steps in the spec.progressiveSync field. Check the official Argo CD documentation and release notes for current maturity status before deploying in production environments.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →