5 Nachteile von Helm

null

5 Gründe, warum wir versuchen, die nächste Generation der Deployment Automation für Kubernetes zu entwickeln. Willst du unsere Reise verfolgen? Dann lass und einen Star auf GitHub da: glasskube/glasskube

Einleitung

Als erfahrener DevOps Engineer habe ich festgestellt, dass Helm, das beliebte Kubernetes Deployment-Tool, einige schockierende Mängel aufweist. In diesem Beitrag möchte ich einige davon diskutieren, die meiner Meinung nach eine neue Vision einer moderneren Deployment-Lösung erfordern. Wenn du noch nie von Helm gehört hast, ist es kurz gesagt:

Ein Framework, um Kubernetes-Ressourcen (Apps) in Charts zu verpacken, sie zu veröffentlichen und über eine Command-Line-Interface einfach installieren zu lassen.

Ziel dieses Beitrags ist es nicht, die klugen und talentierten Leute, die Helm entwickelt haben, zu kritisieren, sondern vielmehr eine produktive und gesunde Diskussion darüber anzustoßen, wohin wir als DevOps-Branche gehen müssen, um in den kommenden Jahren relevant zu bleiben. Aber um das Folgende vollständig zu verstehen, ist es meiner Meinung nach wichtig zu verstehen, welche Entwicklungen uns dahin geführt haben, wo wir heute sind. Bevor wir also beginnen, möchten wir kurz in die Geschichte von Helm eintauchen.

Im Jahr 2015 entwickelte ein Unternehmen namens Deis Helm, einen Paketmanager für Kubernetes. Deis ist jetzt Teil von Azure Kubernetes Service, aber das ursprüngliche Projekt existiert immer noch als Helm Classic. Zur gleichen Zeit gab es bei Google ein Projekt namens Kubernetes Deployment Manager, das dem Google Deployment Manager ähnelte, allerdings für Kubernetes-Ressourcen und nicht für GCS-Ressourcen.

Anfang 2016 beschlossen die beiden Projekte, sich zusammenzuschließen, was später im selben Jahr zur Veröffentlichung von Helm v2 führte. Helm v2 besteht aus einer Client- und einer Serverkomponente (Helm bzw. Tiller), wobei letztere die Fortsetzung des ursprünglichen Kubernetes Deployment Manager-Projekts war. Tiller wurde entwickelt, um Deployment-states zu verwalten, damit mehrere Nutzer Helm einfacher nutzen können, ohne sich gegenseitig zu behindern.

Im Jahr 2018 hat Helm den Helm Hub als zentralen Ort zum Auffinden von Diagrammen eingeführt, die sonst in verstreuten Repositories zu finden sind. Helm Hub wurde 2020 umbenannt in Artifact Hub.

Mit der Veröffentlichung von Kubernetes 1.6, das standardmäßig über eine rollenbasierte Zugriffskontrolle (RBAC) verfügte, wurde der produktive Einsatz von Helm aufgrund der vielen Sicherheitsrichtlinien, die von Kubernetes benötigt wurden, schwieriger. Daher begann man, mit einem neuen Ansatz zu experimentieren, der das Gleiche ohne eine Serverkomponente leisten konnte, was zur Veröffentlichung von Helm v3 im Jahr 2019 führte.

Wie ihr seht, hat Helm eine sehr bewegte Geschichte. Es wurde zum Goldstandard für die Paketierung von Apps für Kubernetes und wird von DevOps-Ingenieuren auf der ganzen Welt verwendet. Aber nur weil Helm der größte Player auf dem Feld ist, bedeutet das nicht, dass es ohne Fehler ist. Warum sollte man sich dann von Helm verabschieden?

5 Nachteile:

1. Helm bietet keinen Mechanismus für Upgrades von Custom Resource Definitions

Helm bietet eine Methode zum Verpacken von Custom Resource Definitions (CRDs), indem es sie in einem speziellen crds- directory ablegt, aber diese werden bei Upgrades ignoriert! Dies ist beabsichtigt und dient dazu, einen versehentlichen Datenverlust zu verhindern. Daher werden beim Upgrade eines Diagramms die zugehörigen CRDs nicht automatisch aktualisiert, was für viele Techniker unerwartet ist und zu mehr manuellen und fehleranfälligen Upgrade-Prozeduren und anderen Anti-Mustern führt.

