DEV Community

Arseny Zinchenko
Arseny Zinchenko

Posted on • Originally published at rtfm.co.ua on

Helm: Kubernetes package manager — an overview, getting started

Helm: Kubernetes package manager — an overview, getting started

The official documentation calls Helm as a “The package manager for Kubernetes”, but in fact, Helm is something bigger than just a package manager — it’s more an application controlling tool for their installation, managing, upgrading, configuration, etc.

In this post, we will take an overview of Helm in general, its Charts, templates, variables, and repositories.

The post is really more like an intro to the Help and doesn’t cover some aspects like release versioning, dependencies, etc.

In contrast to the Kubernetes itself — Helm has really good documentation.

Content

Helm architecture

Helm operates with packages to run applications in Kubernetes, and in terms of Helm they are called chart, and helm allows to:

  • create new charts
  • pack charts into archives (tgz)
  • work with shared charts using their repositories
  • install and uninstall charts in a Kubernetes cluster
  • manage charts releases in a cluster

Helm concepts

The main three concepts are:

  1. chart: information necessary to run an application in a Kubernetes cluster
  2. config: information about necessary configuration options to be used by such a chart to create an application instance and manage its releases
  3. release: работающий инстанс chart-а, связанный с определённым config-ом

Helm components

Helm can be divided into two main part — the client itself, and Helm libraries

  • Helm client: is a command-line tool (Helm is written in Go), and is responsible for chart creation, working with repositories, releases management, etc
  • Helm library: is logic part of Helm responsible for work with Kubernetes API to manage charts, their release, installation to a cluster, etc

Helm Charts

So, chart — is a collection of files, describing some Kubernetes resources which can be used to create a single-pod application — or a whole composite web-service, including a web-server, a frontend ap and backend applications, caching services, etc.

Files structure

Charts are organized as a directories and files tree, where the top-directory name is a chart-name.

For example:

$ tree example-chart/
example-chart/
| — Chart.yaml
| — charts
| — templates
| | — NOTES.txt
| | — \_helpers.tpl
| | — deployment.yaml
| | — hpa.yaml
| | — ingress.yaml
| | — service.yaml
| | — serviceaccount.yaml
| ` — tests
| ` — test-connection.yaml
` — values.yaml

Here:

  • example-chart: top-catalog, a chart name
  • Chart.yaml: a chart's metadata describing the chart's purpose, its versions, dependencies, etc
  • charts: a chart can contain multiply child-charts or subcharts - they'll be stored here
  • templates: contains template files to be applied for a Kubernetes cluster using Go templating
  • NOTES.txt - help-text to be displayed for users
  • deployment.yaml - an example Kubernetes Deployment manifest
  • service.yaml - an example Kubernetes Service manifest
  • values.yaml - contains default values for templates

Well, enough for theory — let’s go to practice!

Preparing the environment

In this will use Minikube, kubectl, and Helm v3:

  • minikube v1.9
  • Kubernetes v1.18
  • kubectl v1.18.2
  • helm-3.2.0

Minikube — a Kubernetes cluster

Install theminikube:

$ sudo pacman -S minikube

Create a cluster:

$ minikube start
😄 minikube v1.9.2 on Arch rolling
…
🌟 Enabling addons: default-storageclass, storage-provisioner
🏄 Done! kubectl is now configured to use “minikube”

Check:

$ kubectl cluster-info
Kubernetes master is running at [https://192.168.99.100:8443](https://192.168.99.100:8443)
KubeDNS is running at [https://192.168.99.100:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy](https://192.168.99.100:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy)

Its nodes:

$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready master 4m16s v1.18.0

Installing Helm

Arch Linux — from a repository:

$ sudo pacman -S helm

macOS — Homebrew:

$ brew install helm

Debian, etc — with Snap:

$ sudo apt install snapd
$ sudo snap install helm — classic

And really good HELP with helm help:

Creating a Helm Chart

Now, let’s create own chart with our template and try to deploy it into the Kubernetes cluster.

Create a new chart:

$ helm create example-chart
Creating example-chart

We already saw its content:

$ tree example-chart/
example-chart/
| — Chart.yaml
| — charts
| — templates
| | — NOTES.txt
| | — \_helpers.tpl
| | — deployment.yaml
| | — hpa.yaml
| | — ingress.yaml
| | — service.yaml
| | — serviceaccount.yaml
| ` — tests
| ` — test-connection.yaml
` — values.yaml
3 directories, 10 files

