⎈ Helm Lektion 2/12 ~8 Min. Einsteiger

Chart-Struktur und Anatomy

Aufbau eines Helm Charts: Chart.yaml, values.yaml, templates/.

📝 Meine Notizen

Lernziele

Nach dieser Lektion kennst du jede Datei in einem Helm-Chart und weißt, wofür sie da ist: Chart.yaml, values.yaml, templates/, _helpers.tpl und charts/. Du kannst den Unterschied zwischen version und appVersion erklären, weißt, welche Dateien Helm rendert und welche nicht, und kannst mit helm create ein sauberes Gerüst erzeugen und lesen.

Das Problem: Ein Paket braucht eine verbindliche Konvention

In Lektion 1 hast du gesehen, dass ein Chart die Blaupause für ein Release ist. Damit Helm — und jedes andere Tool im Ökosystem — ein Chart verarbeiten kann, muss es eine feste Verzeichnisstruktur haben. Das ist kein Selbstzweck: Artifact Hub liest Metadaten aus Chart.yaml, Argo CD weiß, wo die Templates liegen, und helm lint kann prüfen, ob alles am richtigen Platz ist. Eine Konvention statt Konfiguration — wer schon mal ein Maven- oder npm-Projekt geöffnet hat, kennt das Prinzip.

Die Struktur im Überblick:

mychart/
├── Chart.yaml          # Metadaten: Name, Version, Dependencies
├── values.yaml         # konfigurierbare Standardwerte
├── charts/             # paketierte Sub-Charts (Dependencies)
├── templates/          # Manifeste mit Go-Template-Platzhaltern
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── _helpers.tpl    # Named Templates, wird nicht direkt gerendert
│   └── NOTES.txt       # Hinweistext nach der Installation
└── .helmignore         # was beim Paketieren ausgeschlossen wird

Chart.yaml: der Steckbrief des Pakets

Chart.yaml ist die einzige Pflichtdatei neben templates/. Drei Felder sind zwingend: apiVersion (für Helm 3 immer v2), name und version. Der Rest ist optional, aber wichtig:

apiVersion: v2
name: mychart
description: Eine Beispiel-Anwendung
type: application
version: 0.1.0
appVersion: "1.16.0"

Der Klassiker unter den Interview-Fragen versteckt sich hier: version vs. appVersion. version ist die Version des Charts — sie muss SemVer folgen und steigt, wenn sich Templates, Values oder Dependencies ändern. appVersion ist die Version der Anwendung, die das Chart paketiert — reine Information, oft als Default für den Image-Tag genutzt. Ein Chart in Version 4.2.1 kann nginx 1.27.0 ausliefern; beide Zahlen haben nichts miteinander zu tun. Wer das verwechselt, bumpt beim nächsten App-Release die falsche Nummer.

Das Feld type unterscheidet application (normales, installierbares Chart) von library. Ein Library Chart enthält nur Named Templates als wiederverwendbare Bausteine und kann selbst nicht installiert werden — das Muster dahinter schauen wir uns in Lektion 6 an. Unter dependencies: deklarierst du Sub-Charts; das ist Thema von Lektion 8.

values.yaml und templates/: die Arbeitsteilung

Das Herz des Charts ist die Trennung zwischen was konfigurierbar ist und wie es gerendert wird. values.yaml definiert die Standardwerte:

replicaCount: 1
image:
  repository: nginx
  tag: ""

Und in templates/deployment.yaml greifen Go-Template-Ausdrücke darauf zu:

spec:
  replicas: {{ .Values.replicaCount }}

Wichtig fürs Verständnis: values.yaml ist gleichzeitig Dokumentation der Schnittstelle. Wer dein Chart benutzt, liest zuerst diese Datei, um zu sehen, was er überschreiben kann. Deshalb gilt: jeder Wert mit sinnvollem Default und einem Kommentar, was er tut. Die Details der Template-Syntax und der Values-Hierarchie folgen in Lektion 5.

Helm rendert jede Datei unter templates/ — mit zwei Ausnahmen. Dateien, deren Name mit einem Unterstrich beginnt (per Konvention _helpers.tpl), werden zwar von der Template-Engine eingelesen, erzeugen aber kein eigenes Manifest. Dort liegen Named Templates wie mychart.fullname oder die Standard-Labels, die andere Templates per include einbinden. Und NOTES.txt wird gerendert, aber nicht an die Kubernetes-API geschickt — ihr Inhalt erscheint als Hinweistext nach helm install, etwa „so erreichst du deine Anwendung”.

Die Spezialfälle: charts/, crds/ und .helmignore

Drei Verzeichnisse bzw. Dateien sorgen regelmäßig für Verwirrung:

charts/ enthält die paketierten Dependencies als .tgz-Archive, nachdem du helm dependency update ausgeführt hast. Du editierst dort nie von Hand — das Verzeichnis ist ein Build-Artefakt, gesteuert über den dependencies:-Block in Chart.yaml.