Um diesen schwerwiegenden Konstruktionsfehler zu umgehen, haben die Chart-Entwickler mehrere Strategien entwickelt, von denen die beliebtesten sind:

  • Ablage der CRDs im Verzeichnis "Template" des Diagramms
  • Erstellung separater Unterdiagramme nur für CRDs

Eine alternative Möglichkeit, dieses Manko zu überwinden, besteht darin, die helm-commands nicht direkt aufzurufen, sondern eine CI/CD-Lösung wie Flux zu verwenden. Flux bietet eine Einstellung, um CRDs während eines helm-Upgrades automatisch zu aktualisieren, aber sie ist standardmäßig ausgeschaltet.

2. Helm Dependency Management

Die Art und Weise, eine Dependency in einem Helm-Chart zu spezifizieren, besteht darin, sie als Sub-Chart zu referenzieren. Diese Methode eignet sich hervorragend für eng gekoppelte Dependencys, die separat oder als Teil eines anderen Charts installiert werden sollen, hat aber einige Mängel, die es zu beachten gilt:

  • Unterdiagramme werden immer im gleichen Namespace wie die Hauptversion installiert und es gibt keine Möglichkeit, dies zu ändern.
  • Es gibt keinen Mechanismus, um eine Dependency zwischen zwei Versionen zu teilen.

Zum Beispiel hängt unser Glasskube Operator Helm Chart von kube-prometheus-stack, velero und einer Reihe anderer Dependencys ab, von denen einige bereits in vielen Kubernetes-Clustern installiert sind. Um die Installation so einfach wie möglich zu gestalten, verweist das Diagramm auf alle diese Dependencys als Unterdiagramme. Bei diesem Ansatz werden jedoch alle diese Dependencys in der Glasskube Operator Version gebündelt und können nicht separat geändert oder aktualisiert werden. Darüber hinaus gibt es keine Möglichkeit zu überprüfen, ob eine Abhängigkeit bereits installiert ist, so dass ein Benutzer am Ende zwei verschiedene Installationen desselben Helmdiagramms haben könnte!

Ideale Tools würden es den Entwicklern von Charts erlauben, externe Abhängigkeiten anzugeben und einfach sicherzustellen, dass diese in einem Cluster vorhanden sind, bevor ein Chart installiert werden kann. Auf diese Weise könnten die Dependencies gemeinsam genutzt werden. So funktionieren Paketmanager für Betriebssysteme seit jeher. Warum muss Kubernetes anders sein?

3. Die Erstellung von Helm-Charts ist nicht benutzerfreundlich

Bis jetzt haben wir Probleme besprochen, die den Nutzer von Charts betreffen. Aber wie sieht die Situation für Chart-Entwickler aus?

Beginnen wir mit der Erstellung eines neuen Diagramms. Dies lässt sich durch den Aufruf von helm create your-chart durchführen. Ich empfehle dir, schnell ein Terminal zu öffnen, diesen Befehl auszuführen und alle Dateien durchzugehen, die er erzeugt. Ich bin sicher, du stimmst mir zu, dass es... viel ist. Ich erinnere mich noch an den Moment, als ich meine erstes Helm-Chart erstellen wollte und die Ergebnisse dieses Befehls sah und mir gedacht habe: "Das kann nicht richtig sein."

.:
total 8,0K
drwxr-xr-x. 2 kosmoz kosmoz   40  7. Dez 13:23 charts/
-rw-r--r--. 1 kosmoz kosmoz 1,2K  7. Dez 13:23 Chart.yaml
drwxr-xr-x. 3 kosmoz kosmoz  200  7. Dez 13:23 templates/
-rw-r--r--. 1 kosmoz kosmoz 1,9K  7. Dez 13:23 values.yaml

./charts:
total 0

./templates:
total 28K
-rw-r--r--. 1 kosmoz kosmoz 1,9K  7. Dez 13:23 deployment.yaml
-rw-r--r--. 1 kosmoz kosmoz 1,8K  7. Dez 13:23 _helpers.tpl
-rw-r--r--. 1 kosmoz kosmoz  925  7. Dez 13:23 hpa.yaml
-rw-r--r--. 1 kosmoz kosmoz 2,1K  7. Dez 13:23 ingress.yaml
-rw-r--r--. 1 kosmoz kosmoz 1,8K  7. Dez 13:23 NOTES.txt
-rw-r--r--. 1 kosmoz kosmoz  326  7. Dez 13:23 serviceaccount.yaml
-rw-r--r--. 1 kosmoz kosmoz  370  7. Dez 13:23 service.yaml
drwxr-xr-x. 2 kosmoz kosmoz   60  7. Dez 13:23 tests/

