Kapitel 1. Einführung in Helm

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Helm ist der Paketmanager für Kubernetes. So haben die Helm-Entwickler Helm seit den allerersten Übertragungen in das Git-Repository beschrieben. Und dieser Satz ist das Thema dieses Kapitels.

In diesem Kapitel beginnen wir mit einem konzeptionellen Blick auf das Cloud Native Ecosystem, in dem Kubernetes eine Schlüsseltechnologie ist. Wir werfen einen neuen Blick darauf, was Kubernetes zu bieten hat, um die Voraussetzungen für die Beschreibung von Helm zu schaffen.

Als Nächstes werden wir uns die Probleme ansehen, die Helm lösen soll. In diesem Abschnitt gehen wir auf das Konzept der Paketverwaltung ein und erklären, warum wir Helm auf diese Weise modelliert haben. Außerdem werden wir uns einige der einzigartigen Aspekte der Installation von Paketen in einem Cluster-Management-Tool wie Kubernetes ansehen.

Zum Abschluss des Kapitels werfen wir einen Blick auf die Architektur von Helm und konzentrieren uns dabei auf die Konzepte von Diagrammen, Templates und Releases. Am Ende des Kapitels wirst du verstehen, wie Helm in das breitere Ökosystem der Werkzeuge passt, und du wirst mit der Terminologie und den Konzepten vertraut sein, die wir in diesem Buch verwenden werden.

Das Cloud Native Ökosystem

Das Aufkommen der Cloud-Technologien hat die Sichtweise der Branche auf Hardware, Systemmanagement, physische Netzwerke usw. deutlich verändert. Virtuelle Maschinen ersetzten physische Server, Speicherdienste verdrängten das Gerede von Festplatten und Automatisierungstools gewannen an Bedeutung. Dies war vielleicht eine frühe Veränderung in der Art und Weise, wie die Branche die Cloud konzeptualisiert hat. Doch als die Stärken und Schwächen dieses neuen Ansatzes immer deutlicher wurden, begann sich auch die Praxis der Entwicklung von Anwendungen und Diensten zu verändern.

Entwickler und Betreiber begannen, die Praxis der Erstellung großer, einbinärer Anwendungen, die auf leistungsfähiger Hardware ausgeführt wurden, in Frage zu stellen. Sie erkannten die Schwierigkeit, Daten zwischen verschiedenen Anwendungen zu teilen und dabei die Datenintegrität zu wahren. Verteiltes Sperren, Speichern und Zwischenspeichern wurden zu alltäglichen Problemen und nicht mehr nur von akademischem Interesse. Große Softwarepakete wurden in kleinere einzelne ausführbare Dateien zerlegt. Und, wie Kubernetes-Gründer Brendan Burns es oft ausdrückt: "Verteiltes Rechnen wurde von einem Thema für Fortgeschrittene zu einem Grundkurs in Informatik."

Der Begriff "Cloud Native" fasst diesen kognitiven Wandel in unserer architektonischen Sicht auf die Cloud zusammen. Wenn wir unsere Systeme um die Fähigkeiten und Einschränkungen der Cloud herum entwickeln, entwerfen wir Cloud-native Systeme.

Container und Microservices

Das Herzstück des Cloud Native Computing ist die philosophische Sichtweise, dass kleinere, eigenständige Dienste großen monolithischen Diensten, die alles erledigen, vorzuziehen sind. Anstatt eine einzige große Anwendung zu schreiben, die von der Erstellung der Benutzeroberfläche über die Verarbeitung von Aufgabenwarteschlangen bis hin zur Interaktion mit Datenbanken und Caches alles übernimmt, besteht der Cloud Native-Ansatz darin, eine Reihe kleinerer Dienste zu schreiben, von denen jeder einen relativ speziellen Zweck erfüllt, und diese Dienste dann miteinander zu verbinden, um einen übergeordneten Zweck zu erfüllen. In einem solchen Modell könnte ein Dienst der einzige Nutzer einer relationalen Datenbank sein. Dienste, die auf die Daten zugreifen wollen, kontaktieren diesen Dienst (normalerweise) über eine REST-API (Representational State Transfer). Mit Hilfe der JavaScript Object Notation (JSON) über HTTP können diese anderen Dienste die Daten abfragen und aktualisieren.

Diese Aufteilung ermöglicht es Entwicklern, die Low-Level-Implementierung auszublenden und stattdessen eine Reihe von Funktionen anzubieten, die für die Geschäftslogik der breiteren Anwendung spezifisch sind.

Microservices

Wo früher eine Anwendung aus einer einzigen ausführbaren Datei bestand, die die gesamte Arbeit erledigte, sind cloud-native Anwendungen verteilte Anwendungen. Während einzelne Programme jeweils die Verantwortung für eine oder zwei einzelne Aufgaben übernehmen, bilden diese Programme zusammen eine einzige logische Anwendung.

Nach all dieser Theorie kann ein einfaches Beispiel besser erklären, wie das funktioniert. Stell dir eine E-Commerce-Website vor. Wir können uns mehrere Aufgaben vorstellen, die zusammen eine solche Website ausmachen. Es gibt einen Produktkatalog, Benutzerkonten und Warenkörbe, einen Zahlungsprozessor, der die sicherheitsrelevanten Geldtransaktionen abwickelt, und ein Frontend, über das die Kunden die Artikel ansehen und ihre Einkäufe auswählen. Außerdem gibt es eine Verwaltungsoberfläche, über die die Ladenbesitzer/innen ihren Bestand verwalten und Bestellungen ausführen.

In der Vergangenheit wurden solche Anwendungen als ein einziges Programm erstellt. Der Code, der für jede dieser Arbeitseinheiten verantwortlich war, wurde zu einer großen ausführbaren Datei kompiliert, die dann oft auf einem einzigen großen Stück Hardware ausgeführt wurde.

Der cloud-native Ansatz für eine solche Anwendung besteht jedoch darin, die E-Commerce-Anwendung in mehrere Teile zu zerlegen. Ein Teil wickelt den Zahlungsverkehr ab. Eine andere verwaltet den Produktkatalog. Ein anderer sorgt für die Verwaltung und so weiter. Diese Dienste kommunizieren dann über das Netzwerk mithilfe gut definierter REST-APIs miteinander.

Auf die Spitze getrieben, wird eine Anwendung in ihre kleinsten Bestandteile zerlegt, und jeder Teil ist ein Programm. Das ist die Microservice-Architektur. Im Gegensatz zu einer monolithischen Anwendung ist ein Microservice nur für einen kleinen Teil der Gesamtanwendung zuständig.

Das Microservice-Konzept hat einen großen Einfluss auf die Entwicklung des Cloud Native Computing ausgeübt. Und nirgendwo wird dies deutlicher als beim Aufkommen des Container-Computing.

Container

Es ist üblich, einen Container mit einer virtuellen Maschine zu vergleichen. Auf einer virtuellen Maschine wird ein komplettes Betriebssystem in einer isolierten Umgebung auf einem Host-Rechner ausgeführt. Ein Container hingegen hat sein eigenes Dateisystem, wird aber im selben Betriebssystemkern wie der Host ausgeführt.

