Kapitel 1. Einführung

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

In diesem Einführungskapitel legen wir den Grundstein für den Rest des Buches, indem wir einige der zentralen Kubernetes-Konzepte für die Entwicklung und Implementierung von Cloud-nativen Anwendungen erläutern. Das Verständnis dieser neuen Abstraktionen und der damit verbundenen Prinzipien und Muster aus diesem Buch ist der Schlüssel zum Aufbau verteilter Anwendungen, die von Kubernetes automatisiert werden können.

Dieses Kapitel ist keine Voraussetzung für das Verständnis der später beschriebenen Muster. Leser, die mit Kubernetes-Konzepten vertraut sind, können es überspringen und direkt in die Kategorie der Muster springen, die sie interessiert.

Der Weg zu Cloud Native

Microservices gehören zu den beliebtesten Architekturstilen für die Entwicklung von Cloud-nativen Anwendungen. Sie bewältigen die Softwarekomplexität durch die Modularisierung von Geschäftsfunktionen und tauschen Entwicklungskomplexität gegen Betriebskomplexität. Eine wichtige Voraussetzung für den Erfolg von Microservices ist daher die Entwicklung von Anwendungen, die über Kubernetes skalierbar betrieben werden können.

Im Rahmen der Microservices-Bewegung gibt es eine enorme Menge an Theorien, Techniken und ergänzenden Tools, um Microservices von Grund auf zu erstellen oder Monolithen in Microservices aufzuspalten. Die meisten dieser Verfahren basieren auf dem Domain-Driven Design von Eric Evans (Addison-Wesley) und den Konzepten der Bounded Contexts und Aggregate. Bounded Contexts befassen sich mit großen Modellen, indem sie in verschiedene Komponenten aufgeteilt werden, und Aggregate helfen dabei, Bounded Contexts weiter in Module mit definierten Transaktionsgrenzen zu gruppieren. Zusätzlich zu diesen fachlichen Erwägungen gibt es für jedes verteilte System - ob es nun auf Microservices basiert oder nicht - auch technische Bedenken hinsichtlich seiner externen Struktur und der Laufzeitkopplung. Container und Container-Orchestratoren wie Kubernetes bringen neue Primitive und Abstraktionen ein, um die Probleme verteilter Anwendungen zu lösen, und hier besprechen wir die verschiedenen Optionen, die zu berücksichtigen sind, wenn ein verteiltes System in Kubernetes eingebunden wird.

In diesem Buch betrachten wir das Zusammenspiel von Containern und Plattformen, indem wir die Container als Blackboxen betrachten. Wir haben diesen Abschnitt jedoch geschaffen, um zu betonen, wie wichtig es ist, was in Containern steckt. Container und Cloud Native Plattformen bringen enorme Vorteile für deine verteilten Anwendungen, aber wenn du nur Müll in die Container steckst, bekommst du im großen Maßstab verteilten Müll. Abbildung 1-1 zeigt die Mischung der Fähigkeiten, die für die Erstellung guter Cloud-nativer Anwendungen erforderlich sind, und wo die Kubernetes-Muster hineinpassen.

The path to cloud native
Abbildung 1-1. Der Weg zur Cloud Native

