travisghansen / argo-cd-helmfile

Integration between argo-cd and helmfile
MIT License
213 stars 55 forks source link
argo-cd continuous-delivery continuous-deployment continuous-integration gitops helm helmfile kubernetes

Image Image

Intro

Support for helmfile with argo-cd.

argo-cd already supports helm in 2 distinct ways, why is this useful?

Security

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.

Installation

Sidecar

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

ConfigMap (deprecated)

    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

Usage

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 file OR a helmfile.d directory containing any number of *.yaml files. You cannot have both configurations.

There are a number of specially handled ENV variables which can be set (all optional):

Of the above ENV variables, the following do variable expansion on the value:

Meaning, you can do things like:

Any of the standard Build Environment variables can be used as well as variables declared in the application spec.

Helm Plugins

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.

Custom Init

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.

Development

# format before commit
shfmt -i 2 -ci -w src/argo-cd-helmfile.sh