Es gibt jedoch noch eine zweite Möglichkeit, sich den Container vorzustellen - eine, die sich für die vorliegende Diskussion als nützlicher erweisen könnte. Wie der Name schon sagt, bietet ein Container eine nützliche Möglichkeit, die Laufzeitumgebung für ein einzelnes Programm so zu verpacken, dass die ausführbare Datei garantiert alle ihre Abhängigkeiten erfüllt, wenn sie von einem Rechner auf einen anderen verschoben wird.

Das ist vielleicht ein eher philosophischer Ansatz, weil er einem Container einige nicht-technische Einschränkungen auferlegt. Man könnte zum Beispiel ein Dutzend verschiedener Programme in einen einzigen Container packen und sie alle gleichzeitig ausführen. Aber Container, zumindest in der Form, wie sie von Docker entwickelt wurden, sind als Vehikel für ein einziges übergeordnetes Programm gedacht.

Hinweis

Wenn wir hier von Programmen sprechen, denken wir wirklich auf einer höheren Abstraktionsebene als "eine Binärdatei". Die meisten Docker-Container haben mindestens ein paar ausführbare Dateien, die das Hauptprogramm unterstützen sollen. Aber diese ausführbaren Dateien sind Hilfsmittel für die Hauptfunktion des Containers. Ein Webserver kann zum Beispiel ein paar andere lokale Dienstprogramme zum Starten oder zur Ausführung von Low-Level-Aufgaben benötigen (Apache hat zum Beispiel Tools für Module), aber der Webserver selbst ist das Hauptprogramm.

Container und Microservices passen vom Design her perfekt zusammen. Kleine, eigenständige Programme können zusammen mit all ihren Abhängigkeiten in schlanke Container verpackt werden. Und diese Container können von Host zu Host verschoben werden. Bei der Ausführung eines Containers muss der Host nicht über alle Werkzeuge verfügen, die für die Ausführung des Programms erforderlich sind, da alle diese Werkzeuge im Container verpackt sind. Der Host muss lediglich über die Fähigkeit verfügen, Container auszuführen.

Wenn zum Beispiel ein Programm in Python 3 erstellt wird, muss der Host nicht erst Python installieren, konfigurieren und dann alle Bibliotheken installieren, die das Programm benötigt. All das ist in dem Container enthalten. Wenn der Host den Container ausführt, sind die richtige Version von Python 3 und alle benötigten Bibliotheken bereits im Container gespeichert.

Um noch einen Schritt weiter zu gehen, kann ein Host Container mit konkurrierenden Anforderungen frei ausführen. Ein containerisiertes Python-2-Programm kann auf demselben Host laufen wie eine containerisierte Python-3-Anforderung, und die Administratoren des Hosts müssen keine besonderen Maßnahmen ergreifen, um diese konkurrierenden Anforderungen zu konfigurieren!

Diese Beispiele verdeutlichen eines der Merkmale des Cloud Native Ecosystems: Administratoren, Betreiber und Site Reliability Engineers (SREs) müssen sich nicht mehr um die Verwaltung von Programmabhängigkeiten kümmern. Stattdessen können sie sich auf eine höhere Ebene der Ressourcenzuweisung konzentrieren. Anstatt sich darüber aufzuregen, welche Versionen von Python, Ruby und Node auf verschiedenen Servern laufen, können sich die Betreiber darauf konzentrieren, ob die Netzwerk-, Speicher- und CPU-Ressourcen für diese containerisierten Workloads richtig zugewiesen sind.

Manchmal ist es sinnvoll, ein Programm in völliger Isolation laufen zu lassen. Aber häufiger wollen wir einige Aspekte dieses Containers der Außenwelt preisgeben. Wir wollen ihm Zugriff auf die Speicherung geben. Wir wollen ihm erlauben, auf Netzwerkverbindungen zu antworten. Und wir wollen dem Container je nach unseren aktuellen Bedürfnissen kleine Konfigurationsschritte zuweisen. All diese Aufgaben (und noch mehr) werden von der Container-Laufzeitumgebung übernommen. Wenn ein Container deklariert, dass er einen Dienst hat, der intern auf Port 8080 lauscht, kann die Container-Laufzeit dem Dienst Zugriff auf den Host-Port 8000 gewähren. Wenn der Host also eine Netzwerkanforderung auf Port 8000 erhält, sieht der Container dies als eine Anforderung auf seinem Port 8080. Ebenso kann ein Host ein Dateisystem in den Container einhängen oder bestimmte Umgebungsvariablen innerhalb des Containers setzen. Auf diese Weise kann ein Container an seiner weiteren Umgebung teilhaben - nicht nur an anderen Containern auf dem Rechner, sondern auch an anderen Diensten im lokalen Netzwerk oder sogar im Internet.

Container-Images und Registrierungen

Die Containertechnologie ist ein hochentwickeltes und faszinierendes Gebiet für sich. Aber für unsere Zwecke müssen wir nur noch ein paar Dinge über die Funktionsweise von Containern verstehen, bevor wir zur nächsten Schicht des Cloud Native Stacks übergehen können.

Wie wir im vorigen Abschnitt besprochen haben, ist ein Container ein Programm mit seinen Abhängigkeiten und seiner Umgebung. Das Ganze kann in eine portable Darstellung verpackt werden, die als Container-Image (oft auch nur als Image bezeichnet) bezeichnet wird. Images werden nicht in eine große Binärdatei verpackt, sondern in einzelne Schichten, von denen jede ihre eigene eindeutige Kennung hat. Wenn Bilder verschoben werden, werden sie als eine Sammlung von Schichten verschoben, was einen großen Vorteil darstellt. Wenn ein Rechner ein Bild mit fünf Ebenen hat und ein anderer Rechner das gleiche Bild braucht, muss er nur die Ebenen holen, die er noch nicht hat. Wenn er also bereits zwei der fünf Ebenen hat, muss er nur drei Ebenen abrufen, um den gesamten Container neu zu erstellen.

Es gibt eine wichtige Technologie, die es ermöglicht, Container-Images zu verschieben. Eine Container-Image-Registry ist eine spezielle Speicherungstechnologie, die Container beherbergt und sie für Hosts verfügbar macht. Ein Host kann ein Container-Image an eine Registry senden, die die Ebenen in die Registry überträgt. Dann kann ein anderer Host das Container-Image aus der Registry in seine Umgebung ziehen und den Container ausführen.

Die Registry verwaltet die Ebenen. Wenn ein Anbieter ein Bild anfordert, teilt die Registry dem Anbieter mit, aus welchen Ebenen das Bild besteht. Der Host kann dann feststellen, welche Ebenen (wenn überhaupt) fehlen, und nur diese Ebenen aus derRegistry herunterladen.

Eine Registry verwendet bis zu drei Informationen, um ein bestimmtes Bild zu identifizieren:

Name

