Helm – der Package Manager für Kubernetes | Teil 1

10.02.2021 Stefan Welsch
Cloud DevOps Helm CI/CD Infrastructure-as-Code Kubernetes Hands-on

Ursprung

Helm bedeutet soviel wie Ruder oder Steuer und hat seinen Ursprung in Helm Classic. Das Projekt wurde von Deis (deislabs.io) im Jahr 2015 gestartet und an der ersten KubeCon wurde das erste Release vorgestellt.

Im Januar 2016 wurde das Projekt dann mit Kubernetes vereint und auch zu Kubernetes verschoben. In diesem Jahr wurde wegen der Zusammenführung und der damit verbundenen Code Änderungen das Release 2.0 von Helm veröffentlicht. Mit Helm 2.0 wurde Tiller eingeführt. Tiller übernimmt die Kommunikation mit dem API Server in Kubernetes. So wurde es beispielsweise einem Team ermöglicht auf einem verteilten Cluster zu arbeiten.

Im Juni 2018 wurde Helm schliesslich in der CNCF aufgenommen. Helm bekam nach und nach immer mehr Komponenten, darunter Monocular (Frontend), das Helm Chart Repo , das Chart Museum und später den Helm Hub.

Das Helm Chart Repo wurde im November 2020 archiviert. Die Charts im archivierten Repo erhalten seitdem keine Updates mehr. Die Charts wurden grösstenteils in andere Repositories verschoben und können über den Helm Hub gefunden werden.

Im November 2019 wurde Helm 3 released. Mit diesem Release wurde Tiller (Helm Server) aus Helm entfernt. Dieser wurde bis dahin gebraucht um die Kommunikation zwischen Helm und Kubernets herzustellen.

Damit nähert sich Helm an die Infrastruktur von Kubernetes an, da moderne Ressourcen wie Security, Identity und Authorization von Kubernetes genutzt werden.

Architektur

Helm wurde in Go geschrieben. Intern wird der Kubernetes Client zur Kommunikation mit Kubernetes genutzt (REST + JSON). Die Informationen werden in Kubernetes Secrets gespeichert, so dass keine eigene Datenbank gebraucht wird. Alle Konfigurationen sind in YAML geschrieben.

Helm besteht nur aus einem “executable”, welche jedoch 2 Komponenten enthält. Der Helm Client und die Helm Library.

Der Helm Client ist für die Chart Erstellung und die Verwaltung von Repositories und Releases zuständig. Ausserdem stellt dieser der Helm Library den Chart und die Config zur Verfügung, welcher installiert werden soll.

Die Helm Library nimmt diesen Chart und die Config entgegen und kombiniert diese um ein Release zu bauen und das Deployment in Kubernetes auszuführen. Die Helm Library übernimmt generell alle Kommunikation mit Kubernetes.

Funktionsweise und Vorteile

Bedingung zur Nutzung von Helm ist ein lauffähiger Kubernetes Cluster. Helm 3.0.0 nutzt zur Kommunikation den Kubernetes Client Version 1.16.2, also ist es kompatibel mit Kubernetes Version 1.16 (Weitere Informationen über Kompatibilität findet man hier.)

Will man eine Applikation in einem Kubernetes Cluster deployen, so braucht es dafür verschiedenste Ressourcen (Pods, Services, Volumes, Deployments, …). Dies kann schnell sehr komplex und unübersichtlich werden. Dadurch steigt natürlich die Fehlerrate beim Ausliefern von Applikationen stark an.

Helm packt alle diese Ressourcen und Konfigurationen in ein Paket, welches man dann komfortabel und einfach in seinem Cluster installieren kann. Helm bietet ausserdem ein Update, Delete und Rollback Funktion um Charts entsprechend zu aktualisieren, löschen oder bei einem Fehler die vorherige Version wiederherzustellen.

Will man vorhandene Charts nutzen, so kann man bereits bestehende Charts suchen, anpassen und verwenden. Natürlich kann man aber auch neue Charts erstellen und diese in einem eigenen Chart Repository hosten.

Chart, Config, Repository und Release

Ein Helm Chart ist im Prinzip ein Paket. Dieses Paket enthält alle Ressourcen, die zum Ausführen einer Applikation notwendig sind. Ein Helm Chart ist das Kubernetes-Äquivalent eines apt dpkg- oder einer yum rpm-Datei.

Die Config enthält, wie der Name bereits sagt, Konfigurationen, welche dem Chart übergeben werden. So kann man den Chart an seine Bedürfnisse anpassen.

Im Repository werden Charts gesammelt und verteilt. Es ist wie ein App Store für Kubernetes Packages.

Von einem Release spricht man, sobald ein Helm Chart in einem Kubernetes Cluster mit einer bestimmten Config läuft. Man kann in einem Cluster mehrere Charts haben, beispielsweise wenn man zwei Webserver in einem Cluster mit verschiedenen Konfigurationen laufen lassen möchte. Jeder Chart erzeugt ein neues Release mit einem eigenen Release-Name.

