Amr Saber
Amr Saber's Blog

Amr Saber's Blog

Using helmfile to document and version installed helm charts

Using helmfile to document and version installed helm charts

Amr Saber's photo
Amr Saber
·Jun 18, 2022·

5 min read

While managing my kubernetes cluster, I needed to install several helm charts to do things like:

  • Installing ingress controller in order to connect my cluster's ingress with my cloud-provider's load balancer
  • Installing metrics-server to be able to get basic metrics about my cluster

In doing so, I found myself writing commands like

helm repo add bitnami https://charts.bitnami.com/bitnami

helm upgrade --install metrics-server bitnami/metrics-server \
  --create-namespace --namespace metrics-server \
  --set apiService.create=true \
  --set extraArgs.kubelet-insecure-tls=true \
  --set extraArgs.kubelet-preferred-address-types=InternalIP \
  --set hostNetwork=true

in the command line to install the required resources then forget about it.

I didn't like this, as it does not document what I have installed, and does not document how I installed it, and if I needed to install the same infrastructure on another cluster (say from another provider) I will need to scan through my command line history to find the commands I used to install the needed resources.

I began experimenting with creating my own helm chart for my setup, specifying all the required dependencies and so. But as I learned more about it I felt it was too much for what I wanted.

Enters helmfile

Searching about a simpler solution, I found helmfile. The whole idea is that you create a yaml file consisting of your dependencies charts, and you use helmfile to install them.

It was exactly what I wanted.

The configuration file

First, we need to write a yaml file that describes the helm charts that needs to be installed, and specify some details about the related repo, namespace, and other things.

Let's take another look at the commands I ran earlier

helm repo add bitnami https://charts.bitnami.com/bitnami

helm upgrade --install metrics-server bitnami/metrics-server \
  --create-namespace --namespace metrics-server \
  --set apiService.create=true \
  --set extraArgs.kubelet-insecure-tls=true \
  --set extraArgs.kubelet-preferred-address-types=InternalIP \
  --set hostNetwork=true

We can extract some values from those 2 commands, like repo URL (charts.bitnami.com/bitnami), chart name (bitnami/metrics-server), release name (metrics-server), installation namespace (metrics-server), and some flags (--create-namespace flag), and some values that we set using --set flag.

From the above information, and with some help from the documentation of helmfile we can create the following schema

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

releases:
  - name: metrics-server
    chart: bitnami/metrics-server
    namespace: metrics-server
    createNamespace: true
    set:
      - name: apiService.create
        value: true
      - name: extraArgs.kubelet-insecure-tls
        value: true
      - name: extraArgs.kubelet-preferred-address-types
        value: InternalIP
      - name: hostNetwork
        value: true

Now we are only missing 1 required field for the release, and that is the version of the chart. We can get the version number by running

helm repo add bitnami https://charts.bitnami.com/bitnami
helm show chart bitnami/metrics-server

I.e. we add the repo, then call helm show chart {repo}/{chart}.

As of the time of writing this article, the latest version of the metrics-server is 6.0.7, but it has a bug so I am using an older version of 5.11.3

Digging through the documentation of helmfile, we can also make use of atomic option that restores previous state in case of failed release, so that the cluster does not change if the installation failed.

On last thing that I like to do is to set the cluster context in the configuration file, I manage several clusters, and I don't want one cluster's configurations to be applied onto another one, so in the root of the configuration file I added:

helmDefaults:
  kubeContext: my-cluster-context

Now, the final configuration file looks like:

helmDefaults:
  kubeContext: my-cluster-context

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

releases:
  - name: metrics-server
    chart: bitnami/metrics-server
    version: 5.11.3
    namespace: metrics-server
    createNamespace: true
    atomic: true
    set:
      - name: apiService.create
        value: true
      - name: extraArgs.kubelet-insecure-tls
        value: true
      - name: extraArgs.kubelet-preferred-address-types
        value: InternalIP
      - name: hostNetwork
        value: true

Applying The Configurations

We could download the binaries from Github repo, then install some dependencies, then use that binary to install our configuration, but that's not my favorite method to do it.

My favorite method is by using Docker.

In their installation section they have a section for "Running as a container", so let's use that.

I created a small bash file based on the command in the documentation, and I put it in the same directory as the configuration file we made earlier. Here are the contents of the bash file...

# This script deploys the helmfile using helmfile docker image.

# Save current context
current_context=$(kubectl config current-context)

# Write config to ~/.kube/config
kubectl config view --flatten > ~/.kube/config

# Use the saved context
kubectl config use-context $current_context

docker run \
--rm \
--net=host \
-v "${HOME}/.kube:/root/.kube" \
-v "${HOME}/.config/helm:/root/.config/helm" \
-v "${PWD}:/wd" --workdir /wd \
quay.io/roboll/helmfile:helm3-v0.135.0 helmfile sync

The command kubectl config view --flatten > ~/.kube/config is used to write all my kubernetes contexts into the file ~/.kube/config as the docker image reads the contexts from that file.

The first and the third commands are to keep the state of the current context, as it tends to change when I write the contexts into the config file.

All what's left is to run the bash file. It will take a minute, then print something like the following...

Adding repo bitnami https://charts.bitnami.com/bitnami
"bitnami" has been added to your repositories

Affected releases are:
metrics-server (bitnami/metrics-server) UPDATED

Upgrading release=metrics-server, chart=bitnami/metrics-server
Listing releases matching ^metrics-server$
Release "metrics-server" has been upgraded. Happy Helming!
NAME: metrics-server
LAST DEPLOYED: Sat Jun 18 04:38:44 2022
NAMESPACE: metrics-server
STATUS: deployed
REVISION: 5
TEST SUITE: None
NOTES:
CHART NAME: metrics-server
CHART VERSION: 5.11.3
APP VERSION: 0.6.1

** Please be patient while the chart is being deployed **

The metric server has been deployed.

In a few minutes you should be able to list metrics using the following
command:

kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes"

metrics-server  metrics-server  5               2022-06-18 04:38:44.662123115 +0000 UTC deployed        metrics-server-5.11.3   0.6.1

And that's it, metrics server should now be installed in a namespace called "metrics-server" and we should be able to get some basic metrics about the cluster by running kubectl top nodes.

We can now maintain that configuration file to include any dependency that we need to install using helm. The configurations can, and should be, pushed to version control; we can also setup some simple CI/CD to auto deploy the file on any changes.

 
Share this