ApplicationSet is a Kubernetes controller that extends Argo CD to manage multiple Git repositories and generate Argo CD Application resources dynamically.
Here’s a quick example of how it works. Imagine you have a Git repository structure like this:
├── apps
│ ├── dev
│ │ └── my-app.yaml
│ └── prod
│ └── my-app.yaml
└── clusters
├── dev-cluster.yaml
└── prod-cluster.yaml
And you want to deploy my-app to both your dev and prod environments. You can create an ApplicationSet resource that looks like this:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: my-app-set
spec:
generators:
- git:
repoURL: https://github.com/your-org/your-repo.git
revision: HEAD
files:
- "apps/**/my-app.yaml"
template:
metadata:
name: '{{.path.basename}}-{{.path.dirname}}'
spec:
project: default
source:
repoURL: https://github.com/your-org/your-repo.git
path: '{{.path.path}}'
targetRevision: HEAD
destination:
server: 'https://kubernetes.default.svc'
namespace: '{{.path.dirname}}' # This will be 'dev' or 'prod'
When Argo CD processes this ApplicationSet, it will:
-
Scan the Git repository: It looks for files matching the pattern
"apps/**/my-app.yaml". -
Generate Applications: For each matching file, it creates an Argo CD
Applicationresource.-
It uses
{{.path.basename}}and{{.path.dirname}}to dynamically name the application. Forapps/dev/my-app.yaml, the name would bemy-app-dev. -
It uses
{{.path.path}}to set thepathin thesourceof theApplicationto the directory containing the manifest. So, forapps/dev/my-app.yaml, the path will beapps/dev. -
It uses
{{.path.dirname}}to set thenamespacein thedestinationof theApplicationtodevorprodbased on the directory structure.
-
This results in two Argo CD Application resources being created:
my-app-dev: Targets thedevnamespace and points to theapps/devdirectory in your Git repo.my-app-prod: Targets theprodnamespace and points to theapps/proddirectory in your Git repo.
The most surprising true thing about ApplicationSet is that it doesn’t just iterate over files; it can also iterate over directories, Git branches, clusters, and even arbitrary JSON data to generate applications. This allows for incredibly flexible and scalable GitOps management.
For instance, if you wanted to deploy my-app to multiple clusters defined in your Git repo, you could use a clusterGenerator. Let’s say you have a clusters directory with files like dev-cluster.yaml and prod-cluster.yaml, each defining a Kubernetes cluster.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: multi-cluster-app
spec:
generators:
- git:
repoURL: https://github.com/your-org/your-repo.git
revision: HEAD
files:
- "clusters/*.yaml" # This will find your cluster definition files
template:
metadata:
name: 'my-app-{{.path.basename}}' # e.g., my-app-dev-cluster
spec:
project: default
source:
repoURL: https://github.com/your-org/your-repo.git
path: apps/base # Assuming your app manifests are in a common 'base' path
targetRevision: HEAD
destination:
server: '{{index .path.content "server"}}' # Extracts the server URL from the cluster YAML
namespace: my-app # Or dynamically based on cluster config
In this scenario:
-
The
gitgenerator finds all.yamlfiles in theclustersdirectory. -
For each cluster file found (e.g.,
dev-cluster.yaml), it parses the file’s content. -
The
templatethen uses{{.path.basename}}to name the application (e.g.,my-app-dev-cluster). -
Crucially,
{{index .path.content "server"}}dynamically pulls the Kubernetes API server URL directly from the content of the cluster YAML file, effectively telling Argo CD which cluster to deploy to.
This declarative approach means you define your desired state in Git, and ApplicationSet and Argo CD ensure that state is realized across your entire infrastructure. You can manage hundreds or thousands of applications across numerous clusters with minimal manual intervention, simply by updating your Git repositories.
A common pattern is to use a list generator in conjunction with a git generator. This allows you to define specific parameters for each application independently of your Git file structure. For example, you might have a list generator that defines different namespaces and cluster destinations, and then a git generator that points to the common application manifests. This gives you fine-grained control over each deployment.
The template section is where the magic happens. It’s a standard Argo CD Application manifest, but with Go templating that allows you to inject values dynamically from the generators. You can access file paths, directory names, file contents, cluster details, and more, all to construct a unique Application resource for each iteration.
One subtle but powerful aspect is how ApplicationSet handles secret management and credentials. When generating applications that target different clusters, the destination block in the template can reference secrets or service accounts that are specific to each target cluster. This is typically configured within the destination block of the Argo CD Application itself, and ApplicationSet simply helps to populate these fields dynamically based on your generator inputs.
The next concept you’ll likely encounter is managing complex application configurations across many environments, which often involves using Helm charts or Kustomize overlays in conjunction with ApplicationSet generators.