Integrations

Integrations

ArgoCD Integration

Use ArgoCD with helmfile template for GitOps.

ArgoCD has support for kustomize/manifests/helm chart by itself. Why bother with Helmfile?

The reasons may vary:

  1. You do want to manage applications with ArgoCD, while letting Helmfile manage infrastructure-related components like Calico/Cilium/WeaveNet, Linkerd/Istio, and ArgoCD itself.
  • This way, any application deployed by ArgoCD has access to all the infrastructure.
  • Of course, you can use ArgoCD’s Sync Waves and Phases for ordering the infrastructure and application installations. But it may be difficult to separate the concern between the infrastructure and apps and annotate K8s resources consistently when you have different teams for managing infra and apps.
  1. You want to review the exact K8s manifests being applied on pull-request time, before ArgoCD syncs.
  • This is often better than using a kind of HelmRelease custom resources that obfuscates exactly what manifests are being applied, which makes reviewing harder.
  1. Use Helmfile as the single-pane of glass for all the K8s resources deployed to your cluster(s).
  • Helmfile can reduce repetition in K8s manifests across ArgoCD application

For 1, you run helmfile apply on CI to deploy ArgoCD and the infrastructure components.

helmfile config for this phase often reside within the same directory as your Terraform project. So connecting the two with terraform-provider-helmfile may be helpful

For 2, another app-centric CI or bot should render/commit manifests by running:

helmfile template --output-dir-template $(pwd)/gitops//{{.Release.Name}}
cd gitops
git add .
git commit -m 'some message'
git push origin $BRANCH

Note that $(pwd) is necessary when helmfile.yaml has one or more sub-helmfiles in nested directories,
because setting a relative file path in --output-dir or --output-dir-template results in each sub-helmfile render
to the directory relative to the specified path.

so that they can be deployed by Argo CD as usual.

The CI or bot can optionally submit a PR to be review by human, running:

hub pull-request -b main -l gitops -m 'some description'

Recommendations:

  • Do create ArgoCD Application custom resource per Helm/Helmfile release, each point to respective sub-directory generated by helmfile template --output-dir-template
  • If you don’t directly push it to the main Git branch and instead go through a pull-request, do lint rendered manifests on your CI, so that you can catch easy mistakes earlier/before ArgoCD finally deploys it
  • See this ArgoCD issue for why you may want this, and see this helmfile issue for how --output-dir-template works.

Azure ACR Integration

Azure offers helm repository support for Azure Container Registry as a preview feature.

To use this you must first az login and then az acr helm repo add -n <MyRegistry>. This will extract a token for the given ACR and configure helm to use it, e.g. helm repo update should work straight away.

To use helmfile with ACR, on the other hand, you must either include a username/password in the repository definition for the ACR in your helmfile.yaml or use the --skip-deps switch, e.g. helmfile template --skip-deps.

An ACR repository definition in helmfile.yaml looks like this:

repositories:
  - name: <MyRegistry>
    url: https://<MyRegistry>.azurecr.io/helm/v1/repo

OCI Registries

In order to use OCI chart registries firstly they must be marked in the repository list as OCI enabled, e.g.

repositories:
  - name: myOCIRegistry
    url: myregistry.azurecr.io
    oci: true

It is important not to include a scheme for the URL as helm requires that these are not present for OCI registries

Secondly the credentials for the OCI registry can either be specified within helmfile.yaml similar to

repositories:
  - name: myOCIRegistry
    url: myregistry.azurecr.io
    oci: true
    username: spongebob
    password: squarepants

or for CI scenarios these can be sourced from the environment with the format <registryName>_USERNAME and <registryName_PASSWORD>, e.g.

export MYOCIREGISTRY_USERNAME=spongebob
export MYOCIREGISTRY_PASSWORD=squarepants

If <registryName> contains hyphens, the environment variable to be read is the hyphen replaced by an underscore., e.g.

repositories:
  - name: my-oci-registry
    url: myregistry.azurecr.io
    oci: true
export MY_OCI_REGISTRY_USERNAME=spongebob
export MY_OCI_REGISTRY_PASSWORD=squarepants

Troubleshooting OCI registry authentication

If Helmfile fails with an error such as 401 Unauthorized, 403 Forbidden, insufficient_scope, failed to authorize, or pull access denied while reading an OCI chart, verify the same registry access with Helm first. Helmfile delegates the registry login and chart pull to Helm, so a failing helm pull usually indicates a credential, token, or registry-permission problem rather than a Helmfile templating problem.

helm registry login myregistry.azurecr.io --username "$MYOCIREGISTRY_USERNAME" --password-stdin <<<"$MYOCIREGISTRY_PASSWORD"
helm pull oci://myregistry.azurecr.io/helm-repo/my-chart --version 1.2.3 --destination /tmp/helmfile-oci-check

Recommended checks:

  • Set oci: true on the matching entry in repositories; otherwise Helmfile treats the entry like a classic chart repository instead of an OCI registry.
  • Keep the repository url as the registry host only, without https:// or oci://; use the oci:// scheme only in chart references such as oci://myregistry.azurecr.io/helm-repo/my-chart.
  • Make sure the repository name matches the environment variable prefix exactly after uppercasing and replacing hyphens with underscores, for example my-oci-registry reads MY_OCI_REGISTRY_USERNAME and MY_OCI_REGISTRY_PASSWORD.
  • In CI, store registry credentials as secret variables and export them before running Helmfile; masked secrets that are unavailable to pull-request builds or protected branches will look like empty usernames or passwords.
  • Prefer short-lived tokens generated immediately before helmfile sync or helmfile template when using cloud registries such as ACR, ECR, GAR, or GHCR, because registry tokens can expire between pipeline stages.
  • Confirm that the token has permission to pull the chart repository/path and not only the container image repository/path; some registries scope Helm charts separately from images.
  • If credentials were refreshed, remove stale local auth with helm registry logout <registry-host> and log in again, or point Helm at a clean registry config with HELM_REGISTRY_CONFIG.
  • When debugging, run Helmfile with --debug and retry the equivalent helm registry login and helm pull command shown above on the same runner or workstation.
  • For HTTP-only local registries, also check whether your Helm version requires Helmfile’s --oci-plain-http option.
  • Avoid committing usernames, passwords, or access tokens in helmfile.yaml; use environment variables, CI secrets, or another secret manager instead.

OCI Chart Caching

OCI charts are automatically cached in the shared cache directory (~/.cache/helmfile by default, or the directory specified by HELMFILE_CACHE_HOME). This improves performance by avoiding redundant downloads.

Multi-Process Safety: When running multiple helmfile processes in parallel (e.g., as an ArgoCD plugin), charts in the shared cache are not deleted or refreshed to prevent race conditions where one process might delete a chart that another is using. To force a cache refresh, run helmfile cache cleanup first.

See the cache section for more details on cache management.

Attribution

We use:

  • semtag for automated semver tagging. I greatly appreciate the author(pnikosis)’s effort on creating it and their kindness to share it!