Die Werkzeugkiste #1: Helm – Kubernetes-Deployments richtig gemacht

Seite 2: Ein Helm Chart anlegen

Inhaltsverzeichnis

Wer für eigene Applikationen nun selber Hand anlegen möchte, kann mit helm create einfach starten. Er legt ein neues Verzeichnis an, das ein Grundgerüst für ein neues Chart enthält. Als Grundlage für weitere Beispiele legt der Befehl helm create webserver zunächst ein Chart für einen Webserver mit NGINX an:

apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: webserver
version: 0.1.0

Die Metadaten des Charts wie Name und Version sind in der Datei Chart.yaml vorhanden. Das Beispiel ist dem erzeugten Grundgerüst entnommen.

replicaCount: 1
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
ingress:
enabled: false

Eine weitere wichtige Datei ist die values.yaml. Dort liegen die Standardwerte für konfigurierbare Variablen. Das Listing nutzt das Docker Image nginx mit dem Tag latest. Kommandozeilenargumente oder eine separate, ähnlich aufgebaute YAML-Datei können die Variablen beim Deployment überschreiben.

apiVersion: v1
kind: Service
metadata:
name: {{ template "webserver.fullname" . }}
labels:
app: {{ template "webserver.name" . }}
chart: {{ template "webserver.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
app: {{ template "webserver.name" . }}
release: {{ .Release.Name }}

Die Vorlagen für die zu erzeugenden Kubernetes-Objekte liegen im Verzeichnis templates. Obiges Beispiel zeigt den Kubernetes-Service, der einen stabilen und eindeutigen Zugangspunkt zu allen laufenden Pods, also Containern, bietet. Wie man im Listing sieht, sind an vielen Stellen die Werte durch Ausdrücke ersetzt, die erst beim Deployment ausgefüllt werden.

Der Befehl helm template kann die Templates mit gefüllten Werten anzeigen. Er benötigt einen Pfad zum Chart und zeigt die gerenderten Templates auf der Standardausgabe an.

$ helm install webserver
NAME: unrealized-penguin
LAST DEPLOYED: Fri Oct 12 16:45:36 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
unrealized-penguin-webserver ClusterIP 10.103.42.236 <none> 80/TCP 0s

==> v1beta2/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
unrealized-penguin-webserver 1 1 1 0 0s

==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
unrealized-penguin-webserver-8487bbb44-5psrb 0/1 Pending 0 0s


NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app=webserver,release=unrealized-penguin" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80

Das erstellte Chart kann man mit dem Befehl helm install in den Kubernetes Cluster installieren. Helm bezeichnet den Prozess als Release. Sollte man keinen Namen vorgeben, generiert Helm hierfür einen eindeutigen Namen. Er lautet im Beispiel "unrealized-penguin". Er dient danach für alle weiteren Änderungen als Bezeichner. Die Ausgabe zeigt die neu erzeugten Ressourcen innerhalb des Clusters an. Abschließend sehen Nutzer unter "Notes" Informationen zum Zugriff auf die Ressourcen. Sie entstehen aus der Datei "NOTES.txt" innerhalb der Templates.

helm upgrade unrealized-penguin webserver --set image.tag=latest

Der Befehl helm upgrade führt eine Änderung durch. Im Beispiel ersetzt er den Tag des Docker Images. Er hatte aufgrund der Standardwerte zuvor den Wert "stable". Der Aufruf ändert ihn nun in "latest".

$ helm list
NAME REVISION UPDATED STATUS CHART NAMESPACE
unrealized-penguin 2 Fri Oct 12 16:48:47 2018 DEPLOYED webserver-0.1.0 default

Wer die Liste der aktuell installierten Releases nun mit helm list prüft, sieht dass das Beispiel in der zweiten Revision vorliegt. Der Befehl helm history kann nun für jedes Release die Liste der erfolgten Deployments anzeigen. Sollte ein Release Probleme verursachen, können Entwickler mit helm rollback jederzeit auf eine ältere Revision zurückkehren.

Das Basiswissen sollte ausreichen, um Charts für die eigenen Bedürfnisse anzupassen. Wer in die Entwicklung von Helm Charts einsteigen will, ist mit der Dokumentation gut beraten.

Die gezeigten Befehlen ermöglichen Helm die Integration in eine CI/CD-Pipeline. Mit dem Chart können Entwickler eine Beschreibung der Applikation erstellen, die unabhängig von der genutzten Umgebung ist. Beim Deployment müssen nur die sich ändernden Werte wie Image-Version oder umgebungsabhängige Konfigurationen übergeben werden.

Wer neben seiner eigenen Applikation weitere Abhängigkeiten installieren möchte, kann das über Repositorys tun – ein Verteilmechanismus für das zentrale Bereitstellen von Charts. Das bekannteste dürfte das stable-Repository sein, das beim Initialisieren von Helm eingerichtet wird. Die Community auf GitHub pflegt die Quelle der Charts.

Die Installation einer MariaDB erfolgt über den Befehl helm install stable/mariadb. Er lädt das benötigte Chart aus dem Repository herunter und installiert es als separates Release. Das ermöglicht Entwicklern einen schnellen Aufbau und Test von Infrastruktur für die eigenen Applikationen.

Die genannte Variante ist schnell ausgeführt, allerdings wäre es sinnvoll, die eigene Applikation mit einer Abhängigkeit zu verbinden um immer ein einheitliches Deployment und Un-Deployment zu haben.

dependencies:
- name: mariadb
version: 5.x.x
repository: https://kubernetes-charts.storage.googleapis.com/
condition: mariadb.enabled

Dafür kann man innerhalb eines Helm Charts in der Datei requirements.yamleine Abhängigkeit definieren und die Abhängigkeiten mit dem Befehl helm dependency build herunterladen. Im Fall eines Releases mit Helm läuft die Installation automatisch ab.

Releases erfolgen immer atomar. Das heißt, ein Rollout geschieht für die Anwendung mit allen Abhängigkeiten oder nicht. Sollten sich zudem Änderungen wie das Wegfallen von Abhängigkeit ergeben, ist das Entfernen ebenfalls automatisiert.