Ein Bildname kann von einfach bis komplex reichen, je nach der Registry, in der das Bild gespeichert ist: nginx, servers/nginx oder example.com/servers/nginx.

Tag

Das Tag bezieht sich in der Regel auf die Version der installierten Software (v1.2.3), obwohl Tags eigentlich nur beliebige Zeichenfolgen sind. Die Tags latest und stable werden häufig verwendet, um "die neueste Version" bzw. "die neueste produktionsbereite Version" zu kennzeichnen.

Auszug

Manchmal ist es wichtig, eine ganz bestimmte Version eines Bildes zu finden. Da Tags veränderbar sind, gibt es keine Garantie dafür, dass sich ein Tag zu einem bestimmten Zeitpunkt auf genau eine bestimmte Version der Software bezieht. Deshalb unterstützen die Registraturen das Abrufen von Bildern anhand eines SHA-256- oder SHA-512-Digests der Layer-Informationen des Bildes.

In diesem Buch werden wir immer wieder Bilder sehen, auf die mit den drei vorangegangenen Informationen verwiesen wird. Das kanonische Format für die Kombination dieser Angaben ist name:tag@digest, wobei nur name erforderlich ist. So sagt example.com/servers/nginx:latest: "Gib mir den Tag latest für das Bild mit dem Namen example.com/servers/nginx." Und

example.com/my/app@sha256:
a428de44a9059feee59237a5881c2d2cffa93757d99026156e4ea544577ab7f3

sagt: "Gib mir example.com/my/app mit der genauen Zusammenfassung, die hier angegeben ist."

Obwohl es noch viel mehr über Images und Container zu lernen gibt, haben wir jetzt genug Wissen, um zum nächsten wichtigen Thema überzugehen: Zeitplanungsprogramme. Und in diesem Abschnitt werden wir Kubernetes entdecken.

Zeitpläne und Kubernetes

Im vorigen Abschnitt haben wir gesehen, wie Container einzelne Programme und ihre erforderliche Umgebung kapseln. Container können lokal auf Workstations oder remote auf Servern ausgeführt werden.

Als die Entwickler begannen, ihre Anwendungen in Containern zu verpacken, und die Betreiber begannen, Container als Artefakt für die Bereitstellung zu nutzen, tauchten neue Fragen auf. Wie können wir am besten viele Container ausführen? Wie können wir eine Microservice-Architektur, in der viele Container zusammenarbeiten müssen, am besten unterstützen? Wie können wir den Zugriff auf Dinge wie Network Attached Storage, Load Balancer und Gateways sinnvoll verteilen? Wie schaffen wir es, Konfigurationsinformationen in viele Container zu injizieren? Und was vielleicht am wichtigsten ist: Wie verwalten wir Ressourcen wie Speicher, CPU, Netzwerkbandbreite und Speicherung?

Noch eine Stufe darüber hinaus fragten sich die Leute (basierend auf ihren Erfahrungen mit virtuellen Maschinen), wie man Container auf mehrere Hosts verteilen kann, um die Last gleichmäßig zu verteilen und gleichzeitig die Ressourcen sinnvoll zu nutzen? Oder noch einfacher: Wie können wir so wenig Hosts wie möglich betreiben und gleichzeitig so viele Container wie nötig?

Im Jahr 2015 war die Zeit reif: Docker-Container waren auf dem Vormarsch in die Unternehmen. Und es bestand ein klarer Bedarf an einem Tool, das die Planung von Containern und das Ressourcenmanagement auf verschiedenen Hosts verwalten konnte. Mehrere Technologien traten auf den Plan: Mesos führte Marathon ein, Docker schuf Swarm, Hashicorp veröffentlichte Nomad und Google schuf einen Open-Source-Ableger seiner internen Borg-Plattform und nannte diese Technologie Kubernetes (das griechische Wort für den Kapitän eines Schiffs).

In all diesen Projekten wurde ein geclustertes Containermanagementsystem implementiert, mit dem Container geplant und verdrahtet werden können, um anspruchsvolle verteilte Microservice-ähnliche Anwendungen zu hosten.

Jedes dieser Zeitplannungsprogramme hatte Stärken und Schwächen. Doch Kubernetes führte zwei Konzepte ein, die es von der Masse abhoben: die deklarative Infrastruktur und die Reconciliation Loop.

Deklarative Infrastruktur

Nehmen wir den Fall der Bereitstellung eines Containers. Man könnte den Prozess der Bereitstellung eines Containers wie folgt angehen: Ich erstelle den Container. Ich öffne einen Port, auf dem er lauschen soll, und hänge dann eine Speicherung an diesem bestimmten Ort im Dateisystem an. Dann warte ich darauf, dass alles initialisiert wird. Dann teste ich, ob der Container bereit ist. Dann markiere ich ihn als verfügbar.

Bei diesem Ansatz denken wir prozedural, indem wir uns auf den Prozess der Einrichtung eines Containers konzentrieren. Das Konzept von Kubernetes sieht jedoch vor, dass wir deklarativ denken. Wir teilen dem Zeitplannungsprogramm (Kubernetes) mit, wie unser gewünschter Zustand aussehen soll, und Kubernetes wandelt diese deklarative Aussage in seine eigenen internen Verfahren um.

Bei der Installation eines Containers in Kubernetes geht es also eher darum, zu sagen: "Ich möchte, dass dieser Container auf diesem Port mit dieser Menge an CPU und einer bestimmten Speicherung an diesem Ort im Dateisystem läuft." Kubernetes arbeitet hinter den Kulissen, um alles so zu verkabeln, wie wir es uns vorgestellt haben.

Die Versöhnungsschleife

Wie funktioniert Kubernetes hinter den Kulissen, um all das zu tun? Als wir die Dinge prozedural betrachteten, gab es dort eine bestimmte Reihenfolge der Vorgänge. Woher weiß Kubernetes die Reihenfolge? An dieser Stelle kommt die Idee der Versöhnungsschleife ins Spiel.

In einer Abstimmungsschleife sagt das Zeitplannungsprogramm: "Hier ist der vom Benutzer gewünschte Zustand. Hier ist der aktuelle Zustand. Sie sind nicht identisch, also werde ich Schritte unternehmen, um sie abzugleichen." Der Benutzer möchte eine Speicherung für den Container. Derzeit ist keine Speicherung vorhanden. Also erstellt Kubernetes eine Einheit der Speicherung und fügt sie dem Container zu. Der Container braucht eine öffentliche Netzwerkadresse. Es gibt keine. Also wird eine neue Adresse an den Container angehängt. Die verschiedenen Subsysteme von Kubernetes arbeiten daran, ihren Teil des vom Nutzer deklarierten gewünschten Zustands zu erfüllen.

Letztendlich schafft es Kubernetes entweder, die vom Nutzer gewünschte Umgebung zu schaffen, oder es kommt zu dem Schluss, dass es die Wünsche des Nutzers nicht erfüllen kann. In der Zwischenzeit nimmt der Nutzer eine passive Rolle ein, indem er den Kubernetes-Cluster beobachtet und darauf wartet, dass er erfolgreich ist oder die Installation als fehlgeschlagen markiert.

