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.

  • 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
Modern Development Environment for C++: Part 2
In Part 1 of this series, I gave a quick overview of each tool in the development environment and how I came to the conclusion that the tool was a good fit. Today I’m going […]
Mock Intl and Date globals in Jest
In Javascript land, mocking the browser global objects can be a bit of a pain for tests. Searching StackOverflow gives plenty of complicated answers. Some suggesting using 3rd party mock libraries. Some that overwrite the […]
Bitbucket Parameterized Pipelines
Introduction I’d like to address how to handle lots of deployment environments withinBitBucket Pipelines. Below I’m presenting two options: Using tags to parameterize builds Using the BitBucket API to pass variables Lots of Environments There […]
AWS Cloud HSM, Docker and NGINX
There is quite a bit of easily searchable content on the security benefits of leveraging a Hardware Security Module to manage cryptographic keys, so I will leave that to the scope of another article. The […]