Ever wish you could pass some label to an ArgoCD application and have every child resource pick up that label? This is probably of most interest to cluster operators who may not directly control the contents of manifests deployed to their clusters via ArgoCD, but need a way to enforce some standard labeling scheme.
The solution? A simple ArgoCD plugin, easier to setup than you might think.
An ArgoCD plugin needs to be configured as a sidecar container of the argocd-repo-server deployment, and the container needs to have a plugin.yaml
file that describes what it should do.
apiVersion: argoproj.io/v1alpha1
kind: ConfigManagementPlugin
metadata:
# This is the name by which the plugin will be registered to ArgoCD and must be unique within the Argo instance.
name: argocd-labeler
spec:
generate:
command: [sh, c]
args:
- |
if [[ ! -f "kustomization.yaml" && ! -f "kustomization.yml" ]]; then
kustomize create --autodetect --recursive
fi
kustomize edit add label "my_app_id:$ARGOCD_ENV_MY_APP_ID"
kustomize build
This is a very simple plugin config. The full spec is explained in the docs.
Basically, we're running this plugin using an image that already contains kustomize
, and then we're making use of kustomize's commonLabels
to add a key:value pair, where the value comes from the environment.
Additional details:
- When this plugin gets invoked, the context is the repo/location which contains the application manifests (basically the
spec.source
of the Application). Think of this as the working directory where we're calling kustomize. - The
$ARGOCD_ENV_MY_APP_ID
variable is going to come from an input on the Application manifest. - After making sure
kustomize
is properly set up, we callkustomize build
to write the updated manifests to stdout. - If you don't want to include things like Service and Deployment selectors getting labeled, you can add the
--without-selector
flag to thekustomize edit add label
command.
Use this as a kustomize strategic merge patch to add the plugin sidecar container to the argocd-repo-server:
apiVersion: apps/v1
kind: Deployment
metadata:
name: argocd-repo-server
spec:
template:
spec:
containers:
- name: argocd-labeler
image: registry.k8s.io/kustomize/kustomize:v5.4.3
command:
- /var/run/argocd/argocd-cmp/server # starts a gRPC server that will receive calls to the plugin and execute the command defined in the plugin.yaml
securityContext:
runAsNonRoot: true
runAsUser: 999 # must use 999 for the UID
volumeMounts:
- mountPath: /var/run/argocd
name: var-files # this one should already be defined as a volume by a standard argocd-repo-server deployment
- mountPath: /home/argocd/cmp-server/plugins
name: plugins
- mountPath: /home/argocd/cmp-server/config/plugin.yaml # must be mounted here and must be named plugin.yaml
subPath: plugin.yaml
name: argocd-labeler-plugin
- mountPath: /tmp
name: cmp-tmp
volumes:
- configMap:
name: argocd-labeler-plugin
name: argocd-labeler-plugin
- emptyDir: {}
name: cmp-tmp
Note
This assumes you have put the plugin.yaml
in a ConfigMap named argocd-labeler-plugin
in the ArgoCD namespace, and that ConfigMap has a data key named plugin.yaml
, e.g.
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-labeler-plugin
data:
plugin.yaml: |
# contents from above
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: foo-app
namespace: argocd
spec:
destination:
namespace: default
server: https://kubernetes.default.svc
project: default
source:
repoURL: [email protected]:org/my-gitops-repo.git
path: foo
plugin:
name: argocd-labeler
env:
- name: MY_APP_ID
value: "foo-123"
In this simple application we call our argocd-labeler plugin and pass a value for an environment variable. Remember the $ARGOCD_ENV_MY_APP_ID
variable we referenced in the plugin.yaml
? This is where it comes from. ArgoCD will set the variables you define in your app's spec.source.plugin.env
in the plugin environment, prefixed with ARGOCD_ENV_
.
Now when my app syncs, all child resources will have a new label added like my_app_id:foo-123
✅.