Helmfile tutorial

DevOps

Upgrade & Secure Your Future with DevOps, SRE, DevSecOps, MLOps!

We spend hours scrolling social media and waste money on things we forget, but won’t spend 30 minutes a day earning certifications that can change our lives.
Master in DevOps, SRE, DevSecOps & MLOps by DevOps School!

Learn from Guru Rajesh Kumar and double your salary in just one year.


Get Started Now!

Introduction to Helmfile

Helmfile is a declarative tool for deploying and managing multiple Helm charts (Kubernetes applications) as code. It allows you to:

  • Define all releases, configurations, and environments in a single YAML file (helmfile.yaml)
  • Version-control your infrastructure and apply CI/CD best practices
  • Manage complex, multi-environment, and multi-release deployments with ease

Real-world use cases:

  • Coordinating deployment of microservices across dev, staging, and prod
  • Keeping environment-specific configurations DRY and manageable
  • Automating upgrades, rollbacks, and dependency management for multiple charts

Installation and Setup

Prerequisites

  • Kubernetes cluster (local or cloud)
  • kubectl installed and configured
  • Helm (v3+) installed (helm version)
  • Helmfile installed

Installing Helmfile

macOS:

textbrew install helmfile

Linux:

textwget https://github.com/helmfile/helmfile/releases/download/v<version>/helmfile_linux_amd64
chmod +x helmfile_linux_amd64
mv helmfile_linux_amd64 /usr/local/bin/helmfile

Windows (Scoop):

textscoop install helmfile

Docker:

textdocker run --rm -it -v $PWD:/wd -w /wd ghcr.io/helmfile/helmfile:v0.156.0 helmfile sync

Helm must be installed and available in your PATH, as Helmfile delegates to Helm for actual deployments.

helmfile.yaml Structure and Syntax

A typical helmfile.yaml consists of:

  • repositories: List of Helm chart repositories
  • environments: Environment-specific settings and values
  • releases: List of Helm releases, each with chart, version, namespace, and values

Example:

textrepositories:
  - name: bitnami
    url: https://charts.bitnami.com/bitnami

environments:
  dev:
    values:
      - values-dev.yaml
  prod:
    values:
      - values-prod.yaml

releases:
  - name: my-app
    chart: bitnami/nginx
    namespace: web
    version: 13.2.18
    values:
      - common-values.yaml
      - "values-{{ .Environment.Name }}.yaml"
  • Templating: Use {{ .Environment.Name }} to inject environment names dynamically.

Managing Single and Multiple Helm Releases

Single release:

textreleases:
  - name: redis
    chart: bitnami/redis
    namespace: cache
    values:
      - redis-values.yaml

Multiple releases:

textreleases:
  - name: frontend
    chart: bitnami/nginx
    namespace: web
    values: [frontend-values.yaml]
  - name: backend
    chart: bitnami/postgresql
    namespace: db
    values: [backend-values.yaml]

Each release can have its own chart, version, namespace, and values.

Organizing and Templating Values Files

  • Common values: Place shared config in common-values.yaml
  • Environment-specific values: Use values-dev.yaml, values-prod.yaml, etc.

Best practice: List files in order of precedence (last overrides previous):

textvalues:
  - common-values.yaml
  - "values-{{ .Environment.Name }}.yaml"

This allows you to override only what’s necessary for each environment.

Using Environment Variables and Secret Management

  • Environment variables: Use Go templating in values files: textimage: tag: {{ requiredEnv "IMAGE_TAG" }} Run with: textIMAGE_TAG=1.2.3 helmfile apply
  • Secrets: Use the plugin for encrypted secrets, or fetch secrets from remote stores (Vault, AWS SSM) using fetchSecretValue: textvalues: - secrets.yaml # secrets.yaml db_password: ref+vault://db/#password In your release: textvalues: - db_password: {{ .Values.db_password | fetchSecretValue | quote }} This will fetch and inject the secret at runtime.

