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!