Skip to main content

Helmfile Components

Helmfile components manage Kubernetes deployments using Helmfile, a declarative spec for deploying Helm charts. They allow you to manage Helm releases with the same stack-based configuration approach used for Terraform.

Available Configuration Sections

Helmfile components support the common configuration sections:

vars
Variables passed to helmfile.
env
Environment variables during execution.
settings
Integrations and metadata.
metadata
Component behavior and inheritance.
command
Override helmfile binary.
hooks
Lifecycle event handlers.

Component Structure

A typical Helmfile component configuration:

components:
helmfile:
nginx-ingress:
metadata:
component: nginx-ingress
vars:
chart_version: "4.7.1"
replica_count: 3
service_type: LoadBalancer
env:
KUBECONFIG: "{{ env \"HOME\" }}/.kube/config"
settings:
depends_on:
- component: eks
type: terraform

Helmfile Directory Structure

Helmfile components are located in the path configured in atmos.yaml:

# atmos.yaml
components:
helmfile:
base_path: components/helmfile
kubeconfig_path: /dev/shm
helm_aws_profile_pattern: "{namespace}-{tenant}-gbl-{stage}-helm"
cluster_name_pattern: "{namespace}-{tenant}-{environment}-{stage}-eks-cluster"

Example structure:

components/helmfile/
├── nginx-ingress/
│ └── helmfile.yaml
├── cert-manager/
│ └── helmfile.yaml
└── prometheus/
└── helmfile.yaml

Helmfile Template

Each helmfile component contains a helmfile.yaml that uses variables passed from Atmos:

components/helmfile/nginx-ingress/helmfile.yaml
repositories:
- name: ingress-nginx
url: https://kubernetes.github.io/ingress-nginx

releases:
- name: nginx-ingress
namespace: ingress-nginx
createNamespace: true
chart: ingress-nginx/ingress-nginx
version: {{ .Values.chart_version | quote }}
wait: true
values:
- controller:
replicaCount: {{ .Values.replica_count }}
service:
type: {{ .Values.service_type }}
metrics:
enabled: {{ .Values.metrics_enabled | default false }}

Component-Type Defaults

Define defaults for all Helmfile components:

# Apply to all Helmfile components
helmfile:
vars:
timeout: 600
atomic: true
wait: true
env:
HELM_CACHE_HOME: /tmp/helm-cache
HELM_CONFIG_HOME: /tmp/helm-config

# Individual components
components:
helmfile:
nginx-ingress:
vars:
chart_version: "4.7.1"

Complete Example

stacks/orgs/acme/plat/prod/us-east-1.yaml
import:
- catalog/helmfile/_defaults
- orgs/acme/plat/prod/_defaults

vars:
region: us-east-1
stage: prod
eks_cluster_name: acme-prod-eks

helmfile:
vars:
timeout: 900
atomic: true
env:
AWS_PROFILE: acme-prod
KUBECONFIG: "/tmp/kubeconfig-acme-prod"

components:
helmfile:
cert-manager:
metadata:
component: cert-manager
vars:
chart_version: "v1.13.0"
install_crds: true

nginx-ingress:
metadata:
component: nginx-ingress
vars:
chart_version: "4.7.1"
replica_count: 3
service_type: LoadBalancer
metrics_enabled: true
settings:
depends_on:
- component: cert-manager

prometheus:
metadata:
component: prometheus
inherits:
- prometheus/defaults
vars:
chart_version: "45.0.0"
retention: "15d"
storage_size: "100Gi"
settings:
depends_on:
- component: nginx-ingress

Running Helmfile Commands

Atmos provides commands that wrap Helmfile operations:

# Diff changes
atmos helmfile diff nginx-ingress -s plat-ue1-prod

# Apply changes
atmos helmfile apply nginx-ingress -s plat-ue1-prod

# Sync releases
atmos helmfile sync nginx-ingress -s plat-ue1-prod

# Destroy releases
atmos helmfile destroy nginx-ingress -s plat-ue1-prod

# Run any helmfile subcommand
atmos helmfile <subcommand> <component> -s <stack>

Environment Variables

Common environment variables for Helmfile components:

KUBECONFIG
Path to kubeconfig file.
HELM_CACHE_HOME
Helm cache directory.
HELM_CONFIG_HOME
Helm configuration directory.
HELM_DATA_HOME
Helm data directory.
AWS_PROFILE
AWS profile for EKS authentication.
HELM_EXPERIMENTAL_OCI
Enable OCI registry support.

Passing Secrets Securely

Helmfile writes the vars section to a varfile on disk in plaintext (world‑readable, 0644) so Helmfile can read it. Unlike Terraform — which keeps secret‑bearing vars off disk — Helmfile performs no off‑disk partitioning. Never put secrets in a Helmfile component's vars section.

Secrets belong in env, not vars

Values in the env section are injected only into the Helmfile subprocess environment and are never written to disk. Declare secrets under secrets.vars, reference them with !secret in env, and read them inside helmfile.yaml with Helmfile's requiredEnv function.

A simple, self‑contained example:

stacks/deploy/prod.yaml
components:
helmfile:
my-app:
secrets:
vars:
DB_PASSWORD:
description: "Application database password"
store: ssm-secrets # a `secret: true` store; or use `sops: <provider>`
required: true
env:
# Resolved at runtime and injected ONLY into the Helmfile subprocess
# environment — never written to the varfile on disk.
DB_PASSWORD: !secret DB_PASSWORD
vars:
chart_version: "1.2.3" # non-secret values only

Read the secret from the environment in helmfile.yaml — not from .Values (which comes from the on‑disk varfile):

components/helmfile/my-app/helmfile.yaml
releases:
- name: my-app
chart: my-repo/my-app
version: {{ .Values.chart_version | quote }}
values:
- database:
# `requiredEnv` reads the secret from the environment and fails fast if it is unset.
# Use `env "DB_PASSWORD"` instead if the variable is optional.
password: {{ requiredEnv "DB_PASSWORD" | quote }}

Integration with Terraform

Helmfile components often depend on infrastructure created by Terraform:

components:
terraform:
eks:
vars:
cluster_name: acme-prod-eks

helmfile:
nginx-ingress:
vars:
# Reference Terraform outputs
cluster_name: "{{ .terraform_outputs.eks.cluster_name }}"
env:
KUBECONFIG: "{{ .terraform_outputs.eks.kubeconfig_path }}"
settings:
depends_on:
- component: eks
type: terraform

Values Handling

Variables from the vars section are passed to Helmfile and available in templates:

# In stack manifest
components:
helmfile:
my-app:
vars:
image_tag: "v1.2.3"
replicas: 5
resources:
requests:
cpu: "100m"
memory: "256Mi"
# In helmfile.yaml
releases:
- name: my-app
values:
- image:
tag: {{ .Values.image_tag | quote }}
replicaCount: {{ .Values.replicas }}
resources:
requests:
cpu: {{ .Values.resources.requests.cpu | quote }}
memory: {{ .Values.resources.requests.memory | quote }}

Best Practices

  1. Use Dependencies: Define depends_on to ensure Helmfile components deploy after their infrastructure dependencies.

  2. Centralize Chart Versions: Define chart versions in catalog defaults and override only when necessary.

  3. Use Atomic Deployments: Set atomic: true to automatically roll back failed deployments.

  4. Manage Kubeconfig: Use environment variables or settings to manage kubeconfig paths consistently.

  5. Version Pin Charts: Always specify explicit chart versions for reproducible deployments.

  6. Separate Concerns: Create separate Helmfile components for distinct services rather than combining everything into one.