Kubernetes oder K8s ist eine ursprünglich von Google entwickelte Open-Source-Plattform für die Orchestrierung von Containern. Es ist dafür konzipiert, den Betrieb von Linux-Containern zu automatisieren – unabhängig davon, ob diese auf lokalen Systemen, Rechenzentren oder in der Cloud laufen. 

Seit seiner Erstveröffentlichung 2014 findet Kubernetes eine immer breitere Verbreitung in Unternehmen. Seine große Stärke und der Grund für seine Beliebtheit ist seine Fähigkeit, große Mengen von Containern zu verwalten. In Kubernetes umfasst die Orchestrierung das automatische Überwachen, Ausrollen, Fixen, Kopieren und Migrieren von Containern.

Trotz seiner Beliebtheit macht es Kubernetes auch für Experten manchmal schwer, den Wald vor lauter Bäumen zu sehen. Das liegt daran, dass es zwar über eine klare Hierarchie verfügt, gleichzeitig jedoch aus vielen Objekten und einzelnen Funktionen besteht, die miteinander interagieren. Dies macht es zu einer komplexen und vielschichtigen Technik. In diesem Artikel versuchen wir einen vereinfachten Überblick über die Architektur und die wichtigsten K8s-Objekte zu geben. Die Nutzung von Kubernetes beginnt immer mit der Erstellung eines Clusters.

Was ist ein Kubernetes-Cluster?

Kubernetes zu verwenden heißt, dass Sie in der Regel einen oder mehrere Cluster betreiben. Typischerweise besteht ein Cluster aus einer Control Plane, die alle Objekte im Cluster steuert, und einem oder mehreren Worker Nodes auf denen die containerisierten Anwendungen laufen. Um die Redundanz der Kubernetes-Umgebung sicherzustellen, besteht das Standard-Setup eines Clusters häufig aus drei Control Plane Nodes und drei Worker Nodes.

Für die Orchestrierung der Worker Nodes umfasst die Control Plane in einem Cluster folgende Komponenten:

  • API-Server: Der API-Server fungiert als Frontend der Kubernetes-Control-Plane. Über sie lässt sich der gewünschte Zustand des Clusters auslesen und festlegen, welche Anwendungen K8s wie ausführen soll.
  • Scheduler: Der Scheduler platziert die Container anhand der definierten Ressourcenanforderungen und weist freie Pods einem Node zu. 
  • Controller-Manager: Der Controller-Manager gleicht den Ist-Zustand des Clusters mit den vorgegebenen Spezifikationen ab.
  • Etcd: Bei Etcd handelt es sich um einen konsistenten und hochverfügbaren Speicher zur Speicherung aller kritischen Cluster-Daten, wie beispielsweise Konfigurations-, Zustand- und Metadaten von Kubernetes.

Auf den Worker Nodes laufen die beiden Komponenten kubelet und kube-proxy, die für die Steuerung der Container und für die Kommunikation zwischen den Nodes zuständig sind.

Ein Cluster besteht also aus verschiedenen Nodes. Doch was machen die Nodes eigentlich genau?

Was ist ein Kubernetes-Node?

Nodes sind die zentralen Bausteine eines Clusters. Dabei unterscheidet man zwischen den Control Plane Nodes und den Worker Nodes. Während der Master Node für die Verwaltung des Clusters zuständig ist, stellen Worker Nodes die für den Betrieb von Workloads  notwendigen Ressourcen und Dienste bereit. 

Praxis-Tipp: Die Rolle eines Nodes erkennt man mittels kubectl get nodes an den Labels “control-plane” oder “master”. 

Durch das Hosten der Pods ermöglichen Worker Nodes die Ausführung der eigentlichen Workloads. Dabei agieren die Nodes als Pool an CPU- und RAM-Ressourcen, auf denen Kubernetes anschließend die containerisierten Workloads ausführt. 

Zwar müssen Sie die physischen oder virtuellen Maschinen meist noch selbst managen, Kubernetes nimmt Ihnen jedoch die Entscheidung ab, auf welchem Node die Applikation am Ende läuft und ob auf diesem überhaupt genügend Ressourcen bereitstehen. 