Let’s inspect its Deployment file:

$ cat example-chart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include “example-chart.fullname” . }}
labels:
{{- include “example-chart.labels” . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
…

And Values:

$ cat example-chart/values.yaml
Default values for example-chart.
This is a YAML-formatted file.
Declare variables to be passed into your templates.
replicaCount: 1
…

Must be obvious enough — for the replicas: {{ .Values.replicaCount }} in the templates/deployment.yaml will be used the replicaCount: 1 value from the values.yaml.

But will not use those files — let’s create own chart.

Remove them:

$ rm -rf example-chart/templates/\*

And now add our ConfigMap.

Adding a template

Create a new file example-chart/templates/configmap.yaml, and here, for example, content for an index.html file:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-configmap
data:
  index.html: "Hello, World

chart linter

Before installing a chart it’s good to check its syntax — use the helm lint for this:

$ helm lint example-chart/
==> Linting example-chart/
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, 0 chart(s) failed

chart install

Check one more time which cluster is configured in your kubectl:

$ kubectl config current-context
minikube

To install a chart use the helm install passing a release name as a first argument, then options, and a path to the chart's files.

But again, before running real actions it will be good to make a test-run with --dry-run and add --debug to see more details:

$ helm install example-chart — dry-run — debug example-chart/
install.go:159: [debug] Original chart version: “”
install.go:176: [debug] CHART PATH: /home/setevoy/Work/RTFM/example-chart
NAME: example-chart
LAST DEPLOYED: Sun May 3 13:17:07 2020
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
{}
COMPUTED VALUES:
affinity: {}
autoscaling:
enabled: false
maxReplicas: 100
minReplicas: 1
targetCPUUtilizationPercentage: 80
fullnameOverride: “”
image:
pullPolicy: IfNotPresent
repository: nginx
tag: “”
…
 — -
Source: example-chart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configmap
data:
index.html: “Hello, World”

Okay — no errors, install it now:

$ helm install example-chart example-chart/
NAME: example-chart
LAST DEPLOYED: Sun May 3 13:20:52 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

Check its status:

$ helm get manifest example-chart
 — -
Source: example-chart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configmap
data:
index.html: “Hello, World”

And check with the kubectl:

$ kubectl describe cm nginx-configmap
Name: nginx-configmap
Namespace: default
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: example-chart
meta.helm.sh/release-namespace: default
Data
====
index.html:
 — — 
Hello, World

chart uninstall

In the same way, you can delete a chart — use helm uninstall and a release name:

$ helm uninstall example-chart
release “example-chart” uninstalled

Template variables

Okay — everything seems to be working, but we have static data in our ConfgiMap with hardcoded values.

Let’s change it and apply the template engine.

For helm, you can use a set of pre-defined variables like Release.Name, see the full list in the documentation.

Редактируем шаблон нашего ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  index.html: "Hello, World"

Next, add own variables — remove the values.yaml:

$ rm example-chart/values.yaml

And create it over but with the only one line — user: "Username":

user: "Username"

Now, you can use it in the template via .Values.user:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  index.html: "Hello, {{ .Values.user }}"

The .Values told to Helm to use the values,yaml to take the user variables' value.

Apply:

$ helm install example-chart example-chart/
NAME: example-chart
LAST DEPLOYED: Sun May 3 13:35:49 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
Check:
kubectl get cm
NAME DATA AGE
example-chart-configmap 1 31s

Content:

$ kubectl describe cm example-chart-configmap
Name: example-chart-configmap
Namespace: default
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: example-chart
meta.helm.sh/release-namespace: default
Data
====
index.html:
 — — 
Hello, Username

chart upgrade

Okay, but what if we want to change the Username string?

You can delete the whole release and redeploy it with changed value in the values.yaml, or specify it directly with the --set option:

$ helm uninstall example-chart
release “example-chart” uninstalled
helm install example-chart example-chart/ — set user=NewUser

Check:

$ kubectl describe cm example-chart-configmap
…
Data
====
index.html:
 — — 
Hello, NewUser

Another way is to use the helm upgrade with the release name and new value:

$ helm upgrade example-chart example-chart/ — set user=AnotherOneUser
Release “example-chart” has been upgraded. Happy Helming!
…

The result is:

$ kubectl describe cm example-chart-configmap
…
Data
====
index.html:
 — — 
Hello, AnotherOneUser

helm package

To be able to share our chart with colleagues we can pack it to a tgz-file.

Use the helm package, which will create a new file named chart-name-chart-verstion.tgz.

The version helm will get from the chart's metadata:

$ cat example-chart/Chart.yaml | grep version:
version: 0.1.0

Pack it:

$ helm package example-chart/
Successfully packaged chart and saved it to: /home/setevoy/Work/RTFM/example-chart-0.1.0.tgz

Check the archive’s content:

$ tar tf example-chart-0.1.0.tgz
example-chart/Chart.yaml
example-chart/values.yaml
example-chart/templates/configmap.yaml
example-chart/.helmignore

Helm repositories

To share our packed charts the Helm repositories are used.

Earlier, you could use the helm serve to create one, but it was removed in Helm v3.

Now to work with repositories use the helm repo.

By default you’ll have already added repo from Google:

$ helm repo list
NAME URL
stable [https://kubernetes-charts.storage.googleapis.com/](https://kubernetes-charts.storage.googleapis.com/)

Running local Helm repo

To create own repository — it;’s enough to execute helm package for a chart, then generate the index.yaml file in a directory used to store the chart's archive.

As a backend-storage you can use almost anything — starting with Github Pages, and to AWS S3, see The Chart Repository Guide.

Here is an example of how to run a local Helm repository.

Create a directory, move your archived chart into it:

$ mkdir helm-local-repo
$ mv example-chart-0.1.0.tgz helm-local-repo/

Initialize the repository:

$ helm repo index helm-local-repo/

Check its content:

$ tree helm-local-repo/
helm-local-repo/
| — example-chart-0.1.0.tgz
` — index.yaml

To get access to it — run a web-server, for example, a common NGINX:

$ sudo docker run -ti -v $(pwd)/helm-local-repo/:/usr/share/nginx/html -p 80:80 nginx

Check connection:

$ curl localhost/index.yaml
apiVersion: v1
entries:
example-chart:
- apiVersion: v2
appVersion: 1.16.0
created: “2020–05–03T14:04:44.896115358+03:00”
description: A Helm chart for Kubernetes
digest: afa314247a03c4c85f339bda665659f3ab13a5e8656336e14ed37ed7f31b5352
name: example-chart
type: application
urls:
- example-chart-0.1.0.tgz
version: 0.1.0
generated: “2020–05–03T14:04:44.895678349+03:00”

Add this repository to your local Helm:

$ helm repo add example-chart [http://localhost](http://localhost)
“example-chart” has been added to your repositories

Check:

$ helm repo list
NAME URL
stable [https://kubernetes-charts.storage.googleapis.com/](https://kubernetes-charts.storage.googleapis.com/)
example-chart [http://localhost](http://localhost)

Try to search for a chart:

$ helm search repo example
NAME CHART VERSION APP VERSION DESCRIPTION
example-chart/example-chart 0.1.0 1.16.0 A Helm chart for Kubernetes

Install it:

$ helm install example-chart-from-repo example-chart/example-chart
NAME: example-chart-from-repo
LAST DEPLOYED: Sun May 3 14:15:51 2020
NAMESPACE: default
STATUS: deployed

Check in the Kubernetes cluster:

$ kubectl get cm
NAME DATA AGE
example-chart-configmap 1 34m
example-chart-from-repo-configmap 1 22s

That’s all in general.

Originally published at RTFM: Linux, DevOps, and system administration.


Top comments (0)