Helm

Declarative

You can install Helm charts through the UI, or in the declarative GitOps way.
Helm is only used to inflate charts with helm template. The lifecycle of the application is handled by Argo CD instead of Helm. Here is an example:

  1. apiVersion: argoproj.io/v1alpha1
  2. kind: Application
  3. metadata:
  4. name: sealed-secrets
  5. namespace: argocd
  6. spec:
  7. project: default
  8. source:
  9. chart: sealed-secrets
  10. repoURL: https://bitnami-labs.github.io/sealed-secrets
  11. targetRevision: 1.16.1
  12. helm:
  13. releaseName: sealed-secrets
  14. destination:
  15. server: "https://kubernetes.default.svc"
  16. namespace: kubeseal

Values Files

Helm has the ability to use a different, or even multiple “values.yaml” files to derive its parameters from. Alternate or multiple values file(s), can be specified using the --values flag. The flag can be repeated to support multiple values files:

  1. argocd app set helm-guestbook --values values-production.yaml

Note

Before v2.6 of Argo CD, Values files must be in the same git repository as the Helm chart. The files can be in a different location in which case it can be accessed using a relative path relative to the root directory of the Helm chart. As of v2.6, values files can be sourced from a separate repository than the Helm chart by taking advantage of multiple sources for Applications.

In the declarative syntax:

  1. source:
  2. helm:
  3. valueFiles:
  4. - values-production.yaml

Values

Argo CD supports the equivalent of a values file directly in the Application manifest using the source.helm.valuesObject key.

  1. source:
  2. helm:
  3. valuesObject:
  4. ingress:
  5. enabled: true
  6. path: /
  7. hosts:
  8. - mydomain.example.com
  9. annotations:
  10. kubernetes.io/ingress.class: nginx
  11. kubernetes.io/tls-acme: "true"
  12. labels: {}
  13. tls:
  14. - secretName: mydomain-tls
  15. hosts:
  16. - mydomain.example.com

Alternatively, values can be passed in as a string using the source.helm.values key.

  1. source:
  2. helm:
  3. values: |
  4. ingress:
  5. enabled: true
  6. path: /
  7. hosts:
  8. - mydomain.example.com
  9. annotations:
  10. kubernetes.io/ingress.class: nginx
  11. kubernetes.io/tls-acme: "true"
  12. labels: {}
  13. tls:
  14. - secretName: mydomain-tls
  15. hosts:
  16. - mydomain.example.com

Helm Parameters

Helm has the ability to set parameter values, which override any values in a values.yaml. For example, service.type is a common parameter which is exposed in a Helm chart:

  1. helm template . --set service.type=LoadBalancer

Similarly, Argo CD can override values in the values.yaml parameters using argocd app set command, in the form of -p PARAM=VALUE. For example:

  1. argocd app set helm-guestbook -p service.type=LoadBalancer

In the declarative syntax:

  1. source:
  2. helm:
  3. parameters:
  4. - name: "service.type"
  5. value: LoadBalancer

Helm Release Name

By default, the Helm release name is equal to the Application name to which it belongs. Sometimes, especially on a centralised ArgoCD, you may want to override that name, and it is possible with the release-name flag on the cli:

  1. argocd app set helm-guestbook --release-name myRelease

or using the releaseName for yaml:

  1. source:
  2. helm:
  3. releaseName: myRelease

Important notice on overriding the release name

Please note that overriding the Helm release name might cause problems when the chart you are deploying is using the app.kubernetes.io/instance label. ArgoCD injects this label with the value of the Application name for tracking purposes. So when overriding the release name, the Application name will stop being equal to the release name. Because ArgoCD will overwrite the label with the Application name it might cause some selectors on the resources to stop working. In order to avoid this we can configure ArgoCD to use another label for tracking in the ArgoCD configmap argocd-cm.yaml - check the lines describing application.instanceLabelKey.

Helm Hooks

Helm hooks are similar to Argo CD hooks. In Helm, a hook is any normal Kubernetes resource annotated with the helm.sh/hook annotation.

Argo CD supports many (most?) Helm hooks by mapping the Helm annotations onto Argo CD’s own hook annotations:

Helm AnnotationNotes
helm.sh/hook: crd-installSupported as equivalent to argocd.argoproj.io/hook: PreSync.
helm.sh/hook: pre-deleteNot supported. In Helm stable there are 3 cases used to clean up CRDs and 3 to clean-up jobs.
helm.sh/hook: pre-rollbackNot supported. Never used in Helm stable.
helm.sh/hook: pre-installSupported as equivalent to argocd.argoproj.io/hook: PreSync.
helm.sh/hook: pre-upgradeSupported as equivalent to argocd.argoproj.io/hook: PreSync.
helm.sh/hook: post-upgradeSupported as equivalent to argocd.argoproj.io/hook: PostSync.
helm.sh/hook: post-installSupported as equivalent to argocd.argoproj.io/hook: PostSync.
helm.sh/hook: post-deleteNot supported. Never used in Helm stable.
helm.sh/hook: post-rollbackNot supported. Never used in Helm stable.
helm.sh/hook: test-successNot supported. No equivalent in Argo CD.
helm.sh/hook: test-failureNot supported. No equivalent in Argo CD.
helm.sh/hook-delete-policySupported. See also argocd.argoproj.io/hook-delete-policy).
helm.sh/hook-delete-timeoutNot supported. Never used in Helm stable
helm.sh/hook-weightSupported as equivalent to argocd.argoproj.io/sync-wave.
helm.sh/resource-policy: keepSupported as equivalent to argocd.argoproj.io/sync-options: Delete=false.

Unsupported hooks are ignored. In Argo CD, hooks are created by using kubectl apply, rather than kubectl create. This means that if the hook is named and already exists, it will not change unless you have annotated it with before-hook-creation.

Helm hooks + ArgoCD hooks

If you define some Argo CD hooks in addition to the Helm ones, the Helm hooks will be ignored.

‘install’ vs ‘upgrade’ vs ‘sync’

Argo CD cannot know if it is running a first-time “install” or an “upgrade” - every operation is a “sync’. This means that, by default, apps that have pre-install and pre-upgrade will have those hooks run at the same time.

Hook Tips

  • Make your hook idempotent.
  • Annotate crd-install with hook-weight: "-2" to make sure it runs to success before any install or upgrade hooks.
  • Annotate pre-install and post-install with hook-weight: "-1". This will make sure it runs to success before any upgrade hooks.
  • Annotate pre-upgrade and post-upgrade with hook-delete-policy: before-hook-creation to make sure it runs on every sync.

Read more about Argo hooks and Helm hooks.

Random Data

Helm templating has the ability to generate random data during chart rendering via the randAlphaNum function. Many helm charts from the charts repository make use of this feature. For example, the following is the secret for the redis helm chart:

  1. data:
  2. {{- if .Values.password }}
  3. redis-password: {{ .Values.password | b64enc | quote }}
  4. {{- else }}
  5. redis-password: {{ randAlphaNum 10 | b64enc | quote }}
  6. {{- end }}

The Argo CD application controller periodically compares Git state against the live state, running the helm template <CHART> command to generate the helm manifests. Because the random value is regenerated every time the comparison is made, any application which makes use of the randAlphaNum function will always be in an OutOfSync state. This can be mitigated by explicitly setting a value in the values.yaml or using argocd app set command to overide the value such that the value is stable between each comparison. For example:

  1. argocd app set redis -p password=abc123

Build Environment

Helm apps have access to the standard build environment via substitution as parameters.

E.g. via the CLI:

  1. argocd app create APPNAME \
  2. --helm-set-string 'app=${ARGOCD_APP_NAME}'

Or via declarative syntax:

  1. spec:
  2. source:
  3. helm:
  4. parameters:
  5. - name: app
  6. value: $ARGOCD_APP_NAME

It’s also possible to use build environment variables for the Helm values file path:

  1. spec:
  2. source:
  3. helm:
  4. valueFiles:
  5. - values.yaml
  6. - myprotocol://somepath/$ARGOCD_APP_NAME/$ARGOCD_APP_REVISION

Helm plugins

Argo CD is un-opinionated on what cloud provider you use and what kind of Helm plugins you are using, that’s why there are no plugins delivered with the ArgoCD image.

