Helm.sh

Helm.sh

In der Welt der Containerorchestrierung ist effizientes Deployment entscheidend. Der Paket-Manager Helm selbst bezeichnet sich als:

„Der beste Weg, Anwendungen für Kubernetes zu finden, zu teilen und einzusetzen“ [1]

Die Verwendung von Helm ist eng mit der Funktionsweise des Open-Source-Systems Kubernetes (K8s) verbunden. Helm fungiert als eine Abstraktionsebene für Kubernetes und zielt darauf ab, Administratoren und Entwicklern die Verwaltung, Entwicklung und Bereitstellung von Software in Kubernetes-Clustern zu erleichtern. Dabei erfordert die Vermittlung des Prinzips hinter der Paketverwaltung ein grundlegendes Verständnis von Kubernetes, welches im Folgenden vermittelt werden soll.

Kubernetes

Kubernetes treibt als System zur Orchestrierung, Bereitstellung und allgemeinen Verwaltung von containerisierten Anwendungen seit 2014 den Paradigmenwechsel zur Containerisierung von Software und deren Abhängigkeiten voran. So soll eine konsistente Bereistellung von Systemen sowie eine Portabilität über verschiedene Umgebungen erzielt werden.
Über Helm bereitgestellte Software profitiert damit von vielen leistungsfähigen nennenswerten Funktionen, die Kubernetes durch den Betrieb von Containern in einem Cluster realisiert, darunter Skalierung, Lastverteilung und allgemeine Widerstandsfähigkeit des Systems. Signifikant ist dabei nicht zuletzt der deklarative Ansatz, bei dem ein gewisser vorkonfigurierter Zielzustand beschrieben wird. Unabhängige, komponierbare Steuerungsprozesse treiben den aktuellen Zustand des Systems dabei kontinuierlich in Richtung des bereitgestellten Soll-Zustandes. [2]

Ein solches Kubernetes-Cluster besteht dabei grundlegend aus sogenannten Nodes, die auf einer oder mehreren Maschinen laufen können. Dabei fungiert einer dieser Nodes als Main Node, während die Übrigen als Worker Nodes bezeichnet werden. Der Main Node übernimmt eine allgemeine Steuerungsfunktion für die Worker Nodes und verfügt dafür über verschiedene Komponenten wie den Controller-Manager oder einen API-Server als Schnittstelle für Administratoren.

Grundlegender Bestandteile eines Kubernetes-Clusters: Worker Node(s) und Main Node
Komponenten der Main Node und Worker Nodes in einem Kubernetes-Cluster

Auch die Worker Nodes verfügen über essentielle Komponenten, wobei die wichtigsten die sogenannten Pods sind. Diese Pods umfassen jeweils einen oder mehrere Container, in denen wiederum die letztendlich bereitzustellenden Anwendungen in isolierten Umgebungen laufen.
Der erreichte Endzustand dieser Konfiguration wird als Deployment bezeichnet und beschreibt nicht nur die Anzahl der laufenden Pods in den jeweiligen Nodes, sondern auch weitere Eigenschaften wie das Verhalten der Container beim Einspielen von Updates oder ähnliches.

In der Praxis sind komplexe Anwendungen oft modular aufgebaut, was die Notwendigkeit einer Kommunikation der Pods untereinander erfordert. Dafür werden die Anwendungen in den Pods über sogenannte Services abgebildet, die als eine Art Reverse-Proxy dienen und die Netzwerkkomplexität für den Entwickler abstrahieren. Der Service fungiert dann als Kommunikationsendpunkt für eine gewisse bereitgestellte Anwendung des Clusters.

Services in einem Kubernetes-Cluster
Abstrahierung durch Services in einem Kubernetes-Cluster

Das illustrierte Beispiel zeigt den Betrieb eines Webserver und einer Datenbank in einem Kubernetes-Cluster. Potentielle Anfragen eines beliebigen Webserver-Pods sind dabei nicht an die Datenbank-Pods direkt gerichtet, sondern werden zunächst an den abstrahierenden Datenbank-Service adressiert. Dieser leitet die Anfrage letztendlich an einen verfügbaren Datenbank-Pod weiter, wobei die Auswahl des Pods von Faktoren wie der aktuellen Auslastung abhängen kann.