Stellen Sie in der Praxis eine Anwendung in einem Cluster bereit, verteilt Kubernetes die Arbeit auf die Nodes. Dabei kann es die Workloads nahtlos zwischen den Nodes des Clusters verschieben.

Sie können mit Clustern arbeiten, um Applikationen und Ressourcen von verschiedenen Teams in Kubernetes voneinander zu trennen. In traditionellen IT-Infrastrukturen würde man das häufig mittels VMs, separierten Netzwerken oder Umgebungen umsetzen. In Kubernetes gibt es jedoch ein sehr probates und effizientes Hilfsmittel für die Unterteilung von Cluster in isolierte Bereiche: Namespaces.

Was sind Namespaces in Kubernetes?

Mit Namespaces können Sie Kubernetes-Cluster in isolierte, logische Bereiche unterteilen. Jeder Cluster unterstützt hierbei eine beliebige Anzahl von Namespaces, die Namespaces selbst lassen sich aber nicht ineinander verschachteln. 

Mit Namespaces lassen sich beispielsweise die Ressourcen der Kubernetes-Infrastruktur organisieren. Ein Namespace lässt sich also als eine Art virtuellen Sub-Cluster verstehen.

Nahezu jede Kubernetes-Ressource befindet sich entweder in einem Default-Namespace oder in einem manuell erstellten Namespace. Ausnahmen stellen hier die Nodes und Persistent Volumes dar. Beides sind sogenannte Low-Level-Ressourcen und existieren außerhalb von Namespaces – so sind sie für jeden Namespace im Cluster immer sichtbar.

Praxis-Tipp: Alle nicht Namespace-gebundenen Objekte findet man durch kubectl api-resources --namespaced=false.

Warum sollte man Namespaces verwenden?

Wie bereits erwähnt, erlauben Namespaces das Zusammenarbeiten von verschiedenen Teams, etwa im Rahmen von Projekten, in einem eigenen virtuellen Cluster. Dadurch wird die Umgebung der einzelnen Teams nicht beeinflusst. Gleichzeitig lassen sich mithilfe von Namespaces die Ressourcen eines Clusters zwischen mehreren Teams und Usern über Resource Quotas aufteilen. 

Namespaces eignen sich aber auch dazu, den Zugang von Benutzern und Workloads auf bestimmte Namespaces zu begrenzen. Sie bieten zudem eine einfache Methode, um die Entwicklung, Testing und den Betrieb von Applikationen zu trennen – und so den gesamten Lebenszyklus auf demselben Cluster abzubilden.

Findet eine Kommunikation zwischen Namespaces statt?

Namespaces sind zwar voneinander getrennt, können aber problemlos miteinander kommunizieren. Der DNS-Service von Kubernetes kann durch die Verwendung einer erweiterten Form der DNS-Adressierung (svc.cluster.local) jeden Service anhand seines Namens auffinden. Fügt man den Namen des Namespaces zum Service-Namen hinzu, ist der Zugriff auf Dienste in jedem Namespace des Clusters möglich.

Praxis-Tipp: Ein Query auf service.namespace ist identisch zu service.namespace.svc.cluster.local.

Optional lassen sich zudem Netzwerkrichtlinien (Network Policy) für den Zugriff zwischen Namespaces verwenden, um beispielsweise den gesamten Verkehr aus anderen Namespaces zuzulassen oder zu verweigern.

Sie haben bis jetzt erfahren, was Cluster und Nodes sind und wie Sie mit Namespaces Ihre Cluster in logische Bereiche unterteilen können. Wir haben auch erfahren, dass Worker Nodes Pods hosten, ohne diese weiter zu spezifizieren. Das werden wir in den nächsten Abschnitten nun nachholen.

Was ist ein Kubernetes-Pod?

Bei einem Pod handelt es sich um eine Umgebung, die auf einem Node bereitgestellt wird und in der ein Container ausgeführt wird. Es ist zwar möglich, mehrere Container in einem Pod zu betreiben, das ist aber eher die Ausnahme. 

Pods lassen sich als eigenständige Computer verstehen, die eine einzelne Aufgabe ausführen. Wenn Sie die Konfiguration des Pods ändern, setzt Kubernetes die Änderungen automatisch um, indem es neue Pods erstellt oder entfernt. 

