Helm Charts: Kubernetes-Deployments standardisieren
Zurück zum Blog

Helm Charts: Kubernetes-Deployments standardisieren

6 Min. Lesezeit
Lesen auf English

Wenn kubectl allein nicht mehr reicht

Wer eine einzelne Spring-Boot-Anwendung in Kubernetes deployt, kommt mit ein paar YAML-Dateien und kubectl apply erstaunlich weit. Ein Deployment, ein Service, vielleicht noch eine ConfigMap -- das ist überschaubar. Doch in der Praxis bleibt es selten bei einer Anwendung.

In unseren Projekten verwalten wir inzwischen zehn bis zwanzig Microservices pro Cluster, jeweils mit Deployment, Service, Ingress, ConfigMap und Secrets. Multipliziert man das mit drei Umgebungen -- Development, Staging und Production -- landet man schnell bei hundert oder mehr YAML-Dateien. Und genau hier beginnen die Probleme: Werte wie Image-Tags, Replica-Counts oder Ressourcen-Limits unterscheiden sich pro Umgebung, sind aber über dutzende Dateien verstreut. Ein Image-Update erfordert manuelle Änderungen an mehreren Stellen. Copy-Paste-Fehler schleichen sich ein, Konfigurationen driften auseinander.

Was fehlt, ist ein Mechanismus, der Kubernetes-Manifeste parametrisierbar und wiederverwendbar macht. Genau das leistet Helm.

Was Helm ist -- und was Charts sind

Helm bezeichnet sich selbst als Paketmanager für Kubernetes, und die Analogie ist treffend: Was APT für Debian oder YUM für Red Hat ist, ist Helm für Kubernetes. Es bündelt zusammengehörige Kubernetes-Ressourcen in einem definierten Format -- den sogenannten Charts -- und macht sie versionierbar, konfigurierbar und teilbar.

Ein Helm Chart ist im Kern ein Verzeichnis mit einer festen Struktur:

my-spring-app/
  Chart.yaml          # Metadaten: Name, Version, Beschreibung
  values.yaml         # Standard-Konfigurationswerte
  templates/          # Kubernetes-Manifeste als Go-Templates
    deployment.yaml
    service.yaml
    ingress.yaml
    configmap.yaml
  charts/             # Abhängigkeiten zu anderen Charts

Chart.yaml enthält die Metadaten des Charts -- Name, Version und eine Beschreibung. values.yaml definiert die Standardwerte, mit denen die Templates gerendert werden. Und im templates/-Verzeichnis liegen die eigentlichen Kubernetes-Manifeste, allerdings nicht als statisches YAML, sondern als Go-Templates mit Platzhaltern.

Parametrisierung: Das Herzstück von Helm

Die eigentliche Stärke von Helm liegt in der Trennung von Struktur und Konfiguration. Anstatt in jeder YAML-Datei konkrete Werte zu schreiben, referenziert man Variablen, die zur Deployment-Zeit aus der values.yaml aufgelöst werden.

Eine typische values.yaml für eine Spring-Boot-Anwendung sieht bei uns so aus:

replicaCount: 2

image:
  repository: registry.example.com/my-spring-app
  tag: "1.3.0"
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

resources:
  requests:
    memory: "256Mi"
    cpu: "250m"
  limits:
    memory: "512Mi"
    cpu: "500m"

spring:
  profile: "default"