Damit nun auch eine Kommunikation von extern erfolgen kann, kommt zusätzlich ein sogenannter Ingress-Controller zum Einsatz. Mittels Konfiguration durch Ingress-Resourcen werden bestimmte Pfade und Hostnamen auf bereitgestellte Services abgebildet. Der Ingress-Controller realisiert damit eine Verarbeitung und Weiterleitung von Anfragen aus dem Internet, sodass die betriebenen Anwendungen auch von Clients außerhalb des Clusters addressiert werden können.

Ingress Controller und Ingress Ressourcen
Ingress Controller und Ingress Ressourcen

Grundkonzept von Helm.sh

Damit Kubernetes Ressourcen nicht manuell angelegt werden müssen kann Helm verwendet werden, ein auf Go basierender Paketmanager für Kubernetes. Das Ziel besteht darin, Updates und Rollbacks effizienter zu gestalten. Dafür verwendet es insgesamt drei Grundkonzepte:

Charts

Diese sind vergleichbar mit Homebrew formulaes, apt dpkg oder yum rpm Dateien. Charts sind praktisch eine Sammlung von Dateien, die eine zusammenhängende Menge von Kubernetes-Ressourcen beschreiben. Dafür gibt es zum einen die chart.yml. Diese beinhaltet die Definition der Metadaten des Paketes, z. B. die Angabe der apiVersion, den Namen des Charts, sowie die Beschreibung oder den Typ des Charts, etc.
Optionale Parameter sind möglich, wie zum Beispiel dependencies, maintainers, keyWords oder kubeVersion. Der Typ kann sowohl Application (Standard) oder Library sein. Letzteres beinhaltet üblicherweise keine Ressourcen-Objekte und ist nicht installierbar.
Die values.yml stellt den zentralen Ort für Konfigurationen bereit und beinhaltet Standardwerte für Konfigurationseinstellungen. Die darin definierten Werte können anschließend innerhalb von Templates verwendet werden. Die Wortseparierung erfolgt mittels CamelCase. Eine Definition der Werte ist sowohl verschachtelt als auch flach möglich. Zudem können definierte Standardwerte überschrieben werden, um die Charts an unterschiedliche Umgebungen anpassen zu können. Dadurch wird eine hohe Flexibilität und die Wiederverwendbarkeit von Charts ermöglicht.
Die Dateien chart.yml und values.yml können dann jeweils für Templates verwendet werden, bspw. in einer Kubernetes deployment.yml-Datei. Diese Templates stellen die eigentlichen Kernkomponenten eines Charts dar. Es sind Kubernetes-Manifest-Dateien, über welche dynamische Inhalte gerendert werden können. Zudem verwenden sie verschiedene Werte aus values.yml, um spezifische Aspekte der Kubernetes-Ressourcen zu entwickeln. Als Beispiel können hier die Anzahl der Replikate aufgeführt werden. Insgesamt entsteht eine dynamische Gestaltung der Helm Charts durch die Verwendung von Templates. Dadurch kann der gleiche Chart für verschiedene Installationen mit unterschiedlichen Konfigurationen verwendet werden.

Repositories

Erstellte Helm Charts können in Repositories gespeichert werden. Diese können selbst gehostet werden, wie z. B. über das firmeninterne Nexus. Auf Wunsch kann das eigene Repository bei Artifact Hub angegeben werden. Daraufhin werden die Pakete indexiert und in der Suche angezeigt. Artifact Hub stellt dabei eine Vielzahl von vorgefertigten Charts für gängige Anwendungen zur Verfügung.

Release

Ein Release bezeichnet eine Instanz eines installierten Charts innerhalb eines Kubernetes-Clusters. Helm ermöglicht es, verschiedene Releases des selben Charts mit unterschiedlichen Konfigurationen zu verwalten.

 

Beispielhafter Workflow

  1. Der Softwareentwickler entwickelt ein Chart mit den darin enthaltenen Templates.
  2. Dieses wird anschließend in das firmeninterne Repository verschoben.
  3. Die Cluster werden von einem Administrator verwaltet. Dieser nutzt Helm, muss jedoch nicht genau wissen wie der Chart aufgebaut ist. Er muss eventuell nur wissen, welche Konfigurationen notwendig sind.
  4. Der Administrator kann nun per Kommandozeile der erstellte Chart herunterladen bzw. aktualisieren und in das Kubernetes-Cluster deployen. Dadurch entfällt die Notwendigkeit des manuellen Anlegens der Kubernetes-Ressourcen
  5. Das Deployment erfolgt über den Kubernetes-API-Server, welcher auf dem Main Node läuft und die Charts und Konfigurationen kombiniert, die zum Erstellen eines Releases benötigt werden. Aktualisierung und Deinstallation von Releases sind hierüber ebenfalls möglich.

 