Fällt ein Node aus, stellt Kubernetes die betroffenen Pods automatisch auf einem anderen Node bereit. Erkennt Kubernetes via Health Check den Ausfall eines Pods, startet es diesen ebenfalls neu.
Pods werden selten selbst in Kubernetes spezifiziert. Die Erzeugung von Pods erfolgt in der Regel über übergeordnete Mechaniken wie Deployments, DaemonSets und Jobs. Hängen Pods von einem Systemzustand ab, erfolgt die Erstellung häufig über StatefulSets. 

Praxis-Tipp: Über das Attribut “Controlled By” bei Ausgabe via kubectl describe pod [podname] lässt sich erkennen, wodurch ein Pod erstellt wurde. Ist das Feld leer, wurde der Pod ohne übergeordnete Mechanik gestartet.

Was sind Deployments in Kubernetes?

Bei Deployments handelt es sich in Kubernetes um eine der ersten Mechaniken für die Erstellung von Workloads. In der Beschreibung eines Deployments können Sie festlegen, welche Images die Applikation verwenden soll, wie viele Pods dafür erforderlich sind und wie Kubernetes diese aktualisieren soll. Das vereinfacht nicht nur die Durchführung von Updates und den dafür enthaltenen Schritten, sondern erlaubt Ihnen auch die Automatisierung dieses Prozesses und dessen Wiederholung.

Im Einzelnen können Sie mit Deployments Pods bereitstellen und diese aktualisieren, Rollbacks auf frühere Deployment-Versionen durchführen sowie Deployments skalieren, anhalten oder fortsetzen. Sobald sie ein Deployment erstellt haben, übernimmt die Kubernetes-Control-Plane die Planung für die genannten Anwendungsinstanzen.

Deployments eignen sich primär für zustandslose Applikationen. Das hat historische Gründe, da der ursprüngliche Fokus von Kubernetes auf eben diesen Stateless-Applikationen lag. Mit der Zeit hat sich aber herauskristallisiert, dass Kubernetes auch zustandsbasierte Applikationen unterstützen muss. Als Folge hat man sogenannte StatefulSets geschaffen.

Was sind StatefulSets?

Kubernetes verwendet StatefulSets, um die Ausführung von zustandsabhängigen Anwendungen zu steuern, die dauerhafte Identitäten und Hostnamen benötigen. In der Praxis bedeutet das, dass es die Bereitstellung und Skalierung der im Set enthaltenen Pods verwaltet und dabei auch die Reihenfolge und Einzigartigkeit dieser Pods garantiert. 

Mit StatefulSets können Sie zum Beispiel bei einer auf drei Replikas skalierten MySQL-Datenbank in einem Kubernetes-Cluster festlegen, dass eine Frontend-Applikation für Leseprozesse auf alle drei Pods zugreift. Bei Schreibprozessen adressiert sie hingegen nur den ersten Pod, wobei die Daten anschließend mit den anderen beiden Pods synchronisiert werden. 

StatefulSets weisen jedem Pod eine unveränderliche Identität zu, die bei 0 beginnt (0 -> n). Ein neuer Pod wird durch das Klonen der Daten des vorherigen Pods erstellt. Das Löschen beziehungsweise Beenden findet in umgekehrter Reihenfolge statt (n -> 0). Wenn Sie also die Anzahl der Replikate von vier auf drei verkleinern, beendet beziehungsweise löscht Kubernetes den Pod mit der Nummer 3 zuerst.

StatefulSets sind besonders für Applikationen geeignet, die mindestens eines der folgenden Merkmale erfordern: stabile, eindeutige Netzwerk-Identifikatoren, ein stabiler, beständiger Storage, eine geregelte, geordnete Bereitstellung sowie geordnete, automatische fortlaufende Aktualisierungen.

Ein erstelltes StatefulSet sorgt dafür, dass die gewünschte Anzahl an Pods ausgeführt wird und verfügbar ist. Fehlerhafte oder aus dem Node entfernte Pods ersetzt es basierend auf den im Set konfigurierten Spezifikationen automatisch.

Löscht man ein StatefulSet, führt das aus Gründen der Datensicherheit nicht automatisch zu einer Löschung der Daten auf den zugeordneten Volumes.