Um gute Cloud Native Applications zu entwickeln, muss man mit verschiedenen Designtechniken vertraut sein:

  • Auf der untersten Codeebene spielt jede Variable, die du definierst, jede Methode, die du erstellst, und jede Klasse, die du instanziierst, eine Rolle für die langfristige Wartung der Anwendung. Unabhängig davon, welche Containertechnologie und Orchestrierungsplattform du verwendest, haben das Entwicklungsteam und die von ihm erstellten Artefakte den größten Einfluss. Es ist wichtig, Entwickler/innen heranzuziehen, die sich bemühen, sauberen Code zu schreiben, die über die richtige Anzahl automatisierter Tests verfügen, die ständig Refactoring betreiben, um die Codequalität zu verbessern, und die sich im Herzen von den Prinzipien der Software Craftsmanship leiten lassen.

  • Beimbereichsorientierten Design (Domain-driven Design ) geht es darum, das Softwaredesign aus der Unternehmensperspektive zu betrachten, um die Architektur so nah wie möglich an der realen Welt zu halten. Dieser Ansatz funktioniert am besten bei objektorientierten Programmiersprachen, aber es gibt auch andere gute Möglichkeiten, Software für reale Probleme zu modellieren und zu entwerfen. Ein Modell mit den richtigen Geschäfts- und Transaktionsgrenzen, einfach zu konsumierenden Schnittstellen und reichhaltigen APIs ist die Grundlage für eine erfolgreiche Containerisierung und spätere Automatisierung.

  • Die hexagonale Architektur und ihre Variationen wie die Onion- und Clean-Architekturen verbessern die Flexibilität und Wartbarkeit von Anwendungen, indem sie die Anwendungskomponenten entkoppeln und standardisierte Schnittstellen für die Interaktion mit ihnen bereitstellen. Durch die Entkopplung der Kerngeschäftslogik eines Systems von der umgebenden Infrastruktur erleichtert die hexagonale Architektur die Portierung des Systems auf verschiedene Umgebungen oder Plattformen. Diese Architekturen ergänzen das domänenorientierte Design und helfen dabei, den Anwendungscode mit klaren Grenzen und externalisierten Infrastrukturabhängigkeiten zu gestalten.

  • Der Microservices-Architekturstil und die Zwölf-Faktoren-Methode haben sich sehr schnell zur Norm für die Entwicklung verteilter Anwendungen entwickelt und bieten wertvolle Prinzipien und Praktiken für die Entwicklung sich verändernder verteilter Anwendungen. Wenn du diese Prinzipien anwendest, kannst du Implementierungen erstellen, die für Skalierung, Ausfallsicherheit und Veränderungsgeschwindigkeit optimiert sind - alles Anforderungen, die heute an moderne Software gestellt werden.

  • Container wurden sehr schnell zum Standard für die Verpackung und Ausführung verteilter Anwendungen, egal ob es sich um Microservices oder Funktionen handelt. Eine weitere Grundvoraussetzung ist die Erstellung modularer, wiederverwendbarer Container, die gute Cloud Native Citizens sind. Cloud Native ist ein Begriff, der Prinzipien, Muster und Werkzeuge zur Automatisierung von containerisierten Anwendungen in großem Maßstab beschreibt. Wir verwenden den Begriff Cloud Native gleichbedeutend mit Kubernetes, der populärsten Open-Source-Plattform für Cloud Native, die heute verfügbar ist.

In diesem Buch befassen wir uns nicht mit sauberem Code, domain-driven Design, hexagonaler Architektur oder Microservices. Wir konzentrieren uns nur auf die Muster und Praktiken, die sich mit den Belangen der Container-Orchestrierung befassen. Damit diese Muster wirksam sind, muss deine Anwendung von innen heraus gut gestaltet sein, indem du sauberen Code, domänenorientiertes Design, hexagonale Architektur - wie die Isolierung externer Abhängigkeiten -, Microservices-Prinzipien und andere relevante Designtechniken einsetzt.

Verteilte Primitive

Um zu erklären, was wir mit den neuen Abstraktionen und Primitiven meinen, vergleichen wir sie mit der bekannten objektorientierten Programmierung (OOP) und speziell mit Java. In der OOP-Welt gibt es Konzepte wie Klasse, Objekt, Paket, Vererbung, Kapselung und Polymorphismus. Die Java-Laufzeitumgebung bietet spezifische Funktionen und Garantien für die Verwaltung des Lebenszyklus unserer Objekte und der Anwendung als Ganzes.

Die Sprache Java und die Java Virtual Machine (JVM) bieten lokale, prozessinterne Bausteine für die Erstellung von Anwendungen. Kubernetes fügt dieser bekannten Denkweise eine völlig neue Dimension hinzu, indem es einen neuen Satz von verteilten Primitiven und eine Laufzeitumgebung für den Aufbau verteilter Systeme bietet, die sich über mehrere Knoten und Prozesse erstrecken. Mit Kubernetes verlassen wir uns nicht mehr nur auf die lokalen Primitive, um das gesamte Anwendungsverhalten zu implementieren.

Wir müssen immer noch die objektorientierten Bausteine verwenden, um die Komponenten der verteilten Anwendung zu erstellen, aber wir können auch Kubernetes-Primitive für einige der Verhaltensweisen der Anwendung verwenden. Tabelle 1-1 zeigt, wie verschiedene Entwicklungskonzepte mit lokalen und verteilten Primitiven in der JVM bzw. in Kubernetes unterschiedlich umgesetzt werden.