Anwendungsbeispiel 1: Öffentliches Helm Chart

Installation von Minikube und Helm

Es gibt verschiedene Wege, um sich ein eigenes kleines lokales Kubernetes-Cluster aufzusetzen. In diesem Fall soll Minikube verwendet werden. In dieser Anleitung geht man davon aus, dass Minikube auf einem Linux System mit der x86-64 Prozessorarchitektur installiert werden soll. Auf der Minikube Website findet man weitere Anleitungen für andere Betriebssysteme und Prozessorarchitekturen. Minikube kann dann über folgende Kommandos installiert werden:

$ curl -LO \

https://storage.googleapis.com/minikube/releases/latest/minikube-linuxamd64

$ sudo install minikube-linux-amd64 /usr/local/bin/minikube

 

Um das Cluster hochzufahren, muss eine Container-Virtualisierungssoftware wie etwa Docker installiert sein. Das Cluster kann man dann hochfahren über die Eingabe von:

$ minikube start

 

Ab jetzt kann mit dem Kubernetes Cluster mithilfe des Kommandos kubectl interagiert werden, welches bei der Installation von Minikube automatisch mitinstalliert wird. Um sich von der Funktionsweise von kubectl zu überzeugen, kann folgendes Kommando ausgeführt werden, welches die Nodes, aus dem das Cluster besteht, auflistet:

$ kubectl get nodes
NAME       STATUS   ROLES           AGE   VERSION
minikube   Ready    control-plane   42d   v1.28.3

Zudem muss noch ein Addon auf dem Minikube Cluster aktiviert werden:

$ minikube addons enable ingress

Abschließend kann dann noch Helm über die Kommandozeile installiert werden:

$ curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

Installation des Nextcloud Charts

Für dieses Beispiel gehen wir davon aus, dass man einen Nextcloud Server auf dem Kubernetes Cluster installieren möchte. Auf Artifact Hub bietet Nextcloud ein offizielles Nextcloud Helm Chart an. Die Seite des Charts gibt neben Installationsanweisungen auch darüber Auskunft, wie man der Chart bei der Installation konfigurieren kann. Die folgenden Schritte beschreiben chronologisch die Installation des Nextcloud Helm Charts, lassen sich aber theoretisch auch auf die Installation eines beliebigen anderen Charts übertragen.

1. Verweis auf das Nextcloud Repo anlegen

Um der Chart über Helm auf dem lokalen Cluster zu installieren, muss zunächst eine Referenz auf das Repo, in dem der Chart liegt, hinterlegt werden, damit Helm bei der Installation weiß, welches genaue Chart installiert werden soll.

$ helm repo add nextcloud https://nextcloud.github.io/helm/
"nextcloud" has been added to your repositories

2. Konfigurationsdatei anlegen

Um der Chart bei der Installation zu konfigurieren, legt man eine Datei config.yaml an, in der die angestrebte Konfiguration über Key-Value-Paare beschrieben wird:

nextcloud:
   host: mynextcloud.xyz
   username: user01
   password: password123

ingress: 
   enabled: true 
   ingressClass: "nginx"

mariadb: 
   enabled: true
   auth.username: "admin"
   auth.password: "1337H@xx0r"
   auth.rootPassword: "1337H@xx0r"

Mit dieser Konfiguration sorgt man dafür, dass der Nextcloud Server unter der Domain mynextcloud.xyz erreichbar ist und ein Benutzer mit dem Namen user01 und dem Passwort password123 angelegt wird. Da der Server auch von außen bspw. über den Browser ansprechbar sein soll, wird zusätzlich ein Ingress Objekt dazu konfiguriert. Damit die vom Server verwalteten Dateien auch nach einem Neustart des Servers noch vorhanden sind, soll neben dem Nextcloud Server abschließend noch eine MariaDB installiert werden.

3. Installation des Charts

Nun kann der Chart unter der Angabe der im vorigen Schritt erstellten Konfigurationsdatei installiert werden. Der Chart wird hierbei im demo Namespace installiert:

$ : helm -n demo install my-nextcloud nextcloud/nextcloud -f config.yaml
NAME: my-nextcloud
LAST DEPLOYED: Thu Jan 25 11:50:56 2024
NAMESPACE: demo
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
...

Die Installation des Helm Charts – also das Release – trägt den gewählten Namen my-nextcloud, was man aus der Ausgabe des Kommandos erkennen kann.

Um zu sehen, was im Hintergrund auf dem Kubernetes Cluster passiert ist, lässt man sich die Pods, Ingress Objekte und Services im demo Namespace anzeigen:

$ kubectl -n demo get pods,ingress,svc
NAME                                READY   STATUS    RESTARTS   AGE
pod/my-nextcloud-688c657846-n2jzt   1/1     Running   0          80s
pod/my-nextcloud-mariadb-0          1/1     Running   0          80s

NAME                                     CLASS   HOSTS             ADDRESS        PORTS   AGE
ingress.networking.k8s.io/my-nextcloud   nginx   mynextcloud.xyz   192.168.49.2   80      81s

NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/my-nextcloud           ClusterIP   10.100.85.36                  8080/TCP   81s
service/my-nextcloud-mariadb   ClusterIP   10.101.116.73                 3306/TCP   81s

Hier sieht man nun, dass durch die Installation des Charts Kubernetes Ressourcen angelegt wurden. So repräsentieren die zwei Pods den Nextcloud Server sowie die MariaDB Instanz. Ebenso wurde ein Ingress-Objekt erstellt, das angibt, dass der Nextcloud Server unter der angegebenen Domain zu erreichen ist. Die zwei bereitgestellten Services stellen sicher, dass die Pods im Cluster erreicht werden können. Wie man an dieser Stelle sehen kann, spiegelt der Zustand des Clusters mit den angelegten Kubernetes Ressourcen genau die Konfiguration wider, die man bei der Installation des Charts mithilfe der config.yaml übergeben hat.

3. DNS-Eintrag anlegen

Um den Nextcloud Server über die angegebene Domain erreichen zu können, muss im letzten Schritt nur noch ein lokaler DNS-Eintrag angelegt werden, mit dem die Domain mynextcloud.xyz auf die IP-Adresse des Clusters aufgelöst wird. Die IP-Adresse des Clusters erhält man über:

$ minikube ip
192.168.49.2

Dann erstellt man einen DNS-Eintrag in der Datei /etc/hosts. Hier muss die IP-Adresse, die man aus dem Output des vorigen Commands erhält, gefolgt von der Domain mynextcloud.xyz eingetragen werden.
Ein mögliches Beispiel sieht man in der folgenden Abbildung, in der die Domain auf die IP-Adresse 192.168.49.2 auflöst.

127.0.0.1          localhost

192.168.49.2       mynextcloud.xyz

Damit ist die Installation des Nextcloud Helm Charts abgeschlossen und kann nun genutzt werden. Hierzu einfach mynextcloud.xyz im Browser eingeben.

 

Upgrade des installierten Nextcloud Charts

Neben der Installation ist es auch möglich, die Konfiguration eines Helm Releases nach der Installation abzuändern. Der installierte Nextcloud Server soll nun nicht mehr auf die MariaDB angewiesen sein. Dazu passt man zunächst die config.yaml an und kommentiert den nicht mehr benötigten Teil aus:

nextcloud:
   host: mynextcloud.xyz
   username: user01
   password: password123

ingress: 
   enabled: true 
   ingressClass: "nginx"

# mariadb: 
   # enabled: true
   # auth.username: "admin"
   # auth.password: "1337H@xx0r"
   # auth.rootPassword: "1337H@xx0r"

Jetzt kann man der Helm Chart mit der geänderten Konfiguration upgraden.

$ helm -n demo upgrade my-nextcloud nextcloud/nextcloud -f config.yaml
Release "my-nextcloud" has been upgraded. Happy Helming!
...

Wenn man sich nun erneut die Pods und Services auf dem Cluster anzeigen lässt, so fällt auf, dass der MariaDB-Pod und der zugehörige Service verschwunden sind.

kubectl -n demo get pods,ingress,svc
NAME                                READY   STATUS    RESTARTS   AGE
pod/my-nextcloud-69ddd8f55f-5jvhh   1/1     Running   0          113s