But sometimes you want to use a custom plugin. Perhaps you would like to use Google Cloud Storage or Amazon S3 storage to save the Helm charts, for example: https://github.com/hayorov/helm-gcs where you can use gs:// protocol for Helm chart repository access. There are two ways to install custom plugins; you can modify the ArgoCD container image, or you can use a Kubernetes initContainer.

Modifying the ArgoCD container image

One way to use this plugin is to prepare your own ArgoCD image where it is included.

Example Dockerfile:

  1. FROM argoproj/argocd:v1.5.7
  2. USER root
  3. RUN apt-get update && \
  4. apt-get install -y \
  5. curl && \
  6. apt-get clean && \
  7. rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
  8. USER argocd
  9. ARG GCS_PLUGIN_VERSION="0.3.5"
  10. ARG GCS_PLUGIN_REPO="https://github.com/hayorov/helm-gcs.git"
  11. RUN helm plugin install ${GCS_PLUGIN_REPO} --version ${GCS_PLUGIN_VERSION}
  12. ENV HELM_PLUGINS="/home/argocd/.local/share/helm/plugins/"

You have to remember about HELM_PLUGINS environment property - this is required for plugins to work correctly.

After that you have to use your custom image for ArgoCD installation.

Using initContainers

Another option is to install Helm plugins via Kubernetes initContainers. Some users find this pattern preferable to maintaining their own version of the ArgoCD container image.

Below is an example of how to add Helm plugins when installing ArgoCD with the official ArgoCD helm chart:

  1. repoServer:
  2. volumes:
  3. - name: gcp-credentials
  4. secret:
  5. secretName: my-gcp-credentials
  6. volumeMounts:
  7. - name: gcp-credentials
  8. mountPath: /gcp
  9. env:
  10. - name: HELM_CACHE_HOME
  11. value: /helm-working-dir
  12. - name: HELM_CONFIG_HOME
  13. value: /helm-working-dir
  14. - name: HELM_DATA_HOME
  15. value: /helm-working-dir
  16. initContainers:
  17. - name: helm-gcp-authentication
  18. image: alpine/helm:3.8.1
  19. volumeMounts:
  20. - name: helm-working-dir
  21. mountPath: /helm-working-dir
  22. - name: gcp-credentials
  23. mountPath: /gcp
  24. env:
  25. - name: HELM_CACHE_HOME
  26. value: /helm-working-dir
  27. - name: HELM_CONFIG_HOME
  28. value: /helm-working-dir
  29. - name: HELM_DATA_HOME
  30. value: /helm-working-dir
  31. command: [ "/bin/sh", "-c" ]
  32. args:
  33. - apk --no-cache add curl;
  34. helm plugin install https://github.com/hayorov/helm-gcs.git;
  35. helm repo add my-gcs-repo gs://my-private-helm-gcs-repository;
  36. chmod -R 777 $HELM_DATA_HOME;

Helm Version

Argo CD will assume that the Helm chart is v3 (even if the apiVersion field in the chart is Helm v2), unless v2 is explicitly specified within the Argo CD Application (see below).

If needed, it is possible to specifically set the Helm version to template with by setting the helm-version flag on the cli (either v2 or v3):

  1. argocd app set helm-guestbook --helm-version v3

Or using declarative syntax:

  1. spec:
  2. source:
  3. helm:
  4. version: v3

Helm --pass-credentials

Helm, starting with v3.6.1, prevents sending repository credentials to download charts that are being served from a different domain than the repository.

If needed, it is possible to opt into passing credentials for all domains by setting the helm-pass-credentials flag on the cli:

  1. argocd app set helm-guestbook --helm-pass-credentials

Or using declarative syntax:

  1. spec:
  2. source:
  3. helm:
  4. passCredentials: true

Helm --skip-crds

Helm installs custom resource definitions in the crds folder by default if they are not existing. See the CRD best practices for details.

If needed, it is possible to skip the CRD installation step with the helm-skip-crds flag on the cli:

  1. argocd app set helm-guestbook --helm-skip-crds

Or using declarative syntax:

  1. spec:
  2. source:
  3. helm:
  4. skipCrds: true