Tabelle 1-1. Lokale und verteilte Primitive
Konzept Lokal primitiv Verteiltes Primitiv

Verhaltenskapselung

Klasse

Container-Image

Verhalten Instanz

Objekt

Container

Einheit der Wiederverwendung

.jar

Container-Image

Zusammensetzung

Klasse A enthält Klasse B

Seitenwagen-Muster

Vererbung

Klasse A erweitert Klasse B

Das FROM Eltern-Image eines Containers

Einsatzeinheit

.jar/.war/.ear

Pod

Isolierung zwischen Buildtime und Runtime

Modul, Paket, Klasse

Namensraum, Pod, Container

Vorbedingungen für die Initialisierung

Konstrukteur

Init Container

Auslöser für die Postinitialisierung

Init-Methode

postStart

Predestroy-Auslöser

Destroy-Methode

preStop

Bereinigungsverfahren

finalize(), Abschalthaken

-

Asynchrone und parallele Ausführung

ThreadPoolExecutor,ForkJoinPool

Auftrag

Regelmäßige Aufgabe

Timer, ScheduledExecutorService

CronJob

Hintergrund Aufgabe

Daemon-Thread

DaemonSet

Konfigurationsmanagement

System.getenv(), Properties

ConfigMap, Geheimnis

Die prozessinternen Primitive und die verteilten Primitive haben Gemeinsamkeiten, sind aber nicht direkt vergleichbar und austauschbar. Sie arbeiten auf unterschiedlichen Abstraktionsebenen und haben unterschiedliche Voraussetzungen und Garantien. Einige Primitive sollen zusammen verwendet werden. Zum Beispiel müssen wir immer noch Klassen verwenden, um Objekte zu erstellen und sie in Container-Images zu packen. Einige andere Primitive wie der CronJob in Kubernetes können jedoch das ExecutorService Verhalten in Java vollständig ersetzen.

Als Nächstes wollen wir uns ein paar verteilte Abstraktionen und Primitive von Kubernetes ansehen, die für Anwendungsentwickler besonders interessant sind.

Container

Container sind die Bausteine für Kubernetes-basierte Cloud Native Anwendungen. Wenn wir einen Vergleich mit OOP und Java anstellen, sind Container-Images wie Klassen, und Container sind wie Objekte. Genauso wie wir Klassen erweitern können, um ihr Verhalten wiederzuverwenden und zu ändern, können wir Container-Images haben, die andere Container-Images erweitern, um ihr Verhalten wiederzuverwenden und zu ändern. Genauso wie wir Objekte zusammenstellen und Funktionen nutzen können, können wir Container zusammenstellen, indem wir Container in einen Pod packen und zusammenarbeitende Container nutzen.

Wenn wir den Vergleich fortsetzen, wäre Kubernetes wie die JVM, aber über mehrere Hosts verteilt, und sie wäre für die Ausführung und Verwaltung der Container zuständig. Init-Container wären so etwas wie Objektkonstruktoren; DaemonSets wären ähnlich wie Daemon-Threads, die im Hintergrund laufen (wie zum Beispiel der Java Garbage Collector). Ein Pod wäre so etwas wie ein Inversion of Control (IoC)-Kontext (z. B. Spring Framework), bei dem mehrere laufende Objekte einen verwalteten Lebenszyklus teilen und direkt aufeinander zugreifen können.

Die Parallele geht nicht viel weiter, aber der Punkt ist, dass Container eine grundlegende Rolle in Kubernetes spielen und die Erstellung von modularisierten, wiederverwendbaren Container-Images für einen einzigen Zweck von grundlegender Bedeutung für den langfristigen Erfolg eines jeden Projekts und sogar des Container-Ökosystems insgesamt ist. Abgesehen von den technischen Merkmalen eines Container-Images, die für die Paketierung und Isolierung sorgen, stellt sich die Frage, was ein Container ist und welchen Zweck er im Kontext einer verteilten Anwendung erfüllt? Hier sind ein paar Vorschläge, wie man Container betrachten kann:

  • Ein Container-Image ist eine Funktionseinheit, die ein einzelnes Problem löst.

  • Ein Container-Image gehört einem Team und hat seinen eigenen Veröffentlichungszyklus.

  • Ein Container-Image ist in sich geschlossen und definiert und trägt seine Laufzeit-Abhängigkeiten.

  • Ein Container-Image ist unveränderlich, und wenn es einmal erstellt ist, ändert es sich nicht mehr; es ist konfiguriert.

  • Ein Container-Image definiert seine Ressourcenanforderungen und externen Abhängigkeiten.

  • Ein Container-Image verfügt über genau definierte APIs, um seine Funktionen zu offenbaren.

  • Ein Container läuft normalerweise als einzelner Unix-Prozess.

  • Ein Container ist ein Einwegprodukt und kann jederzeit vergrößert oder verkleinert werden.