NAME                                     CLASS   HOSTS             ADDRESS        PORTS   AGE
ingress.networking.k8s.io/my-nextcloud   nginx   mynextcloud.xyz   192.168.49.2   80      8m49s

NAME                   TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/my-nextcloud   ClusterIP   10.100.85.36                 8080/TCP   8m49s

Deinstallation des installierten Nextcloud Charts

Abschließend möchten wir das Release deinstallieren, um unser Cluster in den Ausgangszustand vor der Installation zurückzuversetzen. Dazu folgenden Command in der Kommandozeile eingeben:

$ helm -n demo uninstall my-nextcloud
release "my-nextcloud" uninstalled

Mit der Deinstallation des Charts werden alle erstellten Kubernetes Ressourcen vollständig entfernt.

 

Anwendungsbeispiel 2: Eigenes Helm Chart

Scenario

Wir arbeiten in einem Unternehmen und haben die Aufgabe jeder Abteilung des Unternehmens zu ermöglichen eine eigene Website auf dem Kubernetes-Cluster bereitzustellen. Hierzu erstellen wir ein Helm Chart, welches unternehmensintern bereitgestellt wird. 

Der Helm Chart

Der folgende Helm Chart erstellt einen NGINX Server, welcher eine einfache HTML Website darstellt. Die Domain der Website und der Inhalt können dabei von der installierenden Person konfiguriert werden. So kann jede Abteilung mit demselben Helm Chart individuelle Webseiten bereitstellen.

Dateien:

department-website-chart/
  app-chart/
    templates/
      configmap.yaml
      deployment.yaml
      ingress.yaml
      service.yaml
    Chart.yaml
    values.yaml

Ein Helm Chart besteht immer aus einer Chart.yaml, einer values.yaml und mehreren Template-Files. 

Charts.yaml

apiVersion: v2
name: bis-app
description: sample nginx deployment
type: application
version: 1.0
appVersion: 1.0

Hier sind die Meta-Informationen des Helm Charts festgehalten, wie Name und Version unseres Charts.

Weitere Infos: https://helm.sh/docs/topics/charts/#the-chartyaml-file

values.yaml

host: department1.local
department: "department1"
message: "Welcome on our website!"
replicas: 1

Hier werden alle variablen Konfigurationen unseres Helm Charts mit zugehörigen Default-Werten festgehalten. Die hier aufgelisteten Parameter können beim Installieren und beim Upgraden des Helm Charts für den entsprechenden Use-Case überschrieben werden.

templates/configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-nginx-config
data:
  nginx.conf: |
    events {
      worker_connections  1024;
    }
    http {
      server {
        listen 80;
        location / {
          return 200 "Greeting from Department {{ .Values.department }}! {{ .Values.message }}";
        }
      }
    }

Die Templates im Ordner templates enthalten die jeweiligen Kubernetes Ressources, welche durch den Helm Chart angelegt werden.

Eine ConfigMap ist ein Kubernetes-Objekt, welches Konfigurationen beinhaltet, die von anderen Kubernetes-Objekten genutzt werden können.

In diesem Beispiel benutzen wir die ConfigMap für unsere NGINX Konfiguration.

Mit {{ .Values.department }} und  {{ .Values.message }} greifen wir hier auf die Werte unserer Einträge aus der values.yaml zu. Beim Installieren werden die vom Nutzer festgelegten Values (bzw. die Default-Values vom Nutzer nicht überschrieben) an die entsprechenden Stellen eingesetzt.

Neben den values können noch auf weitere Werte zurückgegriffen werden, wie z.B. {{ .Release.Name }} welches uns den bei der Installation festgelegten Namen der Installation zurückgibt.

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}
  labels:
    app: {{ .Release.Name }}
spec:
  replicas: {{ .Values.replicas }}
  selector:
   matchLabels:
     app: {{ .Release.Name }}
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
        checksum/values: {{ printf "%s-%s" .Values.department .Values.message | sha256sum }}
    spec:
      containers:
        - name: {{ .Release.Name }}
          image: nginx:stable
          ports:
            - containerPort: 80
          volumeMounts:
            - name: config
              mountPath: /etc/nginx/nginx.conf
              subPath: nginx.conf
      volumes:
       - name: config
          configMap:
            name: {{ .Release.Name }}-nginx-config