Handling Dependencies and Release Ordering

  • Use the needs field to specify dependencies between releases: textreleases: - name: db chart: bitnami/postgresql namespace: db - name: app chart: mycompany/app namespace: web needs: - db
  • Helmfile builds a DAG (Directed Acyclic Graph) and deploys releases in the correct order, executing releases in each group in parallel.

Grouping Releases and Using Selectors

  • Labels: Add labels to releases for grouping and filtering: textreleases: - name: app labels: tier: frontend - name: db labels: tier: backend
  • Selectors: Deploy only specific groups: texthelmfile -l tier=frontend apply This applies only releases with the tier=frontend label.

Advanced Templating Features

  • Go templating: All YAML files (including values) support Go templates and Sprig functions.
  • Dynamic values: Use functions like readFile, requiredEnv, and more.
  • .gotmpl files: Use .gotmpl extension for values files to enable templating. text# values-dev.yaml.gotmpl replicaCount: {{ if eq .Environment.Name "prod" }}3{{ else }}1{{ end }}

Best Practices for Multi-Environment Management

  • Use the environments block to define environment-specific values and settings inside helmfile.yaml: textenvironments: dev: values: [values-dev.yaml] prod: values: [values-prod.yaml]
  • Directory structure: text. ├── helmfile.yaml ├── values-dev.yaml ├── values-prod.yaml └── common-values.yaml
  • Override only what’s different in each environment’s values file.

Integrating Helmfile into GitOps and CI/CD Pipelines

  • Store all Helmfile configs and values in Git
  • Typical CI/CD pipeline: texthelmfile -e dev apply
  • With ArgoCD: Use Helmfile to bootstrap ArgoCD or manage its configuration.
  • In GitHub Actions: text- uses: azure/setup-helm@v3 - run: helmfile -e staging apply

Troubleshooting, Debugging, and Optimization

  • Dry-run and diff: texthelmfile -e dev diff helmfile -e dev apply --dry-run
  • Debug logs: textHELMFILE_LOG_LEVEL=debug helmfile apply
  • Helm troubleshooting: Use helm lint, helm template --debug, and helm install --dry-run --debug for underlying chart issues.
  • Optimize by modularizing your helmfiles (split into helmfile.d/*.yaml), and use labels/selectors for targeted deployments.

Real-World Examples, Sample Configs, and Pro Tips

Multi-environment setup:

textenvironments:
  dev:
    values: [values/dev.yaml]
  prod:
    values: [values/prod.yaml]

releases:
  - name: my-app
    chart: stable/my-app
    namespace: default
    values:
      - common.yaml
      - "values/{{ .Environment.Name }}.yaml"

Directory structure for modular Helmfiles:

text.
├── helmfile.yaml
├── helmfile.d/
│   ├── frontend.yaml
│   ├── backend.yaml
├── values/
│   ├── dev/
│   ├── prod/

Pro tips:

  • Use needs for complex dependency ordering
  • Use .gotmpl for dynamic templating
  • Use selectors and labels for targeted deployments
  • Use helmfile sync for idempotent, always-up-to-date deployments

Comparison: Helmfile vs. Helmsman vs. Helmwave

FeatureHelmfileHelmsmanHelmwave
SyntaxYAML + sprigTOML/YAMLYAML + sprig/gomplate
Parallel DeploymentsYesLimitedYes
Dependency ManagementneedsPrioritydepends_on
Advanced TemplatingSprigNoneSprig, Gomplate
Secret Managementhelm-secrets, custom?Via gomplate
Live Resource TrackingNoNoYes (kubedog)
Planfile SupportNoNoYes
Multi-environment SupportStrongBasicStrong

Summary:

  • Helmfile is the most widely adopted, flexible, and integrates deeply with Helm and CI/CD workflows.
  • Helmsman is simpler, focused on basic declarative deployments.
  • Helmwave is newer, offers advanced templating and live tracking, and bundles Helm internally for easier portability.

Helmfile empowers you to manage complex Kubernetes deployments declaratively, reproducibly, and at scale. With its modularity, templating, and environment management, it’s a cornerstone for modern GitOps and CI/CD workflows.

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x