Zusätzlich zu all diesen Eigenschaften ist ein richtiges Container-Image modular. Es ist parametrisiert und wird für die Wiederverwendung in den verschiedenen Umgebungen erstellt, in denen es laufen soll. Kleine, modulare und wiederverwendbare Container-Images führen dazu, dass langfristig spezialisiertere und stabilere Container-Images entstehen, ähnlich wie eine große wiederverwendbare Bibliothek in der Welt der Programmiersprachen.

Pods

Ein Blick auf die Eigenschaften von Containern zeigt, dass sie sich perfekt für die Umsetzung der Microservices-Prinzipien eignen. Ein Container-Image bietet eine einzige Funktionseinheit, gehört zu einem einzigen Team, hat einen unabhängigen Release-Zyklus und bietet eine Isolierung bei der Bereitstellung und während der Laufzeit. Meistens entspricht ein Microservice einem Container-Image.

Die meisten nativen Cloud-Plattformen bieten jedoch eine andere Möglichkeit, den Lebenszyklus einer Gruppe von Containern zu verwalten - in Kubernetes heißt das Pod. Ein Pod ist eine atomare Einheit für die Planung, Bereitstellung und Laufzeitisolierung einer Gruppe von Containern. Alle Container in einem Pod werden immer auf demselben Host eingeplant, gemeinsam bereitgestellt und skaliert und können sich auch die Namensräume für Dateisystem, Netzwerk und Prozesse teilen. Dieser gemeinsame Lebenszyklus ermöglicht es den Containern in einem Pod, über das Dateisystem oder über Netzwerke mittels Localhost- oder Host-Interprozess-Kommunikationsmechanismen miteinander zu interagieren, falls dies gewünscht wird ( z. B. aus Leistungsgründen). Ein Pod stellt auch eine Sicherheitsgrenze für eine Anwendung dar. Es ist zwar möglich, Container mit unterschiedlichen Sicherheitsparametern im selben Pod zu haben, aber in der Regel haben alle Container die gleiche Zugriffsstufe, Netzwerksegmentierung und Identität.

Wie du in Abbildung 1-2 sehen kannst, entspricht ein Microservice zur Entwicklungs- und Build-Zeit einem Container-Image, das ein Team entwickelt und veröffentlicht. Zur Laufzeit wird ein Microservice jedoch durch einen Pod repräsentiert, der die Einheit für die Bereitstellung, Platzierung und Skalierung ist. Die einzige Möglichkeit, einen Container auszuführen - sei es zur Skalierung oder zur Migration - ist die Pod-Abstraktion. Manchmal enthält ein Pod mehr als einen Container. In einem solchen Beispiel verwendet ein containerisierter Microservice zur Laufzeit einen Hilfscontainer, wie Kapitel 16, "Sidecar", zeigt.

Pod as the deployment and management unit
Abbildung 1-2. Ein Pod als Einsatz- und Verwaltungseinheit

Container, Pods und ihre einzigartigen Eigenschaften bieten eine Reihe neuer Muster und Prinzipien für die Entwicklung von Microservices-basierten Anwendungen. Wir haben einige Merkmale von gut konzipierten Containern kennengelernt; jetzt wollen wir uns einige Merkmale eines Pods ansehen:

  • Ein Pod ist die atomare Einheit der Zeitplanung. Das bedeutet, dass das Zeitplannungsprogramm versucht, einen Host zu finden, der die Anforderungen aller Container, die zum Pod gehören, erfüllt (wir behandeln einige Besonderheiten rund um init container in Kapitel 15, "Init Container"). Wenn du einen Pod mit vielen Containern erstellst, muss das Zeitplannungsprogramm einen Host finden, der genug Ressourcen hat, um die Anforderungen aller Container zusammen zu erfüllen. Dieses Zeitplannungsprogramm wird in Kapitel 6, "Automatisierte Platzierung", beschrieben .

  • Ein Pod sorgt für die Kolokation von Containern. Dank der Kolokation haben Container im selben Pod zusätzliche Möglichkeiten, miteinander zu kommunizieren. Die gängigsten Kommunikationsmöglichkeiten sind ein gemeinsames lokales Dateisystem für den Datenaustausch, die Verwendung der Netzwerkschnittstelle des lokalen Hosts oder ein IPC-Mechanismus (Interprocess Communication) des Hosts für hochleistungsfähige Interaktionen.

  • Ein Pod hat eine IP-Adresse, einen Namen und einen Portbereich, die von allen Containern, die zu ihm gehören, gemeinsam genutzt werden. Das bedeutet, dass Container in einem Pod sorgfältig konfiguriert werden müssen, um Portkonflikte zu vermeiden, genauso wie parallel laufende Unix-Prozesse darauf achten müssen, den Netzwerkbereich eines Hosts zu teilen.