Von Containern bis hin zu Pods, Services, Deployments usw.

Das vorangegangene Beispiel ist zwar prägnant, aber ein wenig irreführend. Kubernetes betrachtet den Container nicht unbedingt als Arbeitseinheit. Stattdessen führt Kubernetes eine höhere Abstraktionsebene ein, die Pods genannt wird. Ein Pod ist eine abstrakte Hülle, die eine eigenständige Arbeitseinheit beschreibt. Ein Pod beschreibt nicht nur einen Container, sondern einen oder mehrere Container (sowie deren Konfiguration und Anforderungen), die zusammen eine Arbeitseinheit ausführen:

apiVersion: v1 1
kind: Pod
metadata:
    name: example-pod
spec:
    containers: 2
    - image: "nginx:latest"
      name: example-nginx
1

Die ersten beiden Zeilen definieren die Kubernetes-Art (v1 Pod).

2

Ein Pod kann einen oder mehrere Container enthalten.

Meistens besteht ein Pod nur aus einem Container. Manchmal haben sie aber auch Container, die den Hauptcontainer vorbereiten und ihn verlassen, bevor er online geht. Diese werden Init-Container genannt. In anderen Fällen gibt es Container, die neben dem Hauptcontainer laufen und zusätzliche Dienste bereitstellen. Diese werden Sidecar-Container genannt. Sie werden alle als Teil desselben Pods betrachtet.

Hinweis

Im vorangegangenen Code haben wir eine Definition für eine Kubernetes Pod Ressource geschrieben. Diese Definitionen werden als YAML oder JSON ausgedrückt und als Manifeste bezeichnet. Ein Manifest kann eine oder mehrere Kubernetes-Ressourcen (auch Objekte oder Ressourcendefinitionen genannt) enthalten. Jede Ressource ist mit einem der Kubernetes-Typen verknüpft, z. B. Pod oderDeployment. In diesem Buch verwenden wir typischerweise Ressource, weil das Wort Objekt überladen ist: YAML definiert das Wort Objekt für eine benannte Schlüssel/Wert-Struktur.

Eine Pod beschreibt, welche Konfiguration der oder die Container benötigen (z.B. Netzwerkports oder Dateisystem-Einhängepunkte). Konfigurationsinformationen in Kubernetes können in ConfigMaps oder, für sensible Informationen, in Secrets gespeichert werden. Die Definition von Podkann diese ConfigMapund Secretmit Umgebungsvariablen oder Dateien in jedem Container in Beziehung setzen. Wenn Kubernetes diese Beziehungen erkennt, versucht es, die Konfigurationsdaten so anzuhängen und zu konfigurieren, wie in der Pod Definition beschrieben:

apiVersion: v1 1
kind: ConfigMap
metadata:
    name: configuration-data
data: 2
    backgroundColor: blue
    title: Learning Helm
1

In diesem Fall haben wir ein v1 ConfigMap Objekt deklariert.

2

Innerhalb von data deklarieren wir einige beliebige Name/Wert-Paare.

Eine Secret ist strukturell ähnlich aufgebaut wie eine ConfigMap, mit dem Unterschied, dass die Werte im data Abschnitt Base64 kodiert sein müssen.

Pods sind mit Konfigurationsobjekten (wie ConfigMap oder Secret) über Bände verbunden. In diesem Beispiel nehmen wir das vorherige Pod Beispiel und fügen das Secret oben an:

apiVersion: v1
kind: Pod
metadata:
    name: example-pod
spec:
    volumes: 1
    - name: my-configuration
      configMap:
        name: configuration-data 2
    containers:
    - image: "nginx:latest"
      name: example-nginx
      env: 3
        - name: BACKGROUND_COLOR 4
          valueFrom:
            configMapKeyRef:
                name: configuration-data 5
                key: backgroundColor 6
1

Der Abschnitt volumes teilt Kubernetes mit, welche Speicherquellen dieser Pod benötigt.

2

Der Name configuration-data ist der Name unseres ConfigMap, den wir im vorherigen Beispiel erstellt haben.

3

Der Abschnitt env fügt Umgebungsvariablen in den Container ein.

4

Die Umgebungsvariable wird innerhalb desContainers BACKGROUND_COLOR genannt.

5

Dies ist der Name der ConfigMap, die verwendet werden soll. Diese Map muss in volumes sein, wenn wir sie als Dateisystem-Volume verwenden wollen.

6

Dies ist der Name des Schlüssels im data Abschnitt der ConfigMap.

Ein Pod ist die "primitive" Beschreibung einer lauffähigen Arbeitseinheit mit Containern als Teil dieses Pods. Aber Kubernetes führt Konzepte höherer Ordnung ein.

Nehmen wir eine Webanwendung. Wir wollen vielleicht nicht nur eine Instanz dieser Webanwendung laufen lassen. Wenn wir nur eine laufen lassen würden und diese fehlschlägt, würde unsere Website zusammenbrechen. Und wenn wir sie aktualisieren wollten, müssten wir herausfinden, wie wir das tun können, ohne die gesamte Website lahmzulegen. Deshalb hat Kubernetes das Konzept des Deployments eingeführt. Ein Deployment beschreibt eine Anwendung als eine Sammlung von identischen Pods. Die Deployment besteht aus einigen Top-Level-Konfigurationsdaten sowie einer Vorlage, wie ein Replikat-Pod zu erstellen ist.

Mit einer Deployment können wir Kubernetes anweisen, unsere App mit einem einzigen Pod zu erstellen. Dann können wir sie auf bis zu fünf Pods skalieren. Und wieder zurück auf drei. Wir können einen HorizontalPodAutoscaler (ein weiterer Kubernetes-Typ) anhängen und ihn so konfigurieren, dass er unseren Pod je nach Ressourcenverbrauch skaliert. Und wenn wir die Anwendung aktualisieren, kann Deployment verschiedene Strategien anwenden, um einzelne Pods schrittweise zu aktualisieren, ohne unsere gesamte Anwendung herunterzufahren:

apiVersion: apps/v1 1
kind: Deployment
metadata:
    name: example-deployment
    labels:
        app: my-deployment
spec:
    replicas: 3 2
    selector:
        matchLabels:
            app: my-deployment
    template: 3
        metadata:
            labels:
                app: my-deployment
        spec:
            containers:
            - image: "nginx:latest"
              name: example-nginx
1

Dies ist ein apps/v1 Deployment Objekt.

2

In der Spezifikation fragen wir nach drei Replikaten der folgenden template.

3

Die Vorlage legt fest, wie jeder Replikat Pod aussehen soll.

Wenn es darum geht, eine Kubernetes-Anwendung mit anderen Dingen im Netzwerk zu verbinden, bietet Kubernetes Service-Definitionen. Ein Service ist eine dauerhafte Netzwerkressource (ähnlich wie eine statische IP), die auch dann bestehen bleibt, wenn der Pod oder die Pods, die mit ihr verbunden sind, verschwinden. Auf diese Weise können Kubernetes Pods kommen und gehen, während die Netzwerkschicht den Datenverkehr weiterhin an denselben Service Endpunkt weiterleiten kann. Während Service ein abstraktes Kubernetes-Konzept ist, kann es hinter den Kulissen in Form einer Routing-Regel oder eines externen Load Balancers implementiert werden:

apiVersion: v1 1
kind: Service
metadata:
  name: example-service
spec:
  selector:
    app: my-deployment 2
  ports:
    - protocol: TCP 3
      port: 80
      targetPort: 8080
1

Die Art ist v1 Service.

2

Diese Service leitet zu Pods mit dem Label app: my-deployment weiter.

3

Der TCP-Verkehr zum Port 80 dieser Service wird an den Port 8080 auf den Pods weitergeleitet, die dem Label app: my-deployment entsprechen.

Die beschriebene Service leitet den Verkehr an die Deployment weiter, die wir zuvor erstellt haben.

Wir haben ein paar der vielen Kubernetes-Typen vorgestellt. Es gibt noch Dutzende weitere, die wir behandeln könnten, aber die mit Abstand am häufigsten verwendeten sind Pod, Deployment, ConfigMap, Secret und Service. Im nächsten Kapitel werden wir mit diesen Konzepten direkt arbeiten. Aber jetzt, mit einigen allgemeinen Informationen ausgestattet, können wir Helm vorstellen.

Helm's Ziele

Bis zu diesem Punkt haben wir uns auf das breitere Cloud-Native-Ökosystem und die Rolle von Kubernetes innerhalb dieses Ökosystems konzentriert. In diesem Abschnitt werden wir den Fokus auf Helm richten.

Im vorherigen Abschnitt haben wir verschiedene Kubernetes-Ressourcen kennengelernt: A Pod, aConfigMap, eine Deployment und eine Service. Jede dieser Ressourcen erfüllt eine bestimmte Aufgabe. Eine Anwendung benötigt jedoch in der Regel mehr als eine dieser Ressourcen.

Das CMS-System WordPress kann zum Beispiel innerhalb von Kubernetes betrieben werden. Normalerweise bräuchte es aber mindestens ein Deployment (für den WordPress-Server), ein ConfigMap für die Konfiguration und wahrscheinlich ein Secret (um Passwörter aufzubewahren), ein paar Service Objekte, ein StatefulSet, auf dem eine Datenbank läuft, und ein paar rollenbasierte Zugriffskontrollregeln (RBAC). Schon eine Kubernetes-Beschreibung einer einfachen WordPress-Site würde Tausende von YAML-Zeilen umfassen. Das Herzstück von Helm ist die Idee, dass all diese Objekte in Pakete gepackt werden können, um gemeinsam installiert, aktualisiert und gelöscht zu werden.

Als wir Helm schrieben, hatten wir drei Hauptziele:

  1. Einfacher Einstieg von "Null auf Kubernetes"

  2. Ein Paketverwaltungssystem bereitstellen, wie es Betriebssysteme haben

  3. Schwerpunkt auf Sicherheit und Konfigurierbarkeit für die Bereitstellung von Anwendungen in Kubernetes

Wir werden uns jedes dieser drei Ziele ansehen und dann einen weiteren Aspekt der Nutzung von Helm betrachten: die Beteiligung an der Lebenszyklusmanagement-Story.

Von Null auf Kubernetes

Das Helm-Projekt begann 2015, ein paar Monate vor der ersten KubeCon. Kubernetes war schwierig einzurichten. Oft mussten neue Nutzer den Kubernetes-Quellcode kompilieren und dann einige Shell-Skripte verwenden, um Kubernetes zum Laufen zu bringen. Und wenn der Cluster erst einmal in Betrieb war, mussten neue Nutzer YAML (wie wir es in den vorherigen Abschnitten getan haben) von Grund auf neu schreiben. Es gab nur wenige grundlegende Beispiele und keine produktionsreifen Beispiele.

Wir wollten den Lernzyklus umkehren: Anstatt von den Nutzern zu verlangen, dass sie mit grundlegenden Beispielen beginnen und versuchen, ihre eigenen Anwendungen zu erstellen, wollten wir den Nutzern fertige, produktionsreife Beispiele zur Verfügung stellen. Die Nutzer können diese Beispiele installieren, sie in Aktion sehen und dann lernen, wie Kubernetes funktioniert.

Das war und ist auch heute noch unsere erste Priorität bei Helm: den Einstieg in Kubernetes zu erleichtern. Unserer Meinung nach sollte ein neuer Helm-Nutzer mit einem bestehenden Kubernetes-Cluster in der Lage sein, in fünf Minuten oder weniger vom Download zu einer installierten Anwendung zu gelangen.

Aber Helm ist nicht nur ein Lernwerkzeug. Es ist ein Paketmanager.

Paket Management

Kubernetes ist wie ein Betriebssystem. Ein Betriebssystem stellt eine Umgebung für die Ausführung von Programmen zur Verfügung. Es stellt die notwendigen Werkzeuge bereit, um den Lebenszyklus eines Programms zu speichern, auszuführen und zu überwachen.

Anstatt Programme auszuführen, führt es Container aus. Ähnlich wie ein Betriebssystem stellt es aber die nötigen Werkzeuge zur Verfügung, um diese Container zu speichern, auszuführen und zu überwachen.

Die meisten Betriebssysteme werden von einem Paketmanager unterstützt. Die Aufgabe des Paketmanagers ist es, das Auffinden, Installieren, Aktualisieren und Löschen von Programmen auf einem Betriebssystem zu erleichtern. Paketmanager stellen eine Semantik für die Bündelung von Programmen zu installierbaren Anwendungen bereit und bieten ein Schema zum Speichern und Abrufen von Paketen sowie zum Installieren und Verwalten.

Als wir uns Kubernetes als Betriebssystem vorstellten, erkannten wir schnell den Bedarf an einem Kubernetes-Paketmanager. Von der ersten Übergabe an das Helm-Quellcode-Repository an haben wir die Metapher der Paketverwaltung konsequent auf Helm angewendet:

  • Helm bietet Paket-Repositories und Suchfunktionen, um herauszufinden, welche Kubernetes-Anwendungen verfügbar sind.

  • Helm verfügt über die bekannten Befehle zum Installieren, Aktualisieren und Löschen.

  • Helm definiert eine Methode zur Konfiguration von Paketen, bevor sie installiert werden.

  • Außerdem hat Helm Werkzeuge, mit denen du sehen kannst, was bereits installiert ist und wie es konfiguriert ist.

Ursprünglich haben wir Helm nach dem Vorbild von Homebrew (einem Paketmanager für macOS) und Apt (dem Paketmanager für Debian) entwickelt. Aber während Helm gereift ist, haben wir versucht, von so vielen verschiedenen Paketmanagern zu lernen, wie wir können.