./templates/tests:
total 4,0K
-rw-r--r--. 1 kosmoz kosmoz 388  7. Dez 13:23 test-connection.yaml

Insgesamt erzeugt helm create 10 Dateien in verschiedenen Unterverzeichnissen und es ist nicht sofort ersichtlich, welche davon tatsächlich für ein Diagramm notwendig sind und welche nur Beispielcode sind. Ich habe mich darüber einmal bei einem DevOps-Ingenieur beschwert, der bereits Dutzende von Diagrammen erstellt hatte, und er hat nur gelacht und gesagt:

"Der erste Schritt bei der Erstellung eines Diagramms ist das Ausführen von helm create. Der zweite Schritt ist das Löschen von 90% der Ergebnisse."

Wirklich? Das ist das Beste, was wir tun können? Okay, nehmen wir an, du hast dir die Struktur deines neuen Diagramms ausgedacht. Jetzt möchtest du wahrscheinlich einige Ressourcen hinzufügen. Natürlich kannst du deine bestehenden YAML-Dateien einfach in das Verzeichnis templates des Diagramms legen, aber wahrscheinlich möchtest du einige Parameter aus deiner values.yaml in deinen Ressourcen verwenden. Schließlich ist das ja der Sinn und Zweck der Erstellung eines Helm-Charts. Für ein Beispiel schau dir die Datei templates/serviceaccount.yaml in deinem Terminal an (wo du zuvor dein helm chart erstellt hast):

