|  | 
| 1 | 1 | # argocd-helmfile-plugin | 
| 2 |  | -argocd-helmfile-plugin | 
|  | 2 | + | 
|  | 3 | + | 
|  | 4 | + | 
|  | 5 | + | 
|  | 6 | +# Intro | 
|  | 7 | + | 
|  | 8 | +Support for `helmfile` with `argo-cd`. | 
|  | 9 | + | 
|  | 10 | +`argo-cd` already supports `helm` in 2 distinct ways, why is this useful? | 
|  | 11 | + | 
|  | 12 | +- It helps decouple configuration from chart development | 
|  | 13 | +- It's similar to using a repo type of `helm` but you can still manage | 
|  | 14 | +  configuration with git. | 
|  | 15 | +- Because I like the power afforded using `helmfile`'s features such as | 
|  | 16 | +  `environments`, `selectors`, templates, and being able to use `ENV` vars as | 
|  | 17 | +  conditionals **AND** values. | 
|  | 18 | +- https://github.com/helmfile/helmfile/blob/main/docs/writing-helmfile.md | 
|  | 19 | +- https://github.com/helmfile/helmfile/blob/main/docs/shared-configuration-across-teams.md | 
|  | 20 | + | 
|  | 21 | +# Security | 
|  | 22 | + | 
|  | 23 | +Please make note that `helmfile` itself allows execution of arbitrary scripts. | 
|  | 24 | +Due to this feature, execution of arbitrary scripts are allowed by this plugin, | 
|  | 25 | +both explicitly (see `HELMFILE_INIT_SCRIPT_FILE` env below) and implicity. | 
|  | 26 | + | 
|  | 27 | +Consider these implications for your environment and act appropriately. | 
|  | 28 | + | 
|  | 29 | +- https://github.com/roboll/helmfile#templating (`exec` description) | 
|  | 30 | +- https://github.com/helmfile/helmfile/pull/1 (can disable `exec` using env vars) | 
|  | 31 | +- the execution pod/context is the `argocd-repo-server` | 
|  | 32 | + | 
|  | 33 | +# Installation | 
|  | 34 | + | 
|  | 35 | +- https://argo-cd.readthedocs.io/en/stable/operator-manual/config-management-plugins/ | 
|  | 36 | + | 
|  | 37 | +## Sidecar | 
|  | 38 | + | 
|  | 39 | +This shows optional use of sops/age integration. You may add/remove others as necessary. | 
|  | 40 | + | 
|  | 41 | +```yaml | 
|  | 42 | +repoServer: | 
|  | 43 | +  volumes: | 
|  | 44 | +  ... | 
|  | 45 | +  - name: age-secret-keys | 
|  | 46 | +    secret: | 
|  | 47 | +      secretName: argocd-age-secret-keys | 
|  | 48 | +  - emptyDir: {} | 
|  | 49 | +    name: helmfile-cmp-tmp | 
|  | 50 | + | 
|  | 51 | +  extraContainers: | 
|  | 52 | +  - name: helmfile-plugin | 
|  | 53 | +    image: code-tool/argocd-helmfile-plugin:latest | 
|  | 54 | +    command: [/var/run/argocd/argocd-cmp-server] | 
|  | 55 | +    env: | 
|  | 56 | +    ... | 
|  | 57 | +    - name: SOPS_AGE_KEY_FILE | 
|  | 58 | +      value: /sops/age/keys.txt | 
|  | 59 | +    securityContext: | 
|  | 60 | +      runAsNonRoot: true | 
|  | 61 | +      runAsUser: 999 | 
|  | 62 | +    volumeMounts: | 
|  | 63 | +      ... | 
|  | 64 | +      - mountPath: /sops/age | 
|  | 65 | +        name: age-secret-keys | 
|  | 66 | +      - mountPath: /var/run/argocd | 
|  | 67 | +        name: var-files | 
|  | 68 | +      - mountPath: /home/argocd/cmp-server/plugins | 
|  | 69 | +        name: plugins | 
|  | 70 | +      - mountPath: /tmp | 
|  | 71 | +        name: helmfile-cmp-tmp | 
|  | 72 | +``` | 
|  | 73 | +
 | 
