Helmfile: Deklaratives Management für Helm Charts
Zurück zum Blog

Helmfile: Deklaratives Management für Helm Charts

6 Min. Lesezeit
Lesen auf English

Wenn Helm allein nicht mehr skaliert

Helm hat vieles einfacher gemacht. Statt roher Kubernetes-Manifeste arbeitet man mit parametrisierten Charts, die sich pro Umgebung konfigurieren lassen. Doch wer ein Projekt mit zwanzig oder mehr Helm Releases verwaltet, merkt schnell: Die Komplexität verschiebt sich nur.

In einem unserer aktuellen Kundenprojekte laufen pro Cluster rund dreißig Services -- eigene Spring-Boot-Anwendungen, Datenbanken, Ingress-Controller, Monitoring-Stacks, Message-Broker. Jedes Release erfordert einen eigenen helm upgrade-Befehl mit der richtigen Kombination aus Chart-Version, Values-Datei und Namespace. Multipliziert mit drei Umgebungen -- Development, Staging, Production -- ergeben sich knapp hundert individuelle Helm-Befehle, die in der richtigen Reihenfolge und mit den richtigen Parametern ausgeführt werden müssen.

Shell-Skripte helfen anfangs, werden aber schnell fragil. Die Frage ist: Warum beschreiben wir unsere Infrastruktur deklarativ in Kubernetes-Manifesten, verwalten die Deployments aber imperativ mit einzelnen Helm-Befehlen?

Genau hier setzt Helmfile an.

Was Helmfile leistet

Helmfile ist ein deklarativer Wrapper um Helm. Statt Releases einzeln per Kommandozeile zu installieren, beschreibt man den gewünschten Zustand aller Releases in einer einzigen YAML-Datei -- der helmfile.yaml. Helmfile liest diese Datei, vergleicht den Soll-Zustand mit dem Ist-Zustand im Cluster und führt die notwendigen Änderungen durch.

Das Konzept ist vergleichbar mit Terraform für Cloud-Infrastruktur: Man definiert, was man will, nicht wie man dorthin kommt. Der entscheidende Unterschied zu Kustomize oder reinem Helm ist, dass Helmfile sich auf die Orchestrierung mehrerer Helm Releases spezialisiert, anstatt einzelne Manifeste zu manipulieren.

Aufbau einer helmfile.yaml

Die Struktur ist bewusst einfach gehalten. Eine helmfile.yaml besteht aus drei Kernbereichen: Repositories, Releases und Environments.

repositories:
  - name: bitnami
    url: https://charts.bitnami.com/bitnami
  - name: ingress-nginx
    url: https://kubernetes.github.io/ingress-nginx
  - name: prometheus-community
    url: https://prometheus-community.github.io/helm-charts

releases:
  - name: my-spring-app
    namespace: application
    chart: ./charts/spring-boot-app
    version: 1.4.0
    values:
      - values/{{ .Environment.Name }}/app.yaml

  - name: postgresql
    namespace: database
    chart: bitnami/postgresql
    version: 9.8.4
    values:
      - values/{{ .Environment.Name }}/database.yaml

  - name: ingress-nginx
    namespace: ingress
    chart: ingress-nginx/ingress-nginx
    version: 3.7.1
    values:
      - values/{{ .Environment.Name }}/ingress.yaml

  - name: prometheus
    namespace: monitoring
    chart: prometheus-community/kube-prometheus-stack
    version: 10.1.0
    values:
      - values/{{ .Environment.Name }}/monitoring.yaml

environments:
  dev:
    values:
      - environments/dev.yaml
  staging:
    values:
      - environments/staging.yaml
  production:
    values:
      - environments/production.yaml

Im repositories-Block definiert man alle Helm-Repositories, aus denen Charts bezogen werden. Im releases-Block listet man jedes Helm Release mit Name, Namespace, Chart-Quelle und Values-Dateien auf. Der environments-Block ermöglicht umgebungsspezifische Konfigurationen.

Der Ausdruck {{ .Environment.Name }} ist ein Go-Template, das zur Laufzeit durch den Namen der aktiven Umgebung ersetzt wird. Dadurch lädt Helmfile automatisch die passenden Values-Dateien, ohne dass man separate Konfigurationsdateien pflegen muss.

Verzeichnisstruktur für Values

In der Praxis hat sich folgende Verzeichnisstruktur bewährt:

helmfile/
  helmfile.yaml
  environments/
    dev.yaml
    staging.yaml
    production.yaml
  values/
    dev/
      app.yaml
      database.yaml
      ingress.yaml
      monitoring.yaml
    staging/
      app.yaml
      database.yaml
      ingress.yaml
      monitoring.yaml
    production/
      app.yaml
      database.yaml
      ingress.yaml
      monitoring.yaml