{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ include "your-chart.serviceAccountName" . }}
  labels:
    {{- include "your-chart.labels" . | nindent 4 }}
  {{- with .Values.serviceAccount.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
{{- end }}

Ich weiß, was du jetzt denkst:

Das sieht nicht aus wie das YAML, das ich kenne! Was ist include, toYaml und nindent und was hat es mit dem ganzen - und {{ und | auf sich?

Es stimmt, obwohl Helm-Template-Files die file name extension für YAML verwenden, handelt es sich eigentlich nur um Templates. Helm-Templates basieren auf der Go-Template-Sprache, die zwar sehr flexibel und mächtig ist, sich aber nicht wirklich mit YAML oder Kubernetes auskennt. Deshalb ist es notwendig, viele dieser Konvertierungsfunktionen innerhalb der Template-Dateien aufzurufen.

Dies führt dazu, dass viele populäre Charts mit Template-Dateien enden, die mehr Template-Sprache als tatsächliches YAML enthalten. Das macht sie schwer lesbar und wartbar, insbesondere für jemanden, der nicht an der Erstellung beteiligt war.

4. Die Datei values.yaml ist ein Anti-Muster

Kommen wir nun zurück zu etwas, das für dich als Helm-Benutzer ein wenig greifbarer ist. Als Kubernetes-Anwendungsentwickler, der Ressourcen als YAML-Dateien schreibt, bist du wahrscheinlich daran gewöhnt, dass du in deiner Entwicklungsumgebung über umfangreichen Support verfügst, einschließlich strikter Schema-Validierung und super umfassender Autocomplete-Funktion. Das Erstellen einer "values.yaml"-Datei für ein Diagramm-Release ist ein wenig anders. Es gibt nämlich kein allgemeines Schema dafür, was in eine values.yaml-Datei gehört und was nicht. Dadurch kann deine Entwicklungsumgebung dir nicht über eine einfache YAML-Syntaxhervorhebung hinaus helfen. Die einzige Möglichkeit zu überprüfen, ob deine values.yaml-Datei gültig ist, ist sie durch Helm laufen zu lassen und zu sehen, was passiert. Die Verwendung von helm template ermöglicht es dir, diese Helm Templates zu rendern, um mögliche Fehler in der Konfigurationsdatei erkennen.

Viele Chart-Entwickler möchten den Benutzern die Möglichkeit geben, die meisten Aspekte der endgültigen Bereitstellung fein abzustimmen. Infolgedessen ist die Anzahl der Konfigurationsmöglichkeiten oft unangemessen groß und kompliziert und ahmt die tatsächlichen Ressourcen nach, die sie erstellen wollen, jedoch ohne jegliche Schema-Validierung!

5. Keine Interaktion mit der Kubernetes-API möglich

Wir haben bereits 4 Mängel von Helm besprochen, aber meiner Meinung nach ist dies der größte Nachteil von Helm: Ein Helm-Release ist nur eine einmalige Operation. Sobald ein Helm-Release erfolgreich installiert wurde, ist die Aufgabe von Helm erledigt. Aber hier ist das Problem: Die Installation einer Anwendung ist in der Regel nicht der schwierige Teil, sondern das maintainen einer Installation und die Aufrechterhaltung ihres Betriebs. Leider hilft dir Helm dabei nicht wirklich.

Nach Abschluss der Installation eines Releases kann Helm aufgrund seines Designs als rein clientseitige Anwendung keine weiteren Änderungen vornehmen. Diese Unfähigkeit, in späteren Phasen des Lebenszyklus eines Releases mit dem Release zu interagieren, bedeutet, dass Helm als Deploymentmethode von Natur aus statisch ist, moderne Software-Deployments aber oft sehr dynamisch sein müssen.

Ein einfaches Beispiel, das ein Operator tun kann, Helm aber nicht, wäre das dynamische Festlegen der Ingress-Klasse und der Annotations auf der Grundlage der erkannten Kubernetes-Umgebung:

Detecting the cloud environment:

private val dynamicCloudProvider
    get() = when {
        kubernetesClient.configMaps().inNamespace("kube-system").withName("shoot-info")
            .get()?.data?.get("extensions")?.contains("shoot-dns-service") == true ->
            CloudProvider.gardener

        kubernetesClient.nodes().withLabel("eks.amazonaws.com/nodegroup").list().items.isNotEmpty() ->
            CloudProvider.aws

        kubernetesClient.nodes().withLabel("csi.hetzner.cloud/location").list().items.isNotEmpty() ->
            CloudProvider.hcloud

        else ->
            CloudProvider.generic
    }

Applying configurations based on the environment:

protected val defaultIngressClassName: String?
    get() = when (configService.cloudProvider) {
        CloudProvider.aws -> "alb"
        else -> configService.ingressClassName
    }

protected fun getDefaultAnnotations(primary: P, context: Context

): Map = configService.getCommonIngressAnnotations(primary) + when (configService.cloudProvider) { CloudProvider.aws -> awsDefaultAnnotations CloudProvider.gardener -> gardenerDefaultAnnotations else -> getCertManagerDefaultAnnotations(context) + ingressNginxDefaultAnnotations

Fazit

Obwohl viele Entwickler anfangs etwas Angst vor Helm haben, hat sein einfaches Design Helm den Vorsprung verschafft, den es derzeit im Bereich der Deploymentmethoden von Kubernetes hat. Helm ist derzeit der De-facto-Standard für die Verwaltung komplexer Applikations-Deployments, aber das bedeutet nicht, dass wir sein Design nicht in Frage stellen und auf Schwächen hinweisen sollten. Neue Anforderungen an Anwendungen werden dynamischere Deploymentmethoden erfordern, und wir DevOps-Ingenieure und Anwendungsentwickler müssen darauf vorbereitet sein.

Aus diesem Grund haben wir Glasskube gegründet: Eine einfachere Möglichkeit, Anwendungen und Infrastruktur auf Kubernetes über unseren glasskube/glasskube zu deployen.

Wenn ihr unseren Fortschritt verfolgen wollt, vergesst nicht, glasskube/glasskube zu Staren und unserem Discord beizutreten.

Support Glasskube
By leaving us a Star on GitHub
Star us
Glasskube Newsletter

Sign-Up to get the latest product updates and release notes!

Unsere Lösungen für zuverlässige und skalierbare Infrastruktur

Skalieren Sie Ihre IT-Infrastruktur mühelos und betreiben Sie Ihre Anwendungen schnell und sicher mit unseren cloudbasierten Technologielösungen.

Testen Sie Glasskube kostenlos

Ihre Cloud Native Experten für zuverlässige IT-Infrastrukturlösungen und den automatisieren Betrieb von Open Source tools.