Es gibt einige Unterschiede zwischen typischen Betriebssystemen und Kubernetes. Einer davon ist, dass Kubernetes den Betrieb vieler Instanzen derselben Anwendung unterstützt. Während ich die Datenbank MariaDB vielleicht nur einmal auf meinem Arbeitsplatzrechner installiere, können in einem Kubernetes-Cluster Dutzende, Hunderte oder sogar Tausende vonMariaDB-Installationen laufen - jedemit einer anderen Konfiguration oder sogar einer anderen Version.

Ein weiterer Begriff, der in typischen Betriebssystemen selten vorkommt, aber für Kubernetes von zentraler Bedeutung ist, ist die Idee des Namensraums. In Kubernetes ist ein Namensraum ein beliebiger Gruppierungsmechanismus, der eine Grenze zwischen den Dingen innerhalb und denen außerhalb des Namensraums definiert. Es gibt viele verschiedene Möglichkeiten, Ressourcen mit Namensräumen zu organisieren, aber oft werden sie als fester Bestandteil verwendet, an den Sicherheit geknüpft ist. Zum Beispiel können nur bestimmte Benutzer auf Ressourcen innerhalb eines Namensraums zugreifen.

Dies sind nur einige der Unterschiede zwischen Kubernetes und traditionellen Betriebssystemen. Diese und andere Unterschiede haben uns bei der Entwicklung von Helm vor Herausforderungen gestellt. Wir mussten Helm so entwickeln, dass es die Vorteile dieser Unterschiede nutzt, ohne dabei unsere Paketmanagement-Metapher aufzugeben.

Der Helm-Installationsbefehl erfordert zum Beispiel nicht nur den Namen des Pakets, sondern auch einen vom Benutzer eingegebenen Namen, mit dem die installierte Version des Pakets referenziert werden soll. Im nächsten Kapitel werden wir Beispiele dafür sehen.

Auch die Vorgänge in Helm sind Namensräume-abhängig. Man kann dieselbe Anwendung in zwei verschiedenen Namensräumen installieren, und Helm bietet Werkzeuge, um diese verschiedenen Instanzen der Anwendung zu verwalten.

Letztendlich bleibt Helm aber fest in der Klasse der Paketmanagement-Tools.

Sicherheit, Wiederverwendbarkeit und Konfigurierbarkeit

Unser drittes Ziel mit Helm war es, uns auf drei "Must Haves" für die Verwaltung von Anwendungen in einem Cluster zu konzentrieren:

  1. Sicherheit

  2. Wiederverwendbarkeit

  3. Konfigurierbarkeit

Kurz gesagt, wir wollten Helm so weit mit diesen Prinzipien vertraut machen, dass Helm-Nutzer Vertrauen in die Pakete haben können, die sie verwenden. Ein Nutzer sollte sich vergewissern können, dass ein Paket aus einer vertrauenswürdigen Quelle stammt (und nicht manipuliert wurde), dass er dasselbe Paket mehrfach wiederverwenden und das Paket nach seinen Bedürfnissen konfigurieren kann.

Während die Entwickler von Helm direkten Einfluss auf die beiden vorherigen Designziele haben, ist dieses Ziel einzigartig: Helm kann den Paketautoren nur die richtigen Werkzeuge zur Verfügung stellen und hoffen, dass diese sich für die Umsetzung dieser drei "Must Haves" entscheiden.

Sicherheit

Sicherheit ist eine weit gefasste Kategorie. In diesem Zusammenhang beziehen wir uns jedoch auf die Idee, dass ein Nutzer, wenn er ein Paket untersucht, die Möglichkeit hat, bestimmte Dinge über das Paket zu überprüfen:

  • Das Paket kommt aus einer vertrauenswürdigen Quelle.

  • Die Netzwerkverbindung, über die das Paket gezogen wird, ist gesichert.

  • Das Paket wurde nicht manipuliert.

  • Das Paket kann leicht inspiziert werden, damit der Nutzer sehen kann, was es tut.

  • Der Nutzer kann sehen, welche Konfiguration das Paket hat und wie sich verschiedene Eingaben auf die Ausgabe eines Pakets auswirken.

Im Laufe dieses Buches und vor allem in Kapitel 6 werden wir uns ausführlicher mit dem Thema Sicherheit beschäftigen. Aber diese fünf Fähigkeiten sind Dinge, von denen wir glauben, dass wir sie mit Helm bereitgestellt haben.

Helm bietet eine Herkunftsfunktion, um die Herkunft, den Autor und die Integrität eines Pakets zu überprüfen. Helm unterstützt Secure Sockets Layer/Transport Layer Security (SSL/TLS), um Daten sicher über das Netzwerk zu übertragen. Helm bietet außerdem Befehle für Trockenübungen, Templating und Linting, um Pakete und ihre möglichenKombinationen zu untersuchen.

Wiederverwendbarkeit

Eine Tugend der Paketverwaltung ist die Fähigkeit, dasselbe wiederholt und vorhersehbar zu installieren. Mit Helm wird diese Idee noch etwas erweitert: Wir wollen vielleicht sogar dasselbe (wiederholt und vorhersehbar) in denselben Cluster oder sogar in denselben Namensraum eines Clusters installieren.

Helm-Charts sind der Schlüssel zur Wiederverwendbarkeit. Ein Diagramm bietet ein Muster für die Erstellung der gleichen Kubernetes-Manifeste. Diagramme ermöglichen es den Nutzern aber auch, zusätzliche Konfigurationen bereitzustellen (über die wir im nächsten Kapitel sprechen werden). Helm bietet also Muster für die Speicherung von Konfigurationen, so dass die Kombination aus einem Diagramm und seiner Konfiguration sogar wiederholt werden kann.

Auf diese Weise ermutigt Helm Kubernetes-Nutzer, ihre YAML in Diagramme zu verpacken, damit diese Beschreibungen wiederverwendet werden können.

In der Linux-Welt hat jede Linux-Distribution ihren eigenen Paketmanager und Repositories. Das ist in der Kubernetes-Welt nicht der Fall. Helm wurde so entwickelt, dass alle Kubernetes-Distributionen denselben Paketmanager und (mit sehr, sehr wenigen Ausnahmen) auch dieselben Pakete nutzen können. Wenn es Unterschiede zwischen zwei verschiedenen Kubernetes-Distributionen gibt, können Charts diese mit Hilfe von Templates (die in Kapitel 5 genauer erläutert werden) in Verbindung mit der Konfiguration ausgleichen.

Konfigurierbarkeit

Helm bietet Muster für die Übernahme eines Helm-Diagramms und die Bereitstellung einer zusätzlichen Konfiguration. Ich könnte zum Beispiel eine Website mit Helm installieren, möchte aber (zur Installationszeit) den Namen dieser Website festlegen. Helm bietet Werkzeuge, um Pakete bei der Installation zu konfigurieren und um Installationen bei Upgrades neu zu konfigurieren. Aber ein Wort der Warnung ist angebracht.