|  | 74 | +# Usage | 
|  | 75 | +
 | 
|  | 76 | +Configure your `argo-cd` app to use a repo/directory which holds a valid | 
|  | 77 | +`helmfile` configuration. This can be a directory which contains a | 
|  | 78 | +`helmfile.yaml` **OR** `helmfile.yaml.gotmpl` file **OR** a `helmfile.d` directory containing any number of | 
|  | 79 | +`*.yaml` or `*.yaml.gotmpl` files. You cannot have both configurations. | 
|  | 80 | + | 
|  | 81 | +There are a number of specially handled `ENV` variables which can be set (all | 
|  | 82 | +optional): | 
|  | 83 | + | 
|  | 84 | +- `HELM_BINARY` - custom path to `helm` binary | 
|  | 85 | +- `HELM_TEMPLATE_OPTIONS` - pass-through options for the templating operation | 
|  | 86 | +  `helm template --help` | 
|  | 87 | +- `HELMFILE_BINARY` - custom path to `helmfile` binary | 
|  | 88 | +- `HELMFILE_USE_CONTEXT_NAMESPACE` - do not set helmfile namespace to `ARGOCD_APP_NAMESPACE`, | 
|  | 89 | +  for use with multi-namespace apps | 
|  | 90 | +- `HELMFILE_GLOBAL_OPTIONS` - pass-through options for all `helmfile` | 
|  | 91 | +  operations `helmfile --help` | 
|  | 92 | +- `HELMFILE_TEMPLATE_OPTIONS` - pass-through options for the templating | 
|  | 93 | +  operation `helmfile template --help` | 
|  | 94 | +- `HELMFILE_INIT_SCRIPT_FILE` - path to script to execute during init phase | 
|  | 95 | +- `HELMFILE_HELMFILE` - a complete `helmfile.yaml` or `helmfile.yaml.gotmpl` content | 
|  | 96 | +- `HELMFILE_HELMFILE_STRATEGY` - one of `REPLACE` or `INCLUDE` | 
|  | 97 | +  - `REPLACE` - the default option, only the content of `HELMFILE_HELMFILE` is | 
|  | 98 | +    rendered, if any valid files exist in the repo they are ignored | 
|  | 99 | +  - `INCLUDE` - any valid files in the repo **AND** the content of | 
|  | 100 | +    `HELMFILE_HELMFILE` are rendered, precedence is given to | 
|  | 101 | +    `HELMFILE_HELMFILE` should the same release name be declared in multiple | 
|  | 102 | +    files | 
|  | 103 | +- `HELMFILE_CACHE_CLEANUP` - run helmfile cache cleanup on init | 
|  | 104 | + | 
|  | 105 | +Of the above `ENV` variables, the following do variable expansion on the value: | 
|  | 106 | + | 
|  | 107 | +- `HELMFILE_GLOBAL_OPTIONS` | 
|  | 108 | +- `HELMFILE_TEMPLATE_OPTIONS` | 
|  | 109 | +- `HELM_TEMPLATE_OPTIONS` | 
|  | 110 | +- `HELMFILE_INIT_SCRIPT_FILE` | 
|  | 111 | +- `HELM_DATA_HOME` | 
|  | 112 | + | 
|  | 113 | +Meaning, you can do things like: | 
|  | 114 | + | 
|  | 115 | +- `HELMFILE_GLOBAL_OPTIONS="--environment ${ARGOCD_APP_NAME} --selector cluster=${CLUSTER_ID}` | 
|  | 116 | + | 
|  | 117 | +Any of the standard `Build Environment` variables can be used as well as | 
|  | 118 | +variables declared in the application spec. | 
|  | 119 | + | 
|  | 120 | +- https://argoproj.github.io/argo-cd/user-guide/config-management-plugins/#environment | 
|  | 121 | +- https://argoproj.github.io/argo-cd/user-guide/build-environment/ | 
|  | 122 | + | 
|  | 123 | +## Helm Plugins | 
|  | 124 | + | 
|  | 125 | +To use the various helm plugins the recommended approach is the install the | 
|  | 126 | +plugins using the/an `initContainers` (explicitly set the `HELM_DATA_HOME` env | 
|  | 127 | +var during the `helm plugin add` command) and simply set the `HELM_DATA_HOME` | 
|  | 128 | +environment variable in your application spec (or globally in the pod). This | 
|  | 129 | +prevents the plugin(s) from being downloaded over and over each run. | 
|  | 130 | + | 
|  | 131 | +```yaml | 
|  | 132 | +# repo server deployment | 
|  | 133 | +  volumes: | 
|  | 134 | +  ... | 
|  | 135 | +  - name: helm-data-home | 
|  | 136 | +    emptyDir: {} | 
|  | 137 | +
 | 
|  | 138 | +# repo-server container | 
|  | 139 | +  volumeMounts: | 
|  | 140 | +  ... | 
|  | 141 | +  - mountPath: /home/argocd/.local/share/helm | 
|  | 142 | +    name: helm-data-home | 
|  | 143 | +
 | 
|  | 144 | +# init container | 
|  | 145 | +  volumeMounts: | 
|  | 146 | +  ... | 
|  | 147 | +  - mountPath: /helm/data | 
|  | 148 | +    name: helm-data-home | 
|  | 149 | +
 | 
|  | 150 | +    [[ ! -d "${HELM_DATA_HOME}/plugins/helm-secrets" ]] && /custom-tools/helm-v3 plugin install https://github.com/jkroepke/helm-secrets --version ${HELM_SECRETS_VERSION} | 
|  | 151 | +    chown -R 999:999 "${HELM_DATA_HOME}" | 
|  | 152 | +
 | 
|  | 153 | +# lastly, in your app definition | 
|  | 154 | +... | 
|  | 155 | +plugin: | 
|  | 156 | +  env: | 
|  | 157 | +  - name: HELM_DATA_HOME | 
|  | 158 | +    value: /home/argocd/.local/share/helm | 
|  | 159 | +``` | 
|  | 160 | + | 
|  | 161 | +If the above is not possible/desired, the recommended approach would be to use | 
|  | 162 | +`HELMFILE_INIT_SCRIPT_FILE` to execute an arbitrary script during the `init` | 
|  | 163 | +phase. Within the script it's desireable to run `helm plugin list` and only | 
|  | 164 | +install the plugin only if it's not already installed. | 
|  | 165 | + | 
|  | 166 | +## Custom Init | 
|  | 167 | + | 
|  | 168 | +You can use the `HELMFILE_INIT_SCRIPT_FILE` feature to do any kind of _init_ | 
|  | 169 | +logic required including installing helm plugins, downloading external files, | 
|  | 170 | +etc. The value can be a relative or absolute path and the file itself can be | 
|  | 171 | +injected using an `initContainers` or stored in the application git repository. | 
|  | 172 | + | 
|  | 173 | +## Development | 
|  | 174 | +```declarative | 
|  | 175 | +# Create fork. | 
|  | 176 | +# Add the original repository as a new remote called "upstream" (only once, if not done before) | 
|  | 177 | +git remote add upstream https://github.com/code-tool/argocd-helmfile-plugin.git | 
|  | 178 | +
 | 
|  | 179 | +# List all remotes to verify that "upstream" exists | 
|  | 180 | +git remote -v | 
|  | 181 | +
 | 
|  | 182 | +# 1. Fetch the latest changes from the original repository | 
|  | 183 | +git fetch upstream | 
|  | 184 | +
 | 
|  | 185 | +# 2. Switch to your main branch (your fork’s main branch, usually `master` or `main`) | 
|  | 186 | +git checkout main | 
|  | 187 | + | 
|  | 188 | +# 3. Merge the latest changes from the original repository into your `main` | 
|  | 189 | +git merge upstream/main | 
|  | 190 | + | 
|  | 191 | +# 4. Push the updated `main` branch to your fork on GitHub | 
|  | 192 | +git push origin main | 
|  | 193 | + | 
|  | 194 | +# 5. Create a new feature branch from the updated `main` for your next changes | 
|  | 195 | +git checkout -b new-feature-branch | 
|  | 196 | + | 
|  | 197 | +# (Now you can edit files, commit changes, and push this branch, then open a new pull request) | 
|  | 198 | +``` | 
0 commit comments