Support for helmfile
with argo-cd
.
argo-cd
already supports helm
in 2 distinct ways, why is this useful?
- It helps decouple configuration from chart development
- It's similar to using a repo type of
helm
but you can still manage configuration with git. - Because I like the power afforded using
helmfile
's features such asenvironments
,selectors
, templates, and being able to useENV
vars as conditionals AND values. - https://github.com/helmfile/helmfile/blob/main/docs/writing-helmfile.md
- https://github.com/helmfile/helmfile/blob/main/docs/shared-configuration-across-teams.md
Please make note that helmfile
itself allows execution of arbitrary scripts.
Due to this feature, execution of arbitrary scripts are allowed by this plugin,
both explicitly (see HELMFILE_INIT_SCRIPT_FILE
env below) and implicity.
Consider these implications for your environment and act appropriately.
- https://github.com/roboll/helmfile#templating (
exec
description) - helmfile/helmfile#1 (can disable
exec
using env vars) - the execution pod/context is the
argocd-repo-server
This shows optional use of sops/age integration. You may add/remove others as necessary.
repoServer:
volumes:
...
- name: age-secret-keys
secret:
secretName: argocd-age-secret-keys
- emptyDir: {}
name: helmfile-cmp-tmp
extraContainers:
- name: helmfile-plugin
image: travisghansen/argo-cd-helmfile:latest
command: [/var/run/argocd/argocd-cmp-server]
env:
...
- name: SOPS_AGE_KEY_FILE
value: /sops/age/keys.txt
securityContext:
runAsNonRoot: true
runAsUser: 999
volumeMounts:
...
- mountPath: /sops/age
name: age-secret-keys
- mountPath: /var/run/argocd
name: var-files
- mountPath: /home/argocd/cmp-server/plugins
name: plugins
- mountPath: /tmp
name: helmfile-cmp-tmp
configManagementPlugins: |
- name: helmfile
init: # Optional command to initialize application source directory
command: ["argo-cd-helmfile.sh"]
args: ["init"]
generate: # Command to generate manifests YAML
command: ["argo-cd-helmfile.sh"]
args: ["generate"]
volumes:
- name: custom-tools
emptyDir: {}
initContainers:
- name: download-tools
image: alpine:3.8
command: [sh, -c]
args:
- wget -qO /custom-tools/argo-cd-helmfile.sh https://raw.githubusercontent.com/travisghansen/argo-cd-helmfile/master/src/argo-cd-helmfile.sh &&
chmod +x /custom-tools/argo-cd-helmfile.sh &&
wget -qO /custom-tools/helmfile https://github.com/roboll/helmfile/releases/download/v0.138.7/helmfile_linux_amd64 &&
chmod +x /custom-tools/helmfile
volumeMounts:
- mountPath: /custom-tools
name: custom-tools
volumeMounts:
- mountPath: /usr/local/bin/argo-cd-helmfile.sh
name: custom-tools
subPath: argo-cd-helmfile.sh
- mountPath: /usr/local/bin/helmfile
name: custom-tools
subPath: helmfile
Configure your argo-cd
app to use a repo/directory which holds a valid
helmfile
configuration. This can be a directory which contains a
helmfile.yaml
OR helmfile.yaml.gotmpl
file OR a helmfile.d
directory containing any number of
*.yaml
or *.yaml.gotmpl
files. You cannot have both configurations.
There are a number of specially handled ENV
variables which can be set (all
optional):
HELM_BINARY
- custom path tohelm
binaryHELM_TEMPLATE_OPTIONS
- pass-through options for the templating operationhelm template --help
HELMFILE_BINARY
- custom path tohelmfile
binaryHELMFILE_USE_CONTEXT_NAMESPACE
- do not set helmfile namespace toARGOCD_APP_NAMESPACE
, for use with multi-namespace appsHELMFILE_GLOBAL_OPTIONS
- pass-through options for allhelmfile
operationshelmfile --help
HELMFILE_TEMPLATE_OPTIONS
- pass-through options for the templating operationhelmfile template --help
HELMFILE_INIT_SCRIPT_FILE
- path to script to execute during init phaseHELMFILE_HELMFILE
- a completehelmfile.yaml
orhelmfile.yaml.gotmpl
contentHELMFILE_HELMFILE_STRATEGY
- one ofREPLACE
orINCLUDE
REPLACE
- the default option, only the content ofHELMFILE_HELMFILE
is rendered, if any valid files exist in the repo they are ignoredINCLUDE
- any valid files in the repo AND the content ofHELMFILE_HELMFILE
are rendered, precedence is given toHELMFILE_HELMFILE
should the same release name be declared in multiple files
HELMFILE_CACHE_CLEANUP
- run helmfile cache cleanup on init
Of the above ENV
variables, the following do variable expansion on the value:
HELMFILE_GLOBAL_OPTIONS
HELMFILE_TEMPLATE_OPTIONS
HELM_TEMPLATE_OPTIONS
HELMFILE_INIT_SCRIPT_FILE
HELM_DATA_HOME
Meaning, you can do things like:
HELMFILE_GLOBAL_OPTIONS="--environment ${ARGOCD_APP_NAME} --selector cluster=${CLUSTER_ID}
Any of the standard Build Environment
variables can be used as well as
variables declared in the application spec.
- https://argoproj.github.io/argo-cd/user-guide/config-management-plugins/#environment
- https://argoproj.github.io/argo-cd/user-guide/build-environment/
To use the various helm plugins the recommended approach is the install the
plugins using the/an initContainers
(explicitly set the HELM_DATA_HOME
env
var during the helm plugin add
command) and simply set the HELM_DATA_HOME
environment variable in your application spec (or globally in the pod). This
prevents the plugin(s) from being downloaded over and over each run.
# repo server deployment
volumes:
...
- name: helm-data-home
emptyDir: {}
# repo-server container
volumeMounts:
...
- mountPath: /home/argocd/.local/share/helm
name: helm-data-home
# init container
volumeMounts:
...
- mountPath: /helm/data
name: helm-data-home
[[ ! -d "${HELM_DATA_HOME}/plugins/helm-secrets" ]] && /custom-tools/helm-v3 plugin install https://github.com/jkroepke/helm-secrets --version ${HELM_SECRETS_VERSION}
chown -R 999:999 "${HELM_DATA_HOME}"
# lastly, in your app definition
...
plugin:
env:
- name: HELM_DATA_HOME
value: /home/argocd/.local/share/helm
If the above is not possible/desired, the recommended approach would be to use
HELMFILE_INIT_SCRIPT_FILE
to execute an arbitrary script during the init
phase. Within the script it's desireable to run helm plugin list
and only
install the plugin only if it's not already installed.
You can use the HELMFILE_INIT_SCRIPT_FILE
feature to do any kind of init
logic required including installing helm plugins, downloading external files,
etc. The value can be a relative or absolute path and the file itself can be
injected using an initContainers
or stored in the application git repository.
# format before commit
shfmt -i 2 -ci -w src/argo-cd-helmfile.sh