Notiz

Helm gegen Kustomize 2026: wer rendert und woher das Chart kommt

Helm vs Kustomize 2026: unter Argo CD greift die Hälfte der üblichen Argumente nicht — Helm-Releases gibt es dort keine, und die eigentliche Grenze zwischen den Engines verläuft dort, wo Zugangsdaten für die Registry nötig sind.

Wie viele Helm-Releases liegen im Cluster, wenn Argo CD die Anwendungen ausrollt? Null. helm ls ist leer, helm history hat nichts zu zeigen. Argo CD nutzt Helm als Template-Engine: es führt helm template aus, nimmt die gerenderten Manifeste und wendet sie mit der eigenen Engine an — helm install wird nie aufgerufen. Das FAQ des Projekts sagt es wörtlich, und im Code ist es sichtbar (util/helm/helm.go).

Daraus folgt sofort etwas für die Debatte «Helm gegen Kustomize»: Argumente über Release-Historie, helm rollback und Lifecycle-Steuerung per Hooks greifen im GitOps-Kreis nicht. Historie und Rollback liefert Argo CD — argocd app history, argocd app rollback.

Zu vergleichen bleiben drei Dinge: die Sprache, in der Konfiguration beschrieben wird, die Herkunft des Artefakts und die Fähigkeit, dieses Artefakt aus einer geschlossenen Registry zu holen. Das erste ist Geschmackssache. Die beiden anderen sind 2026 zu harten technischen Grenzen geworden.

Was sich im Jahr geändert hat

Der Zweig Helm 3 schließt. Release 3.22.0 (September 2026) ist sein letztes Minor, bewusst eingeschränkt: es aktualisiert nur die Kubernetes-Client-Bibliotheken für neuere Cluster. Security-Patches laufen bis zum 10. Februar 2027. HIP-0012 nannte ursprünglich November 2026; die Maintainer legten drei Monate drauf. Nach Februar bekommt 3.x gar nichts mehr. Aktuelles Helm ist 4.3.0 aus demselben September-Fenster.

Für GitOps zählt anderes mehr. Ab Argo CD 3.5 rendert ausschließlich Helm 4 die Charts. Das Feld spec.source.helm.version wird ignoriert — stehen lassen ist erlaubt, Wirkung hat es keine. In 3.5.3 steckt Helm 4.2.1; die weiterhin unterstützten Zweige 3.3 und 3.4 laufen auf Helm 3.19.4. Welche Version der Template-Engine in der Pipeline arbeitet, bestimmt die Argo-CD-Version, nicht das, was lokal installiert ist.

Für CI hat das eine praktische Folge. Läuft in der Pipeline helm template oder helm diff mit einem Helm-3-Binary, während das Argo CD im Cluster schon auf 3.5 ist, vergleicht man die Ausgabe zweier verschiedener Renderer und hofft, dass sie übereinstimmt. Die Helm-Version in CI gehört an die Argo-CD-Version gebunden, nicht an das, was im Runner-Image liegt. Die Topologie entscheidet den Rest: bei Hub-and-Spoke rendert ein einziges Argo CD auf dem Hub, also gibt es eine Helm-Version im Kreis; bei Argo CD in jedem Cluster laufen die Cluster über Argo-CD-Minors auseinander und mit ihnen über die Versionen der Template-Engine.

Kustomize lebt leiser: 5.8.2 kam am 30. September 2026, davor 5.8.1 im Februar und 5.8.0 im November 2025. Drei Releases in elf Monaten. Die in kubectl eingebaute Version hängt hinter dem eigenständigen Binary: kubectl 1.36 und 1.37 tragen 5.8.1, Argo CD 3.5.3 ebenfalls 5.8.1.

Das Upgrade, das die interne Registry bricht

Der Umstieg von Argo CD auf Helm 4 brachte einen unauffälligen Breaking Change — OCI-Registries ohne TLS. Helm 4 verlangt ein explizites --plain-http, wo der Vorgänger ohne auskam. In Argo CD hilft ein Flag im Repository-Secret:

stringData:
  insecureOCIForceHttp: "true"

Die Feinheit steckt in den Dependencies. Zeigt Chart.yaml auf repository: oci://… in einer Registry ohne TLS, muss diese Registry in Argo CD separat als Repository mit demselben Flag registriert werden. Unter Helm 3 wurden solche Dependencies transparent gezogen, ohne Registrierung. Eine Falle liegt gleich bereit: sind --insecure-skip-server-verification und --insecure-oci-force-http gleichzeitig gesetzt, verliert Helm 4 --plain-http stillschweigend.

Wo sie zusammenleben und wo die Kombination bricht

Die Engines zu mischen ist fast unvermeidlich: fremdes Chart plus eigene Werte. Zwei Wege funktionieren.

Der erste ist eine Multi-Source-Application. Das Chart kommt aus einer Helm- oder OCI-Registry, die Values liegen in Git und werden über ref und $values eingebunden. Die Zugangsdaten bleiben in den Repository-Secrets von Argo CD, wo sie hingehören.

spec:
  sources:
    - repoURL: https://prometheus-community.github.io/helm-charts
      chart: prometheus
      targetRevision: 15.7.1
      helm:
        valueFiles:
          - $values/charts/prometheus/values.yaml
    - repoURL: https://git.example.com/org/value-files.git
      targetRevision: dev
      ref: values

Der zweite Weg ist Kustomize mit dem Feld helmCharts: das Chart wird innerhalb von Kustomize inflatiert, darüber kommen Patches. So installiert man Argo Rollouts und die Hälfte der CRD-Operatoren. Dieser Weg hat eine Decke, und sie ist dokumentiert.