Zusammenfassend kann man sagen:

Helm installiert Charts in einen Kubernetes Cluster und erzeugt dabei für jeden Chart ein neues Release mit einer bestimmten Config. In einem Repository kann man nach bestimmten Charts suchen.

Installation

Die einfachste Form Helm zu installieren ist über einen Package Manager, beispielsweise Homebrew für Mac oder Apt für Debian

~ ❯ brew install helm

Nachdem Helm installiert wurde, kann man ein Helm Chart Repository hinzufügen, welches man anschliessend durchsuchen kann.

~ ❯ helm repo add stable https://charts.helm.sh/stable

Nun sind wir schon bereit unsere ersten Charts zu suchen und zu installieren. Um einen kleinen Überblick über Charts zu bekommen, kann man diese folgendermassen auflisten:

~ ❯ helm search repo stable

NAME                                 	CHART VERSION	APP VERSION            	DESCRIPTION
stable/acs-engine-autoscaler         	2.2.2        	2.1.1                  	DEPRECATED Scales worker nodes within agent pools
stable/aerospike                     	0.3.5        	v4.5.0.5               	DEPRECATED A Helm chart for Aerospike in Kubern...
stable/airflow                       	7.13.3       	1.10.12                	DEPRECATED - please use: https://github.com/air...
stable/ambassador                    	5.3.2        	0.86.1                 	DEPRECATED A Helm chart for Datawire Ambassador

Wie wir hier sehen können sind die meisten Charts “DEPRECATED”. Das liegt, wie bereits oben erwähnt, daran, dass das Helm Chart Repo im November 2020 archiviert wurde.

Unser erstes Release

Nun wollen wir uns unserem ersten Release widmen. Wir installieren einen Nginx Chart in unserem Cluster. Im Helm Hub suchen wir nach nginx. Wie wir feststellen gibt, es direkt mehrere unter denen wir uns entscheiden müssen. Ich wähle hier das aus, welches zuletzt aktualisiert wurde.

Auf der Detailseite des Charts sehen wir, welches Repo wir hinzufügen müssen, damit wir den Chart installieren können.

~ ❯ helm repo add bitnami https://charts.bitnami.com/bitnami
"bitnami" has been added to your repositories

Nun können wir den Chart installieren und erhalten die folgende Ausgabe.

~ ❯ helm install my-nginx bitnami/nginx
NAME: my-nginx
LAST DEPLOYED: Wed Feb  3 17:56:36 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
** Please be patient while the chart is being deployed **

NGINX can be accessed through the following DNS name from within your cluster:

    my-nginx.default.svc.cluster.local (port 80)

To access NGINX from outside the cluster, follow the steps below:

1. Get the NGINX URL by running these commands:

  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        Watch the status with: 'kubectl get svc --namespace default -w my-nginx'

    export SERVICE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].port}" services my-nginx)
    export SERVICE_IP=$(kubectl get svc --namespace default my-nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    echo "http://${SERVICE_IP}:${SERVICE_PORT}"

Wir können uns diese Informationen mit helm status my-nginx jederzeit wieder abrufen.

Wir können den Status mit dem folgenden Befehl anschauen:

~ ❯ kubectl get svc --namespace default -w my-nginx
NAME       TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
my-nginx   LoadBalancer   10.245.84.171   <pending>     80:31102/TCP   34s

Die Helm CLI bietet uns hier auch einen eigenen Weg, um herauszufinden was mit Helm released wurde.

~ ❯ helm ls
NAME    	NAMESPACE	REVISION	UPDATED                             	STATUS  	CHART      	APP VERSION
my-nginx	default  	1       	2021-02-03 18:10:44.229961 +0100 CET	deployed	nginx-8.5.2	1.19.6

Nachdem das Deployment abgeschlossen ist, können wir mit den angegebenen Befehlen die IP und Port herausfinden und die Applikation aufrufen.

~ ❯ export SERVICE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].port}" services my-nginx)
~ ❯ export SERVICE_IP=$(kubectl get svc --namespace default my-nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
~ ❯ echo "http://${SERVICE_IP}:${SERVICE_PORT}"
http://67.207.72.31:80
~ ❯

Wenn wir den Chart, resp. das Deployment wieder löschen wollen, können wir das einfach mit dem folgenden Befehl erledigen. Dieser löscht alle Ressourcen, die mit dem Release zusammenhängen und auch die Release-History.

helm delete my-nginx

Wenn man die Release History behalten möchte kann man --keep-history angeben.

Für den Befehl delete gibt es mehrere Aliasse (uninstall, del, un). Man kann sich mit --help zusätzliche Informationen über den Befehl ausgeben lassen.

helm delete --help

Anschliessend sind alle Ressourcen wieder vom Cluster gelöscht.

~ ❯ kubectl get svc --namespace default
NAME         TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP      10.245.0.1       <none>        443/TCP        89m

Lasset uns den Chart anpassen

Unser Beispiel hat uns gezeigt, wie man einen Chart installieren und wieder löschen kann. Nun wollen wir aber nicht immer nur vorhandenen Konfigurationen nutzen, sondern unsere eigenen. Dafür müssen wir erstmal herausfinden, welche Optionen in unserem Chart konfigurierbar sind. Dabei hilft uns der folgende Befehl.

~ ❯ helm show values bitnami/nginx
...
## NGINX Service properties
##
service:
  ## Service type
  ##
  type: LoadBalancer

  ## HTTP Port
  ##
  port: 80

  ## HTTPS Port
  ##
  httpsPort: 443
...

Wir sehen nun eine sehr lange Liste mit Optionen, welche im Chart anpassbar sind. Um diese Einstellungen nun anzupassen, können wir bei der Installation eine YAML Datei angeben, welche die Konfigurationen enthält.

Als Beispiel wollen wir den HTTP Port auf 8080 ändern. Wir erstellen also eine YAML Datei values.yamlmit dem folgenden Inhalt:

service:
  port: 8080

Danach geben wir diese Datei bei der Installation des Charts als Parameter an:

~ ❯ helm install -f values.yaml my-nginx bitnami/nginx

Wir können Konfigurationen auch mit dem set Argument überschreiben.

helm install --set name=prod myredis ./redis

Weitere Informationen dazu gibt es in der Helm Dokumentation.

Wir sehen im Service, dass jetzt nicht mehr Port 80 gemapped wird, sondern Port 8080. Nachdem das Deployment abgeschlossen ist, können wir per HTTP also über Port 8080 auf den Server zugreifen.

~ ❯ kubectl get svc --namespace default -w my-nginx
NAME       TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
my-nginx   LoadBalancer   10.245.116.90   <pending>     8080:30149/TCP   48s

Upgrade und Rollback

Helm bietet uns die Möglichkeit ein Release zu aktualisieren oder eine vorherige Version wiederherzustellen. Als Beispiel nehmen wir wieder den nginx Chart. Vom WAF Team haben wir die Anforderung bekommen, dass der nginx neu auf Port 8081 laufen muss.

Schauen wir uns erstmal den aktuellen Release an:

~ ❯ helm list
NAME    	NAMESPACE	REVISION	UPDATED                            	STATUS  	CHART      	APP VERSION
my-nginx	default  	1       	2021-02-03 18:44:58.13495 +0100 CET	deployed	nginx-8.5.2	1.19.6

Wir sehen hier Revision 1, was bedeutet, dass es erst eine Release-Version gibt. Nun wollen wir unser Upgrade ausführen und schauen was passiert.

In unserer values.yaml müssen wir erstmal den Port auf 8081 ändern.

service:
  port: 8081

Danach rufen wir den folgenden Befehl auf, um das Upgrade auszuführen.

~ ❯ helm upgrade my-nginx bitnami/nginx -f values.yaml
Release "my-nginx" has been upgraded. Happy Helming!
NAME: my-nginx
LAST DEPLOYED: Thu Feb  4 06:46:29 2021
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None
NOTES:

Wie wir sehen wurde das Release erfolgreich aktualisiert und die Version wurde hochgezählt. Der Port wurde damit erfolgreich umgestellt.

“Murphy's Law”. Kurz nachdem wir die Änderung ausgerollt haben, kommt ein Anruf vom WAF Team, dass es bei der Umstellung Probleme gab und wir unsere Änderungen wieder rückgängig machen müssen.

Glücklicherweise hilft uns hier Helm wieder und bietet eine Rollback-Funktion an, mit der wir ganz leicht auf die vorherige Version zurückgehen können.

~ ❯ helm rollback my-nginx 1
Rollback was a success! Happy Helming!

Wir haben jetzt gesehen, wo man einen bereits vorhanden Chart findet (Helm Hub) und wie man diesen auf einem Kubernetes Cluster installiert. Wir wissen, wie man eigene Konfigurationen an den Chart übergeben kann und wie man ein Upgrade und Rollback durchführt.

Next Steps:

Im nächsten TechUp wollen wir uns anschauen, wie wir einen eigenen Chart erstellen können uns diesen dann im Cluster installieren.

Viel Spass und stay tuned!

Stefan Welsch – Pionier, Stuntman, Mentor. Als Gründer von b-nova ist Stefan immer auf der Suche nach neuen und vielversprechenden Entwicklungsfeldern. Er ist durch und durch Pragmatiker und schreibt daher auch am liebsten Beiträge die sich möglichst nahe an 'real-world' Szenarien anlehnen.