Die Deployment Kubernetes-Ressource beschreibt wie der Pod welcher unseren NGINX Container ausführt aussehen soll und wie häufig er bereitgestellt werden soll. Hier wird die zuvor definierte ConfigMap verwendet, um die NGINX Konfiguration als nginx.confDatei in dem Container zu erstellen.

Weitere Infos zu Deployments in der Kubernetes Dokumentation.

service.yaml

apiVersion: v1
kind: Service
metadata:
  name: {{ .Release.Name }}-service
spec:
  type: ClusterIP
  selector:
    app: {{ .Release.Name }}
  ports:
    - protocol: "TCP"
      port: 80
      targetPort: 80

Die Service Kubernetes-Ressource ermöglicht es, innerhalb des Clusters mit den in der deployment.yaml definierten Pods zu kommunizieren. 

Weitere Infos zu Services in der Kubernetes Dokumentation.

ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ .Release.Name }}-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
    - host: {{ .Values.host }}
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: {{ .Release.Name }}-service
                port:
                  number: 80

Der Ingress beschreibt eine Route, über die von extern auf den zuvor definierten Service zugegriffen werden kann. Ein Ingress-Controller sammelt alle Ingress-Ressourcen in einem Cluster und leitet eingehende Anfragen anhand dieser Regeln weiter.

In unserem Fall sagen wir, dass alle Anfragen an den Host, welcher in der values.yaml hinterlegt ist (über host: {{ .Values.host }}), an den Service, den wir in templates/service.yaml definiert haben, weitergeleitet werden. 

Weitere Infos zu Ingress und Ingress-Controllern in der Kubernetes Dokumentation.

 

Helm Chart bereitstellen

Damit der Helm Chart von den Abteilungen unseres Unternehmens genutzt werden kann, müssen wir diesen den Helm Chart zunächst bereitstellen.

Hierzu erstellen wir zunächst einen neuen Ordner charts

department-website-chart/
  app-chart/

  charts/

In diesem Ordner führen wir in der Konsole folgenden Befehl aus:

$ helm package app-chart -d charts
Successfully packaged chart and saved it to: charts/bis-app-1.tgz

Die erstellte Datei bis-app-1.tgz (die 1 im Namen ist die Version des Charts) enthält den gesamten Helm Chart und kann so nun an einzelne Personen im Unternehmen verteilt werden. 

Gehen wir davon aus, wir haben unser Helm Chart erweitert. Dann erhöhen wir die Version des Charts in der Charts.yaml Datei, z.B. auf 1.1 (version: 1.1). Nun müssen wir den Chart erneut packen.

$ helm package app-chart -d charts
Successfully packaged chart and saved it to: charts/bis-app-1.1.tgz

Diese neu erstellte Datei müssten wir nun erneut an alle Personen im Unternehmen verteilen, welche bereits eine frühere Chart Version installiert haben. Diese manuelle Verteilung des Charts ist jedoch unpraktisch und sorgt dafür, dass alte Chart Versionen eventuell nicht geupdatet werden. Auch bei der Verwendung von CI/CD ist ein manuelles Verteilen der Releases nicht möglich. Daher möchten wir uns Helm-Repositories als eine bessere Lösung anschauen, um Charts bereitzustellen.

Hierzu indizieren wir zunächst den chart Ordner

$ helm repo index charts

Wir erhalten die Datei charts/index.yaml

apiVersion: v1
entries:
  bis-app:
  - apiVersion: v2
    appVersion: "1"
    created: "2024-01-23T13:46:16.938718324+01:00"
    description: sample nginx deployment
    digest: c964f1a73aa1920286359578496a52341b77d4d226ad32cd6dfdb421c59fd4cb
    name: bis-app
    type: application
    urls:
    - bis-app-1.1.tgz
    version: "1.1"
  - apiVersion: v2
    appVersion: "1"
   created: "2024-01-23T13:46:16.939021608+01:00"
    description: sample nginx deployment
   digest: 552c9bdf46b657dae607483912088d245c0a11b34a4ae35644c9a863ae61b10b
    name: bis-app
    type: application
    urls:
    - bis-app-1.tgz
    version: "1"
generated: "2024-01-23T13:46:16.938178662+01:00"

Diese Datei listet alle gepackten Helm Charts in Ordner charts inklusive deren Metainformation auf.