Ein Pod ist das Atom von Kubernetes, in dem deine Anwendung lebt, aber du greifst nicht direkt auf Pods zu - hier kommen die Dienste ins Spiel.

Dienstleistungen

Pods sind kurzlebig. Sie können aus den unterschiedlichsten Gründen jederzeit kommen und gehen (z. B. Skalierung, fehlgeschlagene Container-Zustandsprüfungen, Knotenmigrationen). Die IP-Adresse eines Pods ist erst bekannt, nachdem er geplant und auf einem Knoten gestartet wurde. Ein Pod kann auf einen anderen Knoten verschoben werden, wenn der bestehende Knoten, auf dem er läuft, nicht mehr in Ordnung ist. Das bedeutet, dass sich die Netzwerkadresse des Pods während der Laufzeit einer Anwendung ändern kann und dass ein anderes Primitiv für die Erkennung und den Lastausgleich benötigt wird.

Hier kommen die Kubernetes Services ins Spiel. Der Service ist eine weitere einfache, aber leistungsstarke Kubernetes-Abstraktion, die den Servicenamen dauerhaft an eine IP-Adresse und eine Portnummer bindet. Ein Service stellt also einen benannten Einstiegspunkt für den Zugriff auf eine Anwendung dar. Im häufigsten Szenario dient der Service als Einstiegspunkt für eine Reihe von Pods, aber das muss nicht immer der Fall sein. Der Service ist ein generisches Primitiv, das auch auf Funktionen außerhalb des Kubernetes-Clusters verweisen kann. Als solches kann das Service-Primitiv für die Service-Erkennung und den Lastausgleich verwendet werden und ermöglicht die Änderung von Implementierungen und die Skalierung, ohne dass die Service-Konsumenten davon betroffen sind. In Kapitel 13, "Service Discovery", werden Services ausführlich erklärt .

Etiketten

Wir haben gesehen, dass ein Microservice zur Build-Zeit ein Container-Image ist, zur Laufzeit aber durch einen Pod repräsentiert wird. Was ist also eine Anwendung, die aus mehreren Microservices besteht? Hier bietet Kubernetes zwei weitere Primitive, mit denen du das Konzept einer Anwendung definieren kannst: Labels und Namensräume.

Bevor es Microservices gab, entsprach eine Anwendung einer einzelnen Bereitstellungseinheit mit einem einzigen Versionsschema und Release-Zyklus. Es gab eine einzige Datei für eine Anwendung in einem .war-, .ear- oder einem anderen Paketformat. Doch dann wurden die Anwendungen in Microservices aufgeteilt, die unabhängig voneinander entwickelt, freigegeben, ausgeführt, neu gestartet oder skaliert werden. Mit Microservices verschwindet der Begriff der Anwendung, und es gibt keine wichtigen Artefakte oder Aktivitäten, die wir auf der Anwendungsebene durchführen müssen. Wenn du aber trotzdem eine Möglichkeit brauchst, um zu kennzeichnen, dass einige unabhängige Dienste zu einer Anwendung gehören, kannst du Labels verwenden. Stellen wir uns vor, dass wir eine monolithische Anwendung in drei Microservices und eine andere in zwei Microservices aufgeteilt haben.

