How to use separate environment configuration files ArgoCD
Posted in gitops on February 13, 2025 by Adrian Wyssmann ‐ 3 min read
Problem
Our current argo setup is as follows:
platform-tooling
├argocd
| └applications
│ ├application_name1.yaml
│ └application_name2.yaml
├application_name1
│ ├env1
│ │ └values.yaml
│ ├dev
│ │ └values.yaml
...
application_nameX
is usually an applicatioSet which ensures the application is deployed to all clusters. Currently this file contains a repetitive configuration:
generators:
- list:
elements:
- cluster: cluster-a
clusterid: c-abcde
project: p-abcde
env: env1
notifyChannel: channel-a
targetRevision: x.x.x.x
- cluster: cluster-b
clusterid: c-bcdef
project: p-bcdef
env: env2
notifyChannel: channel-b
targetRevision: x.x.x.x
...
This list grows the more cluster one has. It also does not follow the DRY-principle. So, following one of my last posts I started to use environment configurations files. So we have the common config in a folder argocd/cluster-config
which contains a <environment>.yaml
containing standard config. For example env1.yaml
cluster: cluster-a
clusterid: c-abcde
project: p-abcde
env: env1
notifyChannel: channel-a
In addition, as we have for each application a folder per environment, we also add a config.yaml
into each folder:
platform-tooling
├argocd
| └applications
│ │ ├application_name1.yaml
│ │ └application_name2.yaml
| └cluster-config
│ ├env1.yaml
│ └env2.yaml
├application_name1
│ ├env1
│ │ ├config.yaml
│ │ └values.yaml
│ ├dev
│ │ ├configyaml
│ │ └values.yaml
...
The config.yaml
itself contains the application specific configuration e.g. chart version or branch for the helm values:
chartVersion: 1.2.0
branch: HEAD
env: env1
Important is, that they share a common key, in our case env
- we use this for []mergeKeys
](https://argo-cd.readthedocs.io/en/latest/operator-manual/applicationset/Generators-Merge/). Now we can use git generators to build a config for each environment
- merge:
mergeKeys:
- env
generators: # The Merge generator combines parameters produced by the base (first) generator with matching parameter sets produced by subsequent generators
- git:
repoURL: https://scm.intra/k8s/tooling.git
revision: HEAD
files:
- path: "application_name1/*/config.yaml"
- git:
repoURL: https://scm.intra/tooling.git
revision: HEAD
files:
- path: "argocd/cluster-config/*.yaml"
For each application_name1/<env>/config.yaml
a config is created containgt the combination of config.yaml
and env1.yaml
- it is important to keep that order, so only when there is a application_name1/<env>
it will create a config - as argocd/cluster-config/*
will always contain all environments. So with that structure you can steer in which environment your application is deployed.
So in addition, you will use then the config parameters in the applicationSet as follows using branch
, chartVersion
and cluster
:
spec:
destination:
namespace: application_name1
name: "{{.cluster}}"
project: tooling
sources:
- repoURL: https://scm.intra/tooling.git
targetRevision: "{{.branch}}"
path: application_name1/{{.env}}
- repoURL: https://scm.intra/tooling.git
targetRevision: "{{.branch}}"
ref: values
- repoURL: https://helm.intra/virtual-helm
targetRevision: "{{.chartVersion}}"
chart: application_name1
helm:
releaseName: application_name1
valueFiles:
- $values/application_name1/{{.env}}/values.yaml
- $values/application_name1/values.yaml
Advantages
- We do not repeat config values
- It makes the ApplicationSet more readable
- ApplicationSet is defined once and does not have to be touched anymore
- Any changes incl. update of chart version happens in the same folder as the value files live