Der Ordner charts kann nun mit einem beliebigen Webserver bereitgestellt und direkt als Helm Repository verwendet werden. Als schnelle und einfache Möglichkeit, Dateien über einen Webserver bereitzustellen, nutzen wir für das Beispiel Github-Pages.

Hierzu muss der Ordner in ein Github-Repository gepusht werden und für das Repository Github-Pages aktiviert werden.

Ob euer Helm Repository erreichbar ist könnt ihr überprüfen, indem ihr versucht die index.yaml Datei von eurer Github-Page anzufragen:

$ curl https://<Username>.github.io/<repository>/charts/index.yaml

Da die Github Page öffentlich erreichbar ist, sind auch die Helm Charts öffentlich erreichbar. Unternehmensintern müsste der Webserver entweder durch Zugangsdaten abgesichert werden oder nur aus dem internen Netz erreichbar sein.

Chart installieren

Nun wollen wir den erstellten Helm Chart über das eigene Repository installieren. Hierzu müssen wir das neu erstellte Repository zunächst lokal hinterlegen.

$ helm repo add bis-repo https://<Username>.github.io/<repository>/charts/
"bis-repo" has been added to your repositories

Mit dem folgenden Befehl kann überprüft werden, welche Repositories lokal hinterlegt sind:

$ helm repo list
NAME     URL                                               
bis-repo https://<Username>.github.io/<repository>/charts/

Mit dem hinterlegten Repository können wir nun einen Namespace erstellen und unser Helm Chart dort installieren:

$ kubectl create ns bis
namespace/bis created

$ helm install bis bis-repo/bis-app -n bis
NAME: bis
LAST DEPLOYED: Tue Jan 23 14:09:25 2024
NAMESPACE: bis
STATUS: deployed
REVISION: 1
TEST SUITE: None

Der install Befehl ist wie folgt aufgebaut

helm install <release-name> <repo>/<chart>[:<chart-version>] -n <kubernetes-namespace>

Wenn wir nun die einzelnen Kubernetes Ressourcen ausgeben, sehen wir, dass alles im Helm Chart Definierte erstellt wurde. Hier als Beispiel einmal die erstellten Pods und der Ingress.

$ kubectl get pod -n bis
NAME                   READY   STATUS    RESTARTS   AGE
bis-6ff46c7499-24bgx   1/1     Running   0          2m17s

$ kubectl get ingress -n bis
NAME          CLASS   HOSTS               ADDRESS        PORTS   AGE
bis-ingress   nginx   department1.local   192.168.58.2   80      3m50s

Wenn wir nun die Website department1.local aufrufen, bekommen wir folgende Antwort.

$ curl department1.local
Greeting from Department department1! Welcome on our website!

Die angezeigte Nachricht können wir nun durch Überschreiben einiger Values unseres Helm Releases anpassen:

$ helm upgrade bis bis-repo/bis-app -n bis --set message="Greetings to BIS!" --set replicas=3
Release "bis" has been upgraded. Happy Helming!
NAME: bis
LAST DEPLOYED: Tue Jan 23 14:20:55 2024
NAMESPACE: bis
STATUS: deployed
REVISION: 2
TEST SUITE: None

Einerseits haben wir die Replicas auf 3 gesetzt. Dadurch wurden anstelle nur eines Pods nun drei Pods gestartet.

$ kubectl get pods -n bis
NAME                   READY   STATUS    RESTARTS   AGE
bis-6d6549c7fb-b9wnh   1/1     Running   0          37s
bis-6d6549c7fb-nb68f   1/1     Running   0          39s
bis-6d6549c7fb-z75j4   1/1     Running   0          40s

Des Weiteren haben wir die Nachricht, welche vom Webserver zurückgegeben wird, angepasst.

$ curl department1.local
Greeting from Department department1! Greetings to BIS!

Zweite Abteilung

Jetzt wollen wir das Gleiche noch einmal für eine zweite Abteilung in unserem Unternehmen umsetzen. Diese soll ebenfalls eine eigene Website bekommen, welche auf demselben Kubernetes Cluster läuft.

Hierzu erstellen wir zunächst eine neue Datei department2-values.yaml welche die Konfiguration für unser Helm Release beinhaltet.

host: department2.local
department: "department2"
replicas: 2

Dann erstellen wir einen neuen Namespace und installieren den Chart für unsere Abteilung2.

$ kubectl create ns bis2
namespace/bis2 created

$ helm install bis bis-repo/bis-app -n bis2 -f department2-values.yaml
NAME: bis
LAST DEPLOYED: Tue Jan 23 14:27:25 2024
NAMESPACE: bis2
STATUS: deployed
REVISION: 1
TEST SUITE: None

Wir können nun beide Webseiten aufrufen.

$ curl department1.local
Greeting from Department department1! Greetings to BIS!

$ curl department2.local
Greeting from Department department2! Welcome on our website!

Abschließend können wir uns von Helm noch einmal alle aktuell installierten Helm Charts anzeigen lassen

$ helm ls -A
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
bis bis 2 2024-01-23 14:20:55.470634413 +0100 CET deployed bis-app-1.1 1.1 
bis bis2 1 2024-01-23 14:27:25.781652628 +0100 CET deployed bis-app-1.1 1.1

 

 

Fazit

Anhand des ersten Anwendungsbeispiels, bei dem das öffentlich zugängliche Helm Chart von Nextcloud auf einem Kubernetes Cluster installiert wurde, lassen sich einige der Vorteile, die Helm bietet, erkennen. Die Installation eines Charts entspricht dem gebündelten Deployment von Kubernetes Ressourcen. Im Gegensatz zur herkömmlichen Interaktion mit einem Cluster müssen die Kubernetes Ressourcen nicht einzeln händisch angelegt werden, sondern können über einen einzigen Helm Command schnell und einfach auf das Cluster gebracht werden. Das Gleiche gilt für den Vorgang des Löschens eines Releases bei dem alle von Helm angelegten Ressourcen gebündelt gelöscht werden. Des Weiteren kann man am ersten Anwendungsbeispiel erkennen, dass der Anwender zu keinem Zeitpunkt dazu gezwungen war, direkt mit dem Kubernetes Cluster zu interagieren. Helm schafft mit seiner Nutzerschnittstelle ein Abstraktionslevel, das den internen Aufbau und die Funktionsweise von Kubernetes vor dem Anwender versteckt. Den Entwicklern von Helm war es wichtig, dass sich Helm sowohl an mit der Funktionsweise von Kubernetes vertraute Anwender als auch an solche richtet, die über wenig bis kaum Erfahrung und technisches Wissen im Bereich von Kubernetes verfügen.

Am zweiten Anwendungsbeispiel kann man erkennen, dass Helm die Abdeckung verschiedener Anwendungsfälle mit nur einem Chart ermöglicht, wodurch die Notwendigkeit für neue Charts entfällt. Wir konnten problemlos zwei Webserver für unterschiedliche Abteilungen erstellen, indem wir lediglich Konfigurationsparameter anpassten, ohne den Code ändern zu müssen. Ein entscheidender Vorteil von Helm liegt zudem in seiner Fähigkeit, das installierte Chart zusammen mit seiner Version auf dem Cluster zu dokumentieren. Dadurch wird eine umfassende Versionsverwaltung gewährleistet, die Transparenz über den aktuellen Stand sowie potenzielle Änderungen mit einem Update oder zwischen den Deployments schafft. Diese Dokumentation ermöglicht eine klare Nachvollziehbarkeit jeder Chart Version. Des Weiteren erleichtert Helm die Reproduzierbarkeit eines bestimmten Zustands erheblich, da sowohl die Konfiguration als auch der Status des Charts als Code gespeichert werden können. Dadurch wird eine konsistente Bereitstellung und Verwaltung von Anwendungen gewährleistet, was wiederum die Zuverlässigkeit und Effizienz der Entwicklungs- und Betriebsprozesse verbessert.

Es lässt sich festhalten, dass das Deployment von Charts über Helm große Vorteile bietet. Helm trägt wesentlich dazu bei, Anwendungen auf Kubernetes Clustern einfach und schnell zur Verfügung zu stellen und spielt damit im Bereich der betrieblichen Informationssysteme eine nicht unwesentliche Rolle.

Einzelnachweise

  1. Was ist Kubernetes? (2022, 17. Juli). Kuberneteshttps://kubernetes.io/de/docs/concepts/overview/what-is-kubernetes/
  2. Helm | Helm. (o. D.). https://helm.sh/
  3. Helm | Docs Home. (o. D.). https://helm.sh/docs/