crds/ ist ein Sonderfall mit Sprengkraft: CustomResourceDefinitions in diesem Verzeichnis installiert Helm vor allen Templates, aber nur beim allerersten helm install. Bei Upgrades fasst Helm sie nie wieder an — eine bewusste Entscheidung, weil ein CRD-Update oder -Löschen clusterweit Daten zerstören kann. Wer Operator-Charts pflegt, muss CRD-Upgrades deshalb separat planen.

.helmignore funktioniert wie .gitignore, nur für helm package: Was dort steht, landet nicht im .tgz. Ohne diese Datei paketierst du schnell .git/-Verzeichnisse, CI-Configs oder lokale Test-Values mit — im harmlosen Fall wird das Paket groß, im schlimmsten Fall verteilst du interne Dateien an alle Chart-Nutzer.

Praxis: ein Chart-Gerüst erzeugen und sezieren

helm create erzeugt ein lauffähiges Best-Practice-Gerüst — der schnellste Weg, die Struktur zu verinnerlichen:

helm create mychart
tree mychart   # oder: find mychart -type f

# Chart validieren und rendern, ohne Cluster
helm lint mychart
helm template test-release mychart | less

# Was ändert sich, wenn du einen Value überschreibst?
helm template test-release mychart --set replicaCount=3 | grep replicas

# Paketieren und reinschauen
helm package mychart
tar -tzf mychart-0.1.0.tgz

Schau dir dabei drei Dinge bewusst an: Erstens templates/_helpers.tpl — dort definiert das Gerüst mychart.fullname, mychart.labels und mychart.selectorLabels, die jedes andere Template einbindet. Zweitens, dass helm template aus NOTES.txt keine Kubernetes-Ressource macht. Drittens den Dateinamen des Pakets: <name>-<version>.tgz — die Chart-Version aus Chart.yaml ist Teil der Identität des Artefakts.

Typische Stolperfallen

Chart-Version nicht gebumpt: Du änderst ein Template, lässt version: 0.1.0 stehen und pusht ins Repository. Konsumenten mit gepinnter Version sehen die Änderung nie — oder schlimmer, das Repository lehnt das Überschreiben einer existierenden Version ab und deine CI bricht.

appVersion als Steuerung missverstanden: appVersion ändert für sich genommen nichts am Deployment. Nur wenn deine Templates sie explizit referenzieren (z. B. tag: {{ .Values.image.tag | default .Chart.AppVersion }} — so macht es das helm create-Gerüst), hat sie einen Effekt.

Nicht-Template-Dateien in templates/: Eine README oder ein Shell-Skript in templates/ jagt Helm durch die Template-Engine — geschweifte Klammern im Inhalt führen zu kryptischen Parse-Fehlern. Solche Dateien gehören auf die oberste Ebene oder in .helmignore.

CRDs im falschen Verzeichnis: CRDs als normale Templates unter templates/ werden bei jedem Upgrade angefasst und bei helm uninstall gelöscht — inklusive aller Custom Resources, die davon abhängen. Unter crds/ sind sie vor beidem geschützt; dafür musst du Upgrades selbst organisieren. Beides muss eine bewusste Entscheidung sein.

Interview-Vorbereitung

Auf „Wie ist ein Helm-Chart aufgebaut?” antwortest du am besten entlang des Datenflusses statt als Dateiliste: Chart.yaml identifiziert das Paket (Name + Version), values.yaml definiert die konfigurierbare Schnittstelle, templates/ rendert daraus Manifeste, _helpers.tpl hält die wiederverwendbaren Bausteine, charts/ die Dependencies. Dann ein Satz zu den Sonderfällen NOTES.txt und crds/ — das zeigt, dass du Charts wirklich gebaut hast.

Typische Follow-ups:

  • „Unterschied version und appVersion?” — Chart-Version (SemVer, Pflicht, Teil des Artefaktnamens) vs. Anwendungsversion (informativ, oft Default für den Image-Tag).
  • „Warum beginnt _helpers.tpl mit einem Unterstrich?” — Konvention: Dateien mit Unterstrich erzeugen kein eigenes Manifest, sie stellen nur Named Templates bereit.
  • „Was ist ein Library Chart?” — type: library, nicht installierbar, liefert nur Template-Bausteine für andere Charts.
  • „Was passiert mit crds/ bei einem Upgrade?” — nichts; Helm installiert CRDs daraus nur beim ersten Install.

Zusammenfassung

Ein Chart ist ein Verzeichnis mit fester Konvention: Chart.yaml (Identität, versionappVersion), values.yaml (konfigurierbare Schnittstelle mit Defaults), templates/ (gerenderte Manifeste plus die Sonderlinge _helpers.tpl und NOTES.txt), charts/ (paketierte Dependencies) und crds/ (nur beim ersten Install). helm create liefert dir ein Gerüst, das alle Konventionen korrekt vormacht.

In der nächsten Lektion geht es um das, was aus einem Chart wird, wenn du es installierst: Releases, Revisionen und wie Rollbacks wirklich funktionieren.