Helm ist ein Paketmanager. Eine andere Klasse von Software befasst sich mit dem Konfigurationsmanagement. Diese Softwareklasse, die von Puppet, Ansible und Chef verkörpert wird, konzentriert sich darauf, wie eine bestimmte Software (oft in Paketen) speziell für die Hostumgebung konfiguriert wird. Ihre Aufgabe ist es, Konfigurationsänderungen im Laufe der Zeit zu verwalten.

Helm wurde nicht als Konfigurationsmanagement-Tool entwickelt, obwohl es zumindest einige Überschneidungen zwischen Paketmanagement und Konfigurationsmanagement gibt.

Die Paketverwaltung beschränkt sich in der Regel auf die Implementierung von drei Verben: install, upgrade und delete. Das Konfigurationsmanagement ist ein übergeordnetes Konzept, das sich auf die Verwaltung einer Anwendung oder mehrerer Anwendungen im Laufe der Zeit konzentriert. Dies wird manchmal auch als "day-two ops" bezeichnet.

Obwohl Helm nicht als Konfigurationsmanagement-Tool konzipiert wurde, wird es manchmal als solches eingesetzt. Organisationen verlassen sich auf Helm nicht nur, um zu installieren, zu aktualisieren und zu löschen, sondern auch, um Änderungen im Laufe der Zeit zu verfolgen, um die Konfiguration zu verfolgen und um festzustellen, ob eine Anwendung als Ganzes läuft. Helm kann auf diese Weise gestreckt werden, aber wenn du eine starke Konfigurationsmanagementlösung willst, solltest du andere Tools aus dem Helm-Ökosystem nutzen. Viele Tools wie Helmfile, Flux und Reckoner haben die Details des Konfigurationsmanagements ergänzt.

Hinweis

Die Helm-Community hat eine Vielzahl von Tools entwickelt, die mit Helm zusammenarbeiten oder es ergänzen. Das Helm-Projekt führt eine Liste dieser Werkzeuge in der offiziellen Dokumentation.

Ein häufiges Thema bei Helm-Diagrammen ist, dass die Konfigurationsoptionen oft so eingerichtet sind, dass du dasselbe Diagramm als Minimalversion für deine Entwicklungsumgebung oder (mit anderen Konfigurationsoptionen) als anspruchsvolle Version für deine Produktionsumgebung verwenden kannst.

Helms Architektur

Im letzten Abschnitt dieses Kapitels gehen wir kurz auf die High-Level-Architektur von Helm ein. Dieser Abschnitt rundet nicht nur die konzeptionelle Diskussion über Cloud-native Kubernetes-Anwendungen und Paketmanagement ab, sondern ebnet auch den Weg für Kapitel 2, in dem wir uns mit der Nutzung von Helm beschäftigen.

Kubernetes Ressourcen

Wir haben uns verschiedene Arten von Kubernetes-Ressourcen angeschaut. Wir haben ein paar Pod Definitionen, ConfigMap, Deployment und Service gesehen. Kubernetes bietet noch Dutzende weitere. Du kannst sogar benutzerdefinierte Ressourcendefinitionen (CRDs) verwenden, um deine eigenen Ressourcentypen zu definieren. In der Kubernetes-Hauptdokumentation findest du sowohl zugängliche Anleitungen als auch eine detaillierte API-Dokumentation zu jeder Art.

Im Laufe dieses Buches werden wir viele verschiedene Kubernetes-Ressourcentypen verwenden. Wir besprechen sie zwar im Zusammenhang, aber wenn du auf neue Ressourcendefinitionen stößt, ist es vielleicht hilfreich, das Kubernetes-Hauptdokument zu überfliegen.

Wie wir bereits besprochen haben, sind Ressourcendefinitionen deklarativ. Du, der Nutzer, beschreibst für Kubernetes den gewünschten Zustand einer Ressource. Du kannst zum Beispiel die Pod Definition, die wir weiter oben im Kapitel erstellt haben, als eine Aussage lesen: "Ich möchte, dass Kubernetes mir eine Pod mit diesen Funktionen erstellt." Es liegt an Kubernetes herauszufinden, wie ein Pod nach deinen Vorgaben konfiguriert und betrieben werden kann.

Alle Kubernetes-Ressourcendefinitionen haben eine gemeinsame Untermenge an Elementen. Das folgende Manifest verwendet eine Deployment, um die wichtigsten Strukturelemente einer Ressourcendefinition zu veranschaulichen:

apiVersion: apps/v1 1
kind: Deployment 2
metadata: 3
    name: example-deployment 4
    labels: 5
        some-name: some-value
    annotations: 6
        some-name: some-value
# resource-specific YAML
1

Die API-Familie und Version für diese Ressource.

2

Die Art der Ressource. Kombiniert mit apiVersion erhalten wir den "Ressourcentyp".

3

Der Abschnitt metadata enthält die wichtigsten Daten über die Ressource.

4

Eine name ist für fast jede Ressourcenart erforderlich.

5

Labels werden verwendet, um Kubernetes abfragbare "Handles" für deine Ressourcen zu geben.

6

Mit Hilfe von Anmerkungen können Autoren ihre eigenen Schlüssel und Werte an eine Ressource anhängen.

Ein Ressourcentyp in Kubernetes setzt sich aus dreiInformationen zusammen:

API-Gruppe (oder Familie)

Bei einigen Basisressourcentypen wie Pod und ConfigMap wird dieser Name weggelassen.

API-Version

Ausgedrückt als v, gefolgt von einer Hauptversion und einer optionalen Stabilitätsmarkierung. Zum Beispiel ist v1 eine stabile "Version 1", während v1alpha eine instabile "Version 1 Alpha 1" bezeichnet.

Ressource Art

Der (großgeschriebene) Name der spezifischen Ressource innerhalb der API-Gruppe.

Hinweis

Der vollständige Name eines Ressourcentyps lautet etwa apps/v1 Deployment oder v1 Pod (für Core-Typen), aber Kubernetes-Benutzer lassen oft die Gruppe und Version weg, wenn sie über bekannte Typen sprechen oder schreiben. In diesem Buch schreiben wir zum Beispiel einfach Deployment statt apps/v1 Deployment. Vollständig qualifizierte Namen werden verwendet, wenn eine genaue Version angegeben wird oder wenn es um einen Ressourcentyp geht, der in einer CRD definiert ist.

So zeigt apps/v1 Deployment an, dass die API-Gruppe "Apps" einen Ressourcentyp "Version 1" (stabil) mit dem Namen "Deployment" hat.

Kubernetes unterstützt zwei Hauptformate für die Deklaration der gewünschten Ressourcen: JSON und YAML. Streng genommen ist YAML eine Obermenge von JSON. Alle JSON-Dokumente sind gültige YAML-Dokumente, aber YAML bietet eine Reihe von zusätzlichen Funktionen.

In diesem Buch halten wir uns an das YAML-Format. Wir finden, dass es einfacher zu lesen und zu schreiben ist, und fast alle Helm-Nutzer wählen YAML statt JSON. Solltest du jedoch andere Vorlieben haben, unterstützen sowohl Kubernetes als auch Helm einfaches JSON.