Das zugehörige Deployment-Template greift auf diese Werte zu:

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-{{ .Chart.Name }}
  labels:
    app: {{ .Chart.Name }}
    release: {{ .Release.Name }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Chart.Name }}
      release: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app: {{ .Chart.Name }}
        release: {{ .Release.Name }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - containerPort: 8080
          resources:
            requests:
              memory: {{ .Values.resources.requests.memory }}
              cpu: {{ .Values.resources.requests.cpu }}
            limits:
              memory: {{ .Values.resources.limits.memory }}
              cpu: {{ .Values.resources.limits.cpu }}
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: {{ .Values.spring.profile | quote }}

Die doppelten geschweiften Klammern markieren Go-Template-Ausdrucke. .Values verweist auf die values.yaml, .Release enthält Informationen uber das aktuelle Release, .Chart die Metadaten aus der Chart.yaml. Mit dem quote-Filter stellt man sicher, dass Werte korrekt in Anführungszeichen gesetzt werden.

Umgebungsspezifische Konfigurationen

Der entscheidende Vorteil zeigt sich, wenn man verschiedene Umgebungen bedienen muss. Statt separate YAML-Dateien pro Umgebung zu pflegen, erstellt man zusätzliche Values-Dateien:

# values-dev.yaml
replicaCount: 1
image:
  tag: "latest"
resources:
  requests:
    memory: "128Mi"
    cpu: "100m"
  limits:
    memory: "256Mi"
    cpu: "250m"
spring:
  profile: "dev"
# values-prod.yaml
replicaCount: 3
image:
  tag: "1.3.0"
resources:
  requests:
    memory: "512Mi"
    cpu: "500m"
  limits:
    memory: "1Gi"
    cpu: "1000m"
spring:
  profile: "production"

Beim Deployment gibt man einfach die passende Values-Datei an. Die Templates bleiben identisch -- nur die Konfiguration ändert sich. Kein Duplizieren von Manifesten, keine Gefahr, dass Umgebungen strukturell auseinanderlaufen.

Helm in der Praxis: Installation, Upgrades und Rollbacks

Bevor man Helm nutzen kann, muss es im Cluster initialisiert werden. Helm 2 arbeitet mit einer Client-Server-Architektur: Der helm-Client läuft lokal, und auf Cluster-Seite läuft Tiller -- ein Server-Prozess, der die eigentlichen Deployments ausführt.

# Helm initialisieren (installiert Tiller im Cluster)
helm init

# Chart installieren -- Development-Umgebung
helm install --name my-app-dev -f values-dev.yaml ./my-spring-app

# Chart installieren -- Production-Umgebung
helm install --name my-app-prod -f values-prod.yaml ./my-spring-app

# Laufendes Release aktualisieren (z.B. neues Image-Tag)
helm upgrade my-app-prod -f values-prod.yaml --set image.tag="1.4.0" ./my-spring-app

# Rollback auf die vorherige Version
helm rollback my-app-prod 1

# Alle Releases anzeigen
helm list

# Templates lokal rendern, ohne zu deployen (zum Prüfen)
helm template -f values-prod.yaml ./my-spring-app

Besonders helm template hat sich in unserem Workflow als unverzichtbar erwiesen. Der Befehl rendert die Templates lokal und gibt das fertige YAML aus, ohne irgendetwas im Cluster zu ändern. So kann man vor jedem Deployment prüfen, ob die generierten Manifeste korrekt sind -- ideal auch für Code Reviews und CI-Pipelines.

helm upgrade führt ein Rolling Update durch und versioniert dabei jedes Release. Falls etwas schiefgeht, bringt helm rollback den vorherigen Zustand zurück. Helm verwaltet die Release-Historie intern, sodass man jederzeit zu einer früheren Revision zurückkehren kann.

Ein Wort zu Tiller

Tiller ist die serverseitige Komponente von Helm und einer der am kontroversesten diskutierten Aspekte. Tiller läuft als Pod im Cluster und benötigt weitreichende Berechtigungen, um Ressourcen erstellen und verwalten zu können. In der Standardkonfiguration hat Tiller Cluster-Admin-Rechte -- das ist in Shared-Cluster-Umgebungen ein ernstzunehmendes Sicherheitsthema.

Für Produktionsumgebungen empfehlen wir, Tiller mit eingeschränkten RBAC-Rechten zu betreiben und den Zugriff per TLS abzusichern. Die Konfiguration ist nicht trivial, aber notwendig:

# Tiller mit Service-Account und eingeschränktem Namespace installieren
helm init --service-account tiller --tiller-namespace my-team

Die Community diskutiert aktiv über die Zukunft von Tiller. Es gibt Bestrebungen, den serverseitigen Anteil zu reduzieren oder ganz zu eliminieren. Bis es soweit ist, sollte man die Sicherheitsimplikationen kennen und entsprechend absichern.

Charts wiederverwenden und teilen

Neben eigenen Charts gibt es ein wachsendes Ökosystem an öffentlichen Charts. Das offizielle Stable-Repository enthält Charts für gängige Software wie PostgreSQL, Redis, Prometheus oder Nginx Ingress. Ein helm search zeigt die verfügbaren Charts, und mit helm install stable/postgresql hat man in Sekunden eine Datenbank im Cluster.

Für eigene Charts lässt sich ein privates Chart-Repository aufsetzen -- im einfachsten Fall ein HTTP-Server, der ein Index-File und die gepackten Chart-Archive bereitstellt. In unseren Teams haben wir ein internes Repository mit Basis-Charts für Spring-Boot-Services, die neue Projekte als Ausgangspunkt nutzen. Das spart bei jedem neuen Service erheblich Einrichtungszeit.

Fazit

Helm löst ein reales Problem, das jedes Team kennt, das mehr als eine Handvoll Services in Kubernetes betreibt: die Verwaltung von Konfiguration über Umgebungen hinweg. Die Trennung von Template-Struktur und Konfigurationswerten ist ein einfaches, aber wirkungsvolles Konzept. Statt hunderte YAML-Dateien manuell zu pflegen, hat man parametrisierte Charts, die sich für Development, Staging und Production gleichermaßen nutzen lassen.

Helm entwickelt sich zunehmend zum De-facto-Standard für Kubernetes-Deployments. Immer mehr Projekte und Tools setzen auf das Chart-Format, und die Community wächst stetig. Wer Kubernetes ernsthaft nutzt, kommt an Helm kaum noch vorbei.

Unser Rat: Fangt mit einem einzelnen Service an. Erstellt ein Chart, parametrisiert die wichtigsten Werte und deployt es in zwei Umgebungen. Der initiale Aufwand zahlt sich schnell aus -- spätestens beim nächsten Service, der das gleiche Chart als Vorlage nutzen kann.

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.