Wir haben jetzt fünf Pod-Definitionen (und vielleicht noch viel mehr Pod-Instanzen), die von der Entwicklungs- und der Laufzeitperspektive unabhängig sind. Trotzdem müssen wir vielleicht noch angeben, dass die ersten drei Pods eine Anwendung und die anderen beiden Pods eine andere Anwendung darstellen. Die Pods können sogar unabhängig sein, um einen Geschäftswert zu liefern, aber sie können voneinander abhängen. Ein Pod kann zum Beispiel die Container enthalten, die für das Frontend zuständig sind, während die beiden anderen Pods für die Backend-Funktionalität verantwortlich sind. Wenn einer dieser Pods ausfällt, ist die Anwendung aus geschäftlicher Sicht nutzlos. Mit können wir eine Reihe von Pods abfragen und identifizieren und sie als eine logische Einheit verwalten. Abbildung 1-3 zeigt, wie du die Teile einer verteilten Anwendung mithilfe von Labels in bestimmte Subsysteme einteilen kannst.

Labels used as an application identity for Pods
Abbildung 1-3. Etiketten, die als Anwendungsidentität für Pods verwendet werden

Hier sind ein paar Beispiele, bei denen Etiketten nützlich sein können:

  • Labels werden von ReplicaSets verwendet, um einige Instanzen eines bestimmten Pods am Laufen zu halten. Das bedeutet, dass jede Pod-Definition eine eindeutige Kombination von Labels haben muss, die für das Scheduling verwendet werden.

  • Labels werden auch vom Zeitplannungsprogramm intensiv genutzt. Das Zeitplannungsprogramm verwendet Labels, um Pods auf die Knotenpunkte zu verteilen, die den Anforderungen der Pods entsprechen.

  • Ein Label kann eine logische Gruppierung einer Gruppe von Pods anzeigen und ihnen eine Anwendungsidentität geben.

  • Zusätzlich zu den oben genannten typischen Anwendungsfällen können Labels auch zum Speichern von Metadaten verwendet werden. Es kann schwierig sein, vorherzusagen, wofür ein Label verwendet werden könnte, aber es ist am besten, wenn genügend Labels vorhanden sind, um alle wichtigen Aspekte der Pods zu beschreiben. Nützlich sind z. B. Labels, die die logische Gruppe einer Anwendung, die geschäftlichen Merkmale und die Kritikalität, die spezifischen Abhängigkeiten von der Laufzeitplattform (z. B. die Hardware-Architektur) oder die Standortpräferenzen angeben.

Später können diese Labels vom Zeitplannungsprogramm für eine feinere Planung verwendet werden, oder dieselben Labels können von der Kommandozeile aus für die Verwaltung der passenden Pods im Maßstab verwendet werden. Du solltest es jedoch nicht übertreiben und im Voraus zu viele Labels hinzufügen. Du kannst sie bei Bedarf später immer noch hinzufügen. Das Entfernen von Labels ist viel riskanter, da es keine einfache Möglichkeit gibt, herauszufinden, wofür ein Label verwendet wird und welche unbeabsichtigten Auswirkungen eine solche Aktion haben kann.

Namensräume

Ein weiteres Primitiv, das auch bei der Verwaltung einer Gruppe von Ressourcen helfen kann, ist der Kubernetes-Namensraum. Wie wir bereits beschrieben haben, ähnelt ein Namespace einem Label, aber in Wirklichkeit handelt es sich um ein ganz anderes Primitiv mit anderen Eigenschaften und Zwecken.

Mit Kubernetes-Namensräumen kannst du einen Kubernetes-Cluster (der in der Regel über mehrere Hosts verteilt ist) in einen logischen Pool von Ressourcen unterteilen. Namensräume bieten Bereiche für Kubernetes-Ressourcen und einen Mechanismus, um Berechtigungen und andere Richtlinien auf einen Teilbereich des Clusters anzuwenden. Der häufigste Anwendungsfall für Namensräume ist die Darstellung verschiedener Softwareumgebungen wie Entwicklung, Test, Integrationstest oder Produktion. Namensräume können auch verwendet werden, um Multitenancy zu erreichen und Teamarbeitsbereiche, Projekte und sogar bestimmte Anwendungen zu isolieren. Für eine stärkere Isolierung bestimmter Umgebungen reichen Namensräume jedoch nicht aus, und es ist üblich, getrennte Cluster zu haben. In der Regel gibt es einen nicht produktiven Kubernetes-Cluster, der für einige Umgebungen (Entwicklung, Tests und Integrationstests) verwendet wird, und einen weiteren produktiven Kubernetes-Cluster, der für Leistungstests und Produktionsumgebungen steht.

Schauen wir uns einige der Eigenschaften von Namensräumen an und wie sie uns in verschiedenen Szenarien helfen können:

  • Ein Namensraum wird als Kubernetes-Ressource verwaltet.

  • Ein Namensraum bietet Platz für Ressourcen wie Container, Pods, Services oder ReplicaSets. Die Namen der Ressourcen müssen innerhalb eines Namensraumes eindeutig sein, aber nicht über alle Namensräume hinweg.

  • Standardmäßig bieten Namensräume einen Geltungsbereich für Ressourcen, aber nichts isoliert diese Ressourcen und verhindert den Zugriff von einer Ressource zur anderen. Ein Pod aus einem Namensraum für die Entwicklung kann zum Beispiel auf einen anderen Pod aus einem Namensraum für die Produktion zugreifen, solange die IP-Adresse des Pods bekannt ist. " Die Netzwerkisolierung über Namensräume hinweg zur Schaffung einer leichtgewichtigen Multitenancy-Lösung wird in Kapitel 24, "Netzwerksegmentierung", beschrieben .

  • Einige andere Ressourcen, wie Namensräume, Knoten und PersistentVolumes, gehören nicht zu Namensräumen und sollten eindeutige clusterweite Namen haben.

  • Jeder Kubernetes-Dienst gehört zu einem Namensraum und erhält einen entsprechenden DNS-Eintrag (Domain Name Service), der den Namensraum in Form von <service-name>.<namespace-name>.svc.cluster.local enthält. Der Name des Namensraums ist also in der URL jedes Dienstes enthalten, der zu dem jeweiligen Namensraum gehört. Das ist ein Grund, warum es so wichtig ist, Namensräume vernünftig zu benennen.

  • ResourceQuotas bieten Beschränkungen, die den aggregierten Ressourcenverbrauch pro Namensraum begrenzen. Mit ResourceQuotas kann ein Cluster-Administrator die Anzahl der Objekte pro Typ festlegen, die in einem Namensraum erlaubt sind. Ein Entwickler-Namensraum darf zum Beispiel nur fünf ConfigMaps, fünf Secrets, fünf Services, fünf ReplicaSets, fünf PersistentVolumeClaims und zehn Pods zulassen.

  • ResourceQuotas kann auch die Gesamtsumme der Rechenressourcen begrenzen, die wir in einem bestimmten Namensraum anfordern können. In einem Cluster mit einer Kapazität von 32 GB RAM und 16 Kernen ist es zum Beispiel möglich, 16 GB RAM und 8 Kerne für den Produktions-Namensraum, 8 GB RAM und 4 Kerne für die Staging-Umgebung, 4 GB RAM und 2 Kerne für die Entwicklung und die gleiche Menge für die Namensräume zum Testen zuzuweisen. Die Möglichkeit, Ressourcenbeschränkungen unabhängig von der Form und den Grenzen der zugrunde liegenden Infrastruktur aufzuerlegen, ist von unschätzbarem Wert.

Diskussion

Wir haben nur kurz einige der wichtigsten Kubernetes-Konzepte behandelt, die wir in diesem Buch verwenden. Es gibt jedoch noch mehr Primitive, die von Entwicklern tagtäglich verwendet werden. Wenn du zum Beispiel einen containerisierten Dienst erstellst, gibt es viele Kubernetes-Abstraktionen, die du nutzen kannst, um alle Vorteile von Kubernetes auszuschöpfen. Denk daran, dass dies nur einige der Objekte sind, die von Anwendungsentwicklern verwendet werden, um einen containerisierten Dienst in Kubernetes zu integrieren. Es gibt noch viele andere Konzepte, die vor allem von Cluster-Administratoren für die Verwaltung von Kubernetes verwendet werden. Abbildung 1-4 gibt einen Überblick über die wichtigsten Kubernetes-Ressourcen, die für Entwickler/innen nützlich sind.

Kubernetes concepts for developers
Abbildung 1-4. Kubernetes-Konzepte für Entwickler

Mit der Zeit entstehen aus diesen neuen Primitiven neue Wege, Probleme zu lösen, und einige dieser sich wiederholenden Lösungen werden zu Mustern. In diesem Buch werden wir nicht jede Kubernetes-Ressource im Detail beschreiben, sondern uns auf Konzepte konzentrieren, die sich als Muster bewährt haben.

Get Kubernetes Patterns, 2. Auflage 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.