Vorhin haben wir den Begriff Manifest eingeführt. Ein Manifest ist einfach eine Kubernetes-Ressource, die entweder im JSON- oder im YAML-Format serialisiert ist. Unsere früheren Beispiele Pod, ConfigMap, Deployment und Service können als Kubernetes-Manifeste bezeichnet werden, da es sich um Ressourcen handelt, die in YAML ausgedrückt sind.

Charts

Wir haben in diesem Kapitel bereits über Helm-Pakete gesprochen. Im Vokabular von Helm wird ein Paket als Karte bezeichnet. Der Name ist eine Anspielung auf die nautische Natur von Kubernetes (was auf Griechisch "Schiffskapitän" bedeutet) und Helm (das ist der Steuermechanismus eines Schiffes). Eine Karte zeigt den Weg, wie eine Kubernetes-Anwendung installiert werden sollte.

Ein Diagramm ist eine Reihe von Dateien und Verzeichnissen, die der Diagrammspezifikation zur Beschreibung der in Kubernetes zu installierenden Ressourcen entsprechen. In Kapitel 4 wird die Chart-Struktur im Detail erklärt, aber es gibt ein paar übergeordnete Konzepte, die wir hier vorstellen wollen.

Ein Diagramm enthält eine Datei namens Chart.yaml, die das Diagramm beschreibt. Sie enthält Informationen über die Diagrammversion, den Namen und die Beschreibung des Diagramms sowie den Autor des Diagramms.

Ein Diagramm enthält auch Templates. Dabei handelt es sich um Kubernetes-Manifeste (wie wir sie weiter oben in diesem Kapitel gesehen haben), die möglicherweise mit Templating-Direktiven versehen sind. Wir werden diese in Kapitel 5 ausführlich behandeln.

Eine Tabelle kann auch eine values.yaml-Datei enthalten, die eine Standardkonfiguration enthält. Diese Datei enthält Parameter, die du bei der Installation und beim Upgrade überschreiben kannst.

Dies sind die grundlegenden Dinge, die du in einem Helm-Diagramm findest, aber es gibt noch weitere, die wir in Kapitel 4 behandeln werden. Wenn du ein Helm-Diagramm siehst, kann es entweder in gepackter oder ungepackter Form dargestellt werden.

Ein entpacktes Helm-Diagramm ist nur ein Verzeichnis. Darin befindet sich eine Chart.yaml, einevalues.yaml, ein templates/ Verzeichnis und vielleicht noch andere Dinge. Ein gepacktes Helm-Diagramm enthält dieselben Informationen wie ein ungepacktes, ist aber geteert und gezippt in einer einzigen Datei.

Ein entpacktes Diagramm wird durch ein Verzeichnis mit dem Namen des Diagramms dargestellt. Zum Beispiel wird die Karte mit dem Namen mychart in das Verzeichnis mychart/ entpackt. Ein gepacktes Diagramm hingegen hat den Namen und die Version des Diagramms sowie das Suffix tgz: mychart-1.2.3.tgz.

Charts werden in Chart-Repositories gespeichert, die wir in Kapitel 7 behandeln werden. Helm weiß, wie man Karten aus Repositories herunterlädt und installiert.

Ressourcen, Installationen und Veröffentlichungen

Um die in diesem Abschnitt eingeführte Terminologie zusammenzufassen: Wenn ein Helm-Diagramm in Kubernetes installiert wird, passiert Folgendes:

  1. Der Steuermann liest die Karte (und lädt sie ggf. herunter).

  2. Sie sendet die Werte in die Templates und erzeugt so Kubernetes-Manifeste.

  3. Die Manifeste werden an Kubernetes gesendet.

  4. Kubernetes erstellt die angeforderten Ressourcen innerhalb des Clusters.

Wenn ein Helm-Diagramm installiert wird, erstellt Helm so viele Ressourcendefinitionen, wie es braucht. Manche erstellen ein oder zwei, andere wiederum Hunderte. Wenn Kubernetes diese Definitionen erhält, erstellt es Ressourcen für sie.

Ein Helm-Diagramm kann viele Ressourcendefinitionen haben. Kubernetes sieht jede dieser Definitionen als eigenständige Sache an. Aus Sicht von Helm sind jedoch alle Ressourcen, die in einem Diagramm definiert sind, miteinander verbunden. Meine WordPress-Anwendung kann zum Beispiel eine Deployment, eine ConfigMap, eineServiceund so weiter. Aber sie sind alle Teil eines Diagramms. Und wenn ich sie installiere, sind sie alle Teil der gleichen Installation. Ein und dasselbe Diagramm kann mehr als einmal installiert werden (jedes Mal mit einem anderen Namen). Ich kann also mehrere Installationen desselben Diagramms haben, genauso wie ich mehrere Ressourcen desselben Kubernetes-Ressourcentyps haben kann.

Und das bringt uns zu einem letzten Begriff. Sobald wir unser WordPress-Diagramm installiert haben, haben wir eine Installation des Diagramms. Dann aktualisieren wir dieses Diagramm mit helm upgrade. Jetzt hat diese Installation zwei Versionen. Jedes Mal, wenn wir Helm verwenden, um die Installation zu ändern, wird eine neue Version der Installation erstellt.

Ein Release wird erstellt, wenn wir eine neue Version von WordPress installieren. Ein Release wird aber auch erstellt, wenn wir lediglich die Konfiguration einer Installation ändern oder wenn wir eine Installation zurücksetzen. Dies ist eine wichtige Funktion von Helm, die wir in Kapitel 7 wiedersehen werden.

Eine kurze Anmerkung zu Helm 2

Diejenigen, die mit Helm 2 vertraut sind, werden feststellen, dass bestimmte Konzepte in diesem Buch fehlen. Es werden weder Tiller noch gRPC erwähnt. Diese Dinge wurden aus Helm 3 entfernt, das Thema des vorliegenden Buches ist. Außerdem konzentriert sich diese Version des Buches auf die Helm-Diagramme der Version 2. So verwirrend es auch ist, die Helm-Kartenversion wird unabhängig von der Helm-Version hochgezählt. Helm v2 verwendet also Helm Charts v1 und Helm v3 verwendet Helm Charts v2. Diese unterscheiden sich in einigen wichtigen Punkten von den Helm Charts der Version 1 - vor allem in der Art, wie Abhängigkeiten deklariert werden. Helm 2 und Helm Charts v1 gelten als veraltet.

Fazit

Das Material hier soll dich auf die kommenden Kapitel vorbereiten. Wir hoffen aber auch, dass es dir einen Einblick gibt, warum wir Helm so entwickelt haben, wie wir es getan haben. Helm ist nur dann erfolgreich, wenn es Kubernetes sowohl für die Erstnutzer als auch für die langjährigen Betriebsteams und SREs, die Helm tagtäglich nutzen, benutzerfreundlicher macht. Der Rest dieses Buches ist der Erläuterung (mit vielen Beispielen) gewidmet, wie du das Beste aus Helm herausholst - und wie du das auf sichere und idiomatische Weise machst.

Get Lernhelm now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.