Aug 4, 2020

Managing your Helm deployments with Helmfile

As we’ve been using Kubernetes to build software delivery platforms for our clients, we’ve found Helm to be a reasonable solution to templating and managing deployments to Kubernetes. 

Although templating alternatives such as Kustomize have been gaining popularity, Helm still offers some advantages – notably, a large collection of publicly-available charts for common applications.

As you get started with Helm, often the tutorials have you working with imperative commands, e.g.:

$ helm install my-release ./my-chart

$ helm upgrade my-release ./my-chart

Notice the difficulties we would have here in developing a CD pipeline around this. First, the command differs from the first deployment, to the second deployment. Thankfully, Helm offers an easy way around this:

$ helm upgrade --install my-release ./my-chart

The --install flag will install the release if it has not already been installed.

What to do about values, however?

$ helm upgrade my-release ./my-chart set labelValue=something

helm upgrade … set passes a value into the Helm chart. That value is then persisted and used in future upgrades, even if you don’t use “set”. That wouldn’t work very well in a CI pipeline. Again, Helm has a solution for this:

$ helm upgrade --install my-release ./my-chart --values dev.yaml

When developing a CD pipeline around Kubernetes deployments, we found that every pipeline looked pretty much the same, just different names, and different values. Rather than require each repository to duplicate pipeline logic, we were looking for a declarative (configuration-driven) solution to define desired Helm releases, versions, and values. Enter Helmfile.

Helmfile is a simple wrapper around Helm. You simple add a simple helmfile.yaml file and run helmfile sync — Helmfile will determine whether an install or upgrade is necessary, compile the values, and run Helm.

# helmfile.yaml

releases:
- name: my-release
  chart: ./my-awesome-chart
  values:
  - dev.yaml


It’s a very straightforward tool, but it scratches an itch we had! It also supports a number of other features:

1. Hemfile supports Go templating in values files and helmfile.yaml, so you can look up values at deploy time (e.g., grab a value from a Terraform output or pull from environment)

# helmfile.yaml

{{ $environment := env "ENVIRONMENT" | default "dev" }}
releases:
- name: my-release
chart: ./my-awesome-chart
values:
- {{ $environment }}.yaml

2. You can make uninstalls declarative, in a sense with “installed: false”

# helmfile.yaml

releases:
- name: my-release
  chart: ./my-awesome-chart
  installed: false
  values:
  - {{ $environment }}.yaml


2. Many Helm flags can be specified via the config file, such as “—wait”, “–history-max”, etc.

# helmfile.yaml

helmDefaults:
  wait: true
  historyMax: 3

releases:
- name: my-release
  chart: ./my-awesome-chart
  values:
  - {{ $environment }}.yaml

3. You can specify multiple releases in a single Helmfile:

# helmfile.yaml

# oh yeah, and dynamically specify repositories!
repositories:
- name: bitnami
  url: https://charts.bitnami.com/bitnami

releases:
- name: my-release
  chart: ./my-awesome-chart
  values:
  - {{ $environment }}.yaml
- name: postgres
  chart: bitnami/postgresql
  values:
  - postgres-{{ $environment }}.yaml

4. You can preview the rendered chart output with “helmfile template”.

$ ENVIRONMENT=production helmfile template
Building dependency release=my-release, chart=my-awesome-chart
Templating release=my-release, chart=my-awesome-chart
---
# Source: my-awesome-chart/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: me
  labels:
    foo: dev


There are so many more ways to use Helmfile! We’ve been using it successfully for a few years now and it has remained under active development. Need help making your Kubernetes platform production-ready? Reach out!

About the Author

David Norton profile.

David Norton

Director, Platform Engineering

Passionate about continuous delivery, cloud-native architecture, DevOps, and test-driven development.Passionate about continuous delivery, cloud-native architecture, DevOps, and test-driven development.

  • Experienced in cloud infrastructure technologies such as Terraform, Kubernetes, Docker, AWS, and GCP.
  • Background heavy in enterprise JVM technologies such as Groovy, Spring, Spock, Gradle, JPA, Jenkins.
  • Focus on platform transformation, continuous delivery, building agile teams and high-scale applications.
Leave a Reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
Using Conftest to Validate Configuration Files
Conftest is a utility within the Open Policy Agent ecosystem that helps simplify writing validation tests against configuration files. In a previous blog post, I wrote about using the Open Policy Agent utility directly to […]
SwiftGen with Image & Color Asset Catalogs
You might remember back in 2015 when iOS 9 was introduced, and we were finally given a way to manage all of our assets in one place with Asset Catalogs. A few years later, support […]
Tracking Original URL Through Authentication
If you read my other post about refreshing AWS tokens, then you probably have a use case for keeping track of the original requested resource while the user goes through authentication so you can route […]
Using Spring Beans in a Kafka Streams ExceptionHandler
There are many things to know before diving into Kafka Streams. If you haven’t already, check out these 5 things as a starting point. Bullet 2 mentions designing for exceptions. Ironically, this seems to be […]