Das Flag --enable-helm, ohne das helmCharts nicht arbeitet, lässt sich in Argo CD nur global einschalten — über kustomize.buildOptions: --enable-helm in argocd-cm, für alle Kustomize-Anwendungen gleichzeitig. Eine Option pro Application gibt es dafür nicht; die Alternative heißt CMP-Plugin schreiben.

Authentifizierung fehlt vollständig. Der Generator baut das Kommando helm pull ohne ein einziges Credential-Flag zusammen: kein --username, kein --password, kein --registry-config, kein --plain-http. Die Repository-Secrets von Argo CD erreichen diesen Pfad nicht, sie wirken nur für die native Helm-Source. Das Schema oci:// unterstützt der Generator — dafür gibt es in pullCommand() einen eigenen Zweig —, aber eine private Registry oder eine ohne TLS ist deklarativ überhaupt nicht konfigurierbar. Auf einem internen Harbor ohne TLS baut die Kombination «Kustomize + helmCharts + Argo CD 3.5» gar nicht.

Die Kustomize-Maintainer verschweigen das nicht: der Generator ist als begrenzte Teilmenge von Helm gedacht, angenommen werden Bugfixes, kritische Security-Arbeit und Flags analog zu helm template. Unterstützung für private Registries und Authentifizierung ist nicht geplant — die nächste Iteration soll eine KRM-Funktion werden. Dieses Dokument liest sich als Absichtserklärung: es verspricht auch, OCI nicht aufzunehmen, und das Schema oci:// steckt bereits im Code des Generators.

Hooks und Determinismus

Argo CD erkennt helm.sh/hook und verteilt Hooks auf die eigenen Phasen, doch die Zuordnung ist unvollständig, und die Unterschiede ändern das Verhalten:

  • pre-install und pre-upgrade fallen zu PreSync zusammen. Argo CD unterscheidet Erstinstallation und Update nicht — alles ist ein Sync. Ein Migrations-Job für die Datenbank mit "helm.sh/hook": pre-upgrade,pre-install läuft bei jedem Sync. Ist er nicht idempotent, erfahren Sie es an den Daten.
  • pre-rollback, post-rollback, test-success, test-failure und hook-delete-timeout werden ignoriert.
  • Ein einziger eigener argocd.argoproj.io/hook in der Application schaltet alle Helm-Hooks ab.

Der zweite Handlungsstrang ist der Determinismus des Renderings. helm template läuft bei jedem Vergleich mit dem Cluster neu. Ein Chart, das ein Passwort per randAlphaNum erzeugt, liefert ewiges OutOfSync: der Wert ändert sich bei jedem Rendern, der Diff konvergiert nie. Heilung ist, den Wert in den Values festzunageln. Reines Kustomize, ohne helmCharts, hat diese Problemklasse konstruktionsbedingt nicht: die Ausgabe von kustomize build ist deterministisch. Die starke Seite ist hier genau der Determinismus; das Fehlen von Templates garantiert für sich nichts — packen Sie ein Chart in helmCharts, und es rendert dasselbe Template mit demselben randAlphaNum und demselben ewigen OutOfSync.

Für Determinismus verlangt Kustomize seinen Preis: der Patch lebt getrennt vom Objekt, und um das fertige Manifest zu sehen, muss das Overlay gebaut werden. Dazu die Altlast in gewachsenen Bäumen. Version 5.0.0 erklärte patchesStrategicMerge, patchesJson6902 und vars für veraltet, bases schon 2.1.0; Ersatz sind patches, replacements und resources, konvertiert von kustomize edit fix. Aus kustomize.config.k8s.io/v1beta1 werden sie nicht entfernt, in das künftige v1-API aber nicht übernommen — reparieren muss man also. Die automatische Umwandlung von vars zu replacements kann viele Dateien überschreiben und die Build-Ausgabe verändern — machen Sie sie in einem sauberen Git-Baum.

Was auch rendert: geprüft wird das Render-Ergebnis, nicht die Quelle. Policies am Ausgang von helm template und kustomize build fangen ab, was im Cluster nichts zu suchen hat, unabhängig von der Wahl der Engine.

Wann was wählen

SituationWahlWarum
Fremdes Chart aus öffentlicher oder privater RegistryNative Helm-Source plus Values über Multi-SourceZugangsdaten, TLS und OCI-Flags liegen in Repository-Secrets
Eigene Manifeste, viele UmgebungenKustomize: Bases und OverlaysDeterministische Ausgabe, Patches statt verzweigter Templates
Chart muss oben korrigiert werden: Annotationen, Limits, SidecarKustomize plus helmChartsPatch über dem Render, aber die Registry muss öffentlich und per TLS erreichbar sein
Interne Registry ohne TLS oder mit AutorisierungNur native Helm-SourceDer Generator helmCharts übergibt weder Zugangsdaten noch --plain-http
Chart geht an externe NutzerHelmChart-Versionierung, Dependencies, OCI-Distribution

Was daraus folgt

Die Wahl diktiert die Herkunft des Artefakts. Wo ein Chart aus einer Registry geholt werden muss, die Zugangsdaten verlangt oder ohne TLS läuft, bleibt ein Weg gangbar — die native Helm-Source in Argo CD: nur sie hat einen Kanal zu den Repository-Secrets. Wo die Manifeste eigene sind und im selben Git liegen, gibt Kustomize einen deterministischen Build und Patches statt verzweigter Templates. Der Geschmack an Go-Templates spielt in dieser Entscheidung keine Rolle; eine Rolle spielt, wem die Registry die Tür öffnet.

© 2026 axyi.ru · CC BY 4.0