Jede Umgebung hat eigene Values-Dateien pro Release. Die globalen Umgebungsvariablen -- etwa Cluster-Domain, Registry-URL oder Ressourcen-Defaults -- liegen in der jeweiligen environments/*.yaml. Diese Werte stehen dann allen Releases als Template-Variablen zur Verfügung.

Die wichtigsten Befehle

Helmfile bietet eine Handvoll Befehle, die den gesamten Lifecycle abdecken:

# Gewünschten Zustand anwenden -- installiert neue Releases, aktualisiert bestehende
helmfile -e production sync

# Änderungen anzeigen, ohne sie auszuführen (Dry-Run mit Diff)
helmfile -e production diff

# Nur geänderte Releases aktualisieren (effizienter als sync)
helmfile -e production apply

# Alle Releases der Umgebung entfernen
helmfile -e production destroy

# Templates lokal rendern (zum Prüfen)
helmfile -e production template

Der -e-Parameter wählt die Umgebung. helmfile sync bringt den Cluster auf den definierten Zustand -- neue Releases werden installiert, bestehende aktualisiert. helmfile diff zeigt die Änderungen an, ohne sie durchzuführen, ähnlich wie terraform plan. helmfile apply kombiniert beides: Es zeigt den Diff und führt nur die tatsächlich geänderten Releases aus.

In unseren CI/CD-Pipelines verwenden wir helmfile diff als Validierungsschritt und helmfile apply für das eigentliche Deployment. So sieht man im Pipeline-Log genau, was sich ändern wird, bevor die Änderungen wirksam werden.

Imperativ vs. Deklarativ: Der Unterschied in der Praxis

Ohne Helmfile sieht ein Deployment-Skript für vier Releases ungefähr so aus:

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

helm upgrade --install postgresql bitnami/postgresql \
  --namespace database --version 9.8.4 \
  -f values/production/database.yaml

helm upgrade --install my-spring-app ./charts/spring-boot-app \
  --namespace application --version 1.4.0 \
  -f values/production/app.yaml

helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress --version 3.7.1 \
  -f values/production/ingress.yaml

helm upgrade --install prometheus prometheus-community/kube-prometheus-stack \
  --namespace monitoring --version 10.1.0 \
  -f values/production/monitoring.yaml

Das funktioniert, hat aber Nachteile: Die Reihenfolge ist implizit, Fehler in einem Befehl brechen nicht zwingend das gesamte Deployment ab, und der gewünschte Zustand ist über mehrere Befehle verteilt. Mit Helmfile reduziert sich das auf:

helmfile -e production apply

Ein Befehl, der den gesamten Zustand abgleicht. Deklarativ statt imperativ.

Helmfile und GitOps

Helmfile fügt sich nahtlos in GitOps-Workflows ein. Die helmfile.yaml und alle Values-Dateien liegen im Git-Repository. Änderungen durchlaufen den normalen Pull-Request-Prozess mit Code Review. Die CI/CD-Pipeline führt bei einem Merge auf den Main-Branch helmfile apply aus und bringt den Cluster auf den gewünschten Zustand.

Das bedeutet: Git ist die Single Source of Truth für den gesamten Cluster-Zustand. Jede Änderung ist nachvollziehbar, jedes Deployment reproduzierbar. Wer den aktuellen Zustand eines Clusters wissen will, schaut ins Repository, nicht in den Cluster.

Umgebungsvariablen lassen sich über die environments-Sektion oder über Helmfiles eingebaute Unterstützung für Umgebungsvariablen einbinden. Secrets können über das helm-secrets-Plugin verschlüsselt im Repository liegen, sodass auch sensible Werte versioniert werden, ohne im Klartext sichtbar zu sein.

Abgrenzung zu anderen Tools

Helmfile ist nicht die einzige Option für deklaratives Kubernetes-Management. Kustomize arbeitet direkt auf Kubernetes-Manifesten ohne Helm und eignet sich gut für Teams, die den Helm-Overhead vermeiden wollen. Terraform mit dem Helm-Provider bietet Zustandsverwaltung und eignet sich, wenn man Cloud-Infrastruktur und Kubernetes-Deployments im selben Tool verwalten möchte.

Helmfile positioniert sich dazwischen: Es nutzt Helm als Basis, erweitert es aber um die deklarative Orchestrierung mehrerer Releases. Wer bereits in Helm Charts investiert hat und die bestehenden Charts weiter nutzen will, findet in Helmfile das flexibelste Werkzeug, um diese Charts umgebungsübergreifend zu verwalten.

Fazit

Helm löst das Problem der Parametrisierung einzelner Deployments. Helmfile löst das Problem der Orchestrierung vieler Deployments. Sobald ein Cluster mehr als eine Handvoll Releases umfasst -- und das ist in Microservice-Architekturen der Regelfall -- rechtfertigt sich der Einsatz von Helmfile schnell.

Der Einstieg ist niedrigschwellig: Eine helmfile.yaml mit den bestehenden Releases anlegen, Values-Dateien in die passende Verzeichnisstruktur verschieben und helmfile sync ausführen. Von dort aus lässt sich die Konfiguration schrittweise um Environments, Templates und Secrets erweitern.

In unseren Projekten hat Helmfile die Deployment-Skripte weitgehend abgelöst. Der Cluster-Zustand ist im Repository dokumentiert, Änderungen sind nachvollziehbar, und ein neues Deployment ist ein einzelner Befehl. Wer Helm bereits nutzt und mit der Verwaltung vieler Releases kämpft, sollte Helmfile ausprobieren.

Teilen

Patrick Hütter

Geschrieben von

Patrick Hütter

Gründer & Software-Architekt

Softwarearchitekt, Ingenieur und Unternehmer. Patrick baut seit über einem Jahrzehnt Produkte und Plattformen — von Enterprise-Backends über Cloud-Native-Infrastruktur bis hin zu KI-gestützten Anwendungen. Als Gründer von encircle360 verbindet er technische Tiefe mit unternehmerischem Denken und treibt Open-Source-Projekte voran, die echten Impact haben.