Neben Deployments und StatefulSets bietet Kubernetes mit DaemonSets noch eine weitere Mechanik zum Starten von Pods.

Was sind DaemonSets?

Mit DaemonSets starten Sie einen bestimmten Pod auf jedem Worker Node. Das heißt, dass sich dieser für Applikationen eignet, die Sie gerne auf jedem einzelnen Worker Node betreiben wollen. Das kann beispielsweise ein Logging Daemon sein, der die Logs aller Container sammelt und an einen zentralen Log-Server übermittelt.

Wie die verschiedenen Objekte und Funktionen in Kubernetes miteinander kommunizieren, schauen wir uns im nächsten Schritt an. Dabei wird zwischen der inneren und äußeren Kommunikation unterschieden. Für die Kommunikation der Objekte innerhalb eines Clusters verwendet Kubernetes sogenannte Services. 

Was sind Services in Kubernetes?

Bei Services in Kubernetes handelt es sich um eine logische Abstraktion für eine Gruppe von Pods in einem Cluster, die dieselbe Funktion erfüllen. Ein Service weist dieser Pod-Gruppe einen Namen und eine eindeutige IP-Adresse (clusterIP) zu, sodass diese für andere Pods erreichbar ist. Er legt außerdem die Richtlinien für den Zugriff fest und übernimmt die automatische Lastenverteilung aller eingehenden Anfragen.

Da ein Service die Erkennung und das Routing zwischen abhängigen Pods, etwa Frontend- und Backend-Komponenten übernimmt, wird die Anwendung nicht beeinträchtigt, wenn ein Pods stirbt und repliziert wird. 

Um Pods zu einer Gruppe zu verbinden, verwenden Services Labels und Selektoren.

Neben der inneren Kommunikation müssen die Applikationen jedoch nach außen kommunizieren können. Dies erfolgt über Ingress.

Was ist eine Kubernetes Ingress?

Kubernetes Ingress ist eine Schnittstelle, die es externen Usern via HTTP/HTTPS ermöglicht, auf Services in einem Kubernetes-Cluster zuzugreifen. Ingress erlaubt außerdem die Erstellung von Regeln für das Routing des Datenverkehrs, ohne dass Sie dafür Load Balancer erstellen oder alle Services eines Nodes offenlegen müssen. 

Sie haben jetzt die wichtigsten Objekte von Kubernetes kennengelernt. Was Ihnen jetzt noch fehlt, ist das Wissen, wie Sie überhaupt eine Applikation auf Kubernetes ausrollen können.

Wie rollt man Applikationen in Kubernetes aus?

Um eine Applikation in Kubernetes auszurollen, müssen Sie ein Manifest erstellen und ausführen. Bei einem Manifest handelt es sich um eine JSON- oder YAML-Datei. In einem Manifest legen Sie fest, welche Objekte – Deployments, Services, Pods, etc. – Sie erstellen wollen, wie diese im Cluster laufen sollen, welches Container-Image verwendet wird oder wie viele Replicas Kubernetes erzeugen soll. Anschließend rollen Sie das Manifest über die Kommandozeile (kubectl), oder über eine CI auf dem Cluster aus.

Aufgrund der einfachen Nutzung schreiben die meisten Kubernetes-Neulinge ihre Manifeste mit YAML. Ein Manifest hat jedoch den Nachteil, dass es sehr statisch und nicht besonders flexibel ist. Aus diesem Grund wechseln Kubernetes-User an irgendeinen Punkt meistens zu Helm Charts. Helm ist ein Paketmanager von Kubernetes und erleichtert besonders die Bereitstellung von hochgradig wiederholbaren Applikationen. Ein Helm Chart ist ein Paket aus einem oder mehreren Manifesten, die zu Templates mit Variablen umgearbeitet wurden. Die Variablen lassen sich bequem über eine weitere YAML spezifizieren, die man dem Helm ebenfalls mitgeben kann. Leider führt das in der Regel dazu, dass die Templates selbst nahezu unlesbar werden.  

Eine weitere Methode zum Ausrollen von Applikationen ist der sogenannte Kubernetes Operator. Dabei handelt es sich um einen Controller, der diesen Prozess noch weiter automatisiert. In der Praxis heißt das, dass man das Wissen über den Lifecycle einer Anwendung codiert. Dadurch erlauben Operatoren die Verwaltung und Skalierung von Stateless-Applikationen, wie Webanwendungen oder API-Services, ohne dass Sie über Kenntnisse zur Funktionsweise verfügen zu müssen. Auf diese Weise reduziert ein Operator die manuellen Aufgaben, die für die Verwaltung von Kubernetes Workloads nötig sind. Jedoch erfordert die Programmierung eines Operators die entsprechende Expertise.

FAQ

Was ist der Unterschied zwischen Deployments und StatefulSets?

Um Applikationen zu deployen, nutzt man in der Regel entweder Deployments oder StatefulSets. Der Unterschied zwischen Deployments und StatefulSets lässt sich historisch erklären: In der Anfangszeit beschränkte sich K8s auf Stateless-Applikationen. Mit der Zeit hat sich jedoch gezeigt, dass sich Stateful-Applikationen nicht mit Deployments abbilden lassen. Also Folge wurden die StatefulSets eingeführt.

Was sind Stateful- und Stateless-Applikationen?

Bei Stateful-Applikationen handelt es sich um Applikationen die Daten speichern und diese nachverfolgen. So sind Datenbanken wie MySQL, Oracle und PostgeSQL Beispiele für solche Anwendungen. Im Gegensatz dazu speichern zustandslose Anwendungen die Daten nicht, sondern verarbeiten die bei jeder Anfrage empfangen Daten jedes Mal aufs neue, indem sie diese beispielsweise an eine zustandsabhängige Applikation weiterreichen.

Wie erstelle ich ein Kubernetes-Deployment?

Deployments lassen sich mittels YAML oder JSON mit kubectl erstellen und verwalten. Die Befehlszeilenschnittstelle kommuniziert mit der Kubernetes-API, um mit dem Cluster zu interagieren. Sobald ein Pod des Deployments erstellt wurde, überwacht ein Kubernetes-Deployment-Controller diese Instanzen kontinuierlich. Fällt ein Node aus, auf dem eine Instanz läuft, ersetzt der Controller die Instanz durch eine neue auf einem anderen Node im Cluster. Dadurch bietet Kubernetes einen Selbstheilungsprozess, der Systemausfälle vermeiden soll.

Was ist der Horizontal Pod Autoscaler?

Wie der Name bereits vermuten lässt, skaliert der Horizontal Pod Autoscaler (hPA) automatisch die Anzahl der Pods von z. B. einem Deployment. Dabei zieht er die durchschnittliche CPU-Auslastung des zugewiesenen Ziels oder von der Anwendung bereitgestellte Metriken für die Autoskalierung heran. Auf diese Weise stellt der hPA sicher, dass bei Leistungsspitzen zusätzliche Pods gestartet werden und die Applikation weiterhin performant ist. Der hPA macht Kubernetes so vor allem bei Spitzenauslastungen besonders effektiv und bietet Schutz vor Systemausfällen.

Wichtig: Sie müssen bereits beim Erstellen des Deployments festlegen, ab welchem Wert der hPA neue Pods starten oder bestehende Pods löschen soll. 

Wie funktioniert Kubernetes-Monitoring?

Es gibt verschiedene Möglichkeiten, Kubernetes zu überwachen. Der Status von Applikationen lässt sich mit Health Endpoints einfach überprüfen. Tritt ein Problem auf, bietet Kubernetes mit kubectl ein Bordmittel an, um über die API zum Beispiel die Logs von Containern für ein Troubleshooting abzufragen. Wer tiefere Einblicke benötigt, etwa über Leistungsmetriken, muss zusätzliche Tools implementieren. Mit Kubernetes Dashboard gibt es zum Beispiel eine einfache Möglichkeit, Metriken zu visualisieren.

Wer ein holistisches Bild über sämtliche Aspekte der Kubernetes-Umgebung benötigt, sowie auf eine automatische Erkennung von problematischen Status und ein intelligentes Alerting nicht verzichten mag, ist mit einer Kubernetes-Monitoring-Software wie Checkmk gut beraten.