Helm – der Package Manager für Kubernetes - Teil 2

04.03.2021 Stefan Welsch
Cloud DevOps helm cicd iac k8s handson

Einleitung

Im ersten Teil haben wir gesehen, wo man einen bereits vorhanden Chart findet (Helm Hub) und wie man diesen auf einem Kubernetes Cluster installiert. Wir haben uns angeschaut, wie man eigene Konfigurationen an den Chart übergeben kann und wie man ein Upgrade und Rollback durchführt. Heute wollen wir noch einen Schritt weiter gehen und uns anschauen, wie man einen eigenen Chart erstellen kann.

Aufbau eines Chart

Wollen wir uns als erstes anschauen, wie ein Helm Chart aufgebaut ist. Am einfachsten erstellen wir uns hierfür einen eigenen Chart. Helm bietet uns einen einfachen Befehl, mit dem wir das Grundgerüst unseres eigenen Chart erstellen können.

~ ❯ helm create mychart
Creating mychart

Schauen wir uns an, was passiert ist. Es wurde ein Ordner erstellt, in dem die erforderlichen Konfigurationen liegen.

~ ❯ ls mychart
Chart.yaml  charts      templates   values.yaml

Chart.yml

In dieser Datei befinden sich die Metadaten des Charts, wie Name, Beschreibung, Typ und Version. ApiVersion muss immer gesetzt werden und ist für Helm 3 “v2”.

~/mychart ❯ cat Chart.yaml
apiVersion: v2
name: mychart
description: A Helm chart for Kubernetes

# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.0"

Verzeichnis: charts

Dieses Verzeichnis ist leer. Wir haben hier die Möglichkeit bereits bestehende Charts hinzuzufügen, welche für unseren Chart benötigt werden, also Abhängigkeiten. Eine weitere und von Helm bevorzugte Möglichkeit Abhängigkeiten hinzuzufügen, ist als dependencies Feld in der Chart.yaml Datei. Wir können hier Abhängigkeiten hinzufügen und anschliessend mit dem Befehl helm dependency update diese Abhängigkeiten in den charts Ordner herunterladen.

Für unser einfaches Beispiel brauchen wir diese Funktion aber erstmal nicht.

dependencies:
  - name: apache
    version: 1.2.3
    repository: http://example.com/charts
  - name: mysql
    version: 3.2.1
    repository: http://another.example.com/charts

Weitere Informationen dazu findet man auf der Helm Seite.

Verzeichnis: templates

Nun kommen wir zu dem Herzstück unseres Charts. In diesem Verzeichnis finden sich alle Konfigurationsdateien, welche wir für die Installation auf dem Kubernetes Cluster benötigen. Alle Dateien, die sich im templates Verzeichnis befinden, werden durch die Helm Template Rendering Engine gesendet. Die Ergebnisse der Templates werden gesammelt und anschliessend zu Kubernetes gesendet.

~/mychart ❯ ls templates
NOTES.txt           _helpers.tpl        deployment.yaml     hpa.yaml            ingress.yaml        service.yaml        serviceaccount.yaml tests

Wir sehen hier verschiedene Dateien, welche bereits von Helm für uns angelegt wurden.

  • NOTES.txt:

    • Das ist der Hilfetext für einen Chart. Dieser wird dem Benutzer angezeigt, wenn er helm install ausführen
  • deployment.yaml, service.yaml, hpa.yaml, ingress.yaml, serviceaccount.yaml:

    • Grundgerüste um eine Kubernetes Resource zu erstellen
  • _helpers.tpl:

    • Hier befinden sich Helper für Templates, welche im Chart wiederverwendet werden können.
  • tests:

    • Hier befinden sich Tests um die Funktionalität des Charts im Cluster zu verifizieren.

values.yaml

Die values.yaml Datei ist wichtig um die Templates zu parsen. Hier befinden sich alle Default Werte, welche vom Benutzer mit helm install oder helm upgrade überschrieben werden können.

Mit diesem Wissen können wir nun unseren ersten eigenen Chart entwickeln.

Der erste eigene Chart

Wollen wir mit einem einfach Beispiel starten. Dafür löschen wir im Ordner templates erstmal alle Dateien, damit wir unser kleines Tutorial von Grund auf beginnen können.

rm -rf mychart/templates/* 

Anschliessend erstellen wir unser erstes eigenes Template. Wir erstellen eine Datei mit dem Namen configmap.yaml mit folgendem Inhalt:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  name: {{.Values.myName}}

In der Datei haben wir nun eine unbekannte Syntax.

{{ .Release.Name }} und {{.Values.myName}}. Beides sind spezielle Platzhalter, welche durch die Template Rendering Engine ersetzt werden.

{{ .Release.Name }} wird, wie der Name schon sagt, dynamisch durch den Namen des Release ersetzt, welchen wir beim Installieren angeben.

{{.Values.myName}} wird durch das Property myName aus der Datei values.yaml ersetzt. Schauen wir uns dafür diese Datei einmal genauer an.

myName: b-nova

Nun haben wir bereits einen vollständig lauffähigen und installierbaren Chart. Schauen wir uns an, was bei der Installation passiert. Dafür können wir dem install Befehl das Flag --dry-run anhängen um die Installation lediglich zu simulieren. Mit --debug aktivieren wir “verbose” Output.

~ ❯ helm install myRelease ./mychart --dry-run --debug
install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: ~/mychart

NAME: myRelease
LAST DEPLOYED: Thu Feb  4 19:07:54 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
myName: b-nova

HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myRelease-configmap # <-- {{ .Release.Name }}
data:
  name: b-nova # <-- {{.Values.myName}}

Wie wir sehen können wurden unsere Platzhalter wie gewünscht ersetzt. Nun können wir unseren Chart installieren. Wir wollen aber bei der Installation nicht den Default Name “b-nova” nutzen, sondern wollen einen eigenen Namen vergeben. Weiter oben haben wir bereits gesehen, dass wir die Werte durch Angabe einer eigenen values.yaml Datei, oder durch das --set Flag bei der Installation überschreiben können. Wir wollen an dieser Stelle die zweite Variante versuchen.

~ ❯ helm install bnova-chart ./mychart --debug --set myName=whats_my_name
install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: /Users/swelsch/mychart

client.go:122: [debug] creating 1 resource(s)
NAME: bnova-chart
LAST DEPLOYED: Thu Feb  4 19:18:16 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
myName: whats_my_name

COMPUTED VALUES:
myName: whats_my_name

HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: bnova-chart-configmap
data:
  name: whats_my_name

Success! Der Chart wurde erfolgreich installiert und der Default-Name wurde mit dem dynamischen Wert ersetzt. Jetzt wollen wir noch einmal verifizieren, ob unsere ConfigMap auch wirklich richtig deployed wurde. Wir schauen also mit kubectl direkt auf dem Cluster nach.

~/mychart ❯ kubectl get configmap
NAME                    DATA   AGE
bnova-chart-configmap   1      4m40s

Wie wir sehen wurde die ConfigMap mit dem richtigen Namen angelegt. Schauen wir uns zur Vollständigkeit auch noch den Inhalt an.

~/mychart ❯ kubectl describe configmap bnova-chart-configmap
Name:         bnova-chart-configmap
Namespace:    default
Labels:       app.kubernetes.io/managed-by=Helm
Annotations:  meta.helm.sh/release-name: bnova-chart
              meta.helm.sh/release-namespace: default

Data
====
name:
----
whats_my_name
Events:  <none>

Den gesamten Code findet ihr im im b-nova Github

Auch der Inhalt entspricht dem erwarteten Ergebnis. Wir haben damit erfolgreich unseren ersten Chart erstellt und auf unserem Cluster installiert.

Next Steps:

Helm Charts hat im Managed Container Umfeld eine grosse Zukunft. Wir werden die Entwicklung von Helm daher gespannt weiterverfolgen. Im nächsten TechUp will ich mit euch die folgenden Themen an einem praktischen Beispiel anschauen:

  • Monocular - das Frontend für Helm

  • Ein eigenes Repository hosten

  • Template:

    • Template Functions und Pipelines

    • Flow Control

    • Built-In Objects

    • Named Templates

    • Subcharts

    • Debugging Templates

    • Post Rendering

    • File Handling

  • Best practices

Viel Spass und stay tuned!

Stefan Welsch - pioneer, stuntman, mentor. As the founder of b-nova, Stefan is always looking for new and promising fields of development. He is a pragmatist through and through and therefore prefers to write articles that are as close as possible to real-world scenarios.