5. Kubernetes¶
Im fünften Teil der DVA-Serie wollen wir nochmal das Thema Docker aufgreifen, das wir bereits im zweiten Teil behandelt haben. Im zweiten Versuch hatten wir ein Hot Potato Spiel entwickelt, bei dem jeder Teilnehmer in einem eigenen Docker-Container läuft. Diese Teilnehmer kommunizieren über den Schiedsrichter, welcher für die Verwaltung des Spiels zuständig ist.
In diesem Versuch wollen wir uns diesem kleinen Spiel nochmal annehmen und es in einem Cluster verteilt implementieren. Und welches Tool wäre da besser als das Framework von Kubernetes? Richtig, keines. Versuchen wir also Schritt für Schritt uns der doch komplexen Logik von Kubernetes zu nähern.
Bemerkung
An dieser Stellen möchten wie auf unseren Zweiten Versuch Docker verweisen. Da wir dort bereits auf die Logik des Spiels sehr detailliert eingegangen sind, wollen wir in diesem Artikel darauf verzichten. Wenn Sie also den Zweiten Artikel noch nicht gelesen haben, sei dieser als Voraussetzung für diesen Teil empfohlen.
5.1. Was ist Kubernetes¶
Zu Beginn stellt sich also die Frage, was ist Kubernetes eigentlich und was kann ich damit konkret machen. Kubernetes ist eine Plattform, zur Bereitstellung, Skalierung und Verwaltung containerisierter Anwendungen. Mit Kubernetes können Sie Container in einem Cluster von Computern orchestrieren, indem Sie sicherstellen, dass die richtigen Container zur richtigen Zeit auf den richtigen Maschinen laufen. Kubernetes kümmert sich dann um die Ressourcenverteilung, Lastverteilung, Service Discovery, Skalierung und Wiederherstellung von Anwendungen, was die Verwaltung komplexer Anwendungen erheblich vereinfacht.
Kurz gesagt, Kubernetes hilft Ihnen, Anwendungen in Containern effizient und zuverlässig zu betreiben und zu verwalten, unabhängig davon, ob Sie eine kleine Anwendung oder ein großes, verteiltes System betreiben.
5.2. Projekt Kontext¶
Wie in der Einleitung kurz erwähnt, wollen wir das Hot Potato Spiel nochmal aufgreifen, um für diese Anwendung das Kubernetes Cluster zu installieren. Wir wollen hier klären, wie wir das Cluster auf unser Spiel abbilden und welche Instanz des Spiels wo zu finden ist.
5.3. Architektur¶
Wir wollen uns nun endlich mit der Architektur eines Kubernetes-Clusters vertraut machen und tiefer eintauchen in die Welt von Kubernetes. Wir beschreiben die verschiedenen Bestandteile von Kubernetes und versuchen auf jeden etwas genauer einzugehen, sodass klar wird für was jeder Teil zuständig ist.
Kubernetes verfügt im Grunde über ein config-File vom Type yaml. Wir wollen diese Datei getrennt betrachten um so den Überblick zu bewahren.
Node
Service
Deployments
Im Folgenden sehen wir uns alle drei Teil an.
Bemerkung
Zu Beginn sei gesagt, das wir ein lokales Cluster aufsetzten. Da wir nicht über mehrere Rechner verfügen nutzten wir ein Packages, dass es uns erlaubt ein Cluster lokal auf einem Rechner aufzusetzen, ohne physikalisch mehrere Rechner haben zu müssen. Das Package, was wir hier nutzen ist das minikube
Node und das Package *minikube*: Minikube ist ein Open-Source-Tool, das es ermöglicht, eine lokale Kubernetes-Umgebung zu erstellen und zu verwalten. Es ist ideal für Entwickler, die Kubernetes auf ihrem lokalen Rechner testen, entwickeln und debuggen möchten, ohne eine vollständige Kubernetes-Cluster-Infrastruktur aufsetzen zu müssen. In einer Container-Welt würde wir so eine Konfiguration als Single-Node-Cluster beschreiben.[MINIKUBE_DOKU] Minikube ist ein gängiges Package für das lokale Aufsetzten und Testen einer Anwendung, bevor dieses in ein tatsächliches Cluster übergeht.
Einen Service bereitstellen: Jede Kubernetes Anwendung benötigt einen Service. Dieser stellt sicher, dass die Anwendung von außen zugänglich ist.
apiVersion: v1
kind: Service
metadata:
name: hot-potato-service
spec:
selector:
app: hot-potato
ports:
- port: 8000
targetPort: 8000
type: LoadBalancer
Versuchen wir zu verstehen welcher Teil welche Aufgaben übernehmen. Hier werden in erster Linie wichtige Metadaten hinterlegt wie die Version und der Name der Anwendung. Die Selektoren haben die Aufgabe die dann die passenden Pods mit dem Label app: hot-potato herauszusuchen. Mit Ports können wir dem Service mitteilen, an welchen Port er die Daten weiterleiten soll. In unserem Beispiel ist es 8000. Das wohl wichtigste Merkmal eines Services ist der Typ. Dieser legt fest, um was für einen Typ von Service es sich handelt. Hier ist es ein LoadBalancer. Dieser ist dafür zuständig, die Anfragen von Außen an einen verfügbares Deployment weiterzuleiten. Was genau ein Deployment ist und wo es einzuordnen ist, sehen wir uns im nächsten Abschnitt an.
Deployments anlegen Ein Kubernetes Deployment stellt den größten Teil in einem Kubernetes-Cluster da. In ihm können wir die Pods definieren, in denen die eigentliche Anwendung läuft. Das Deployment-File scheint auf den ersten Blick sehr groß zu sein. Aber wenn wir es Schritt für Schritt ansehen, dann wird es etwas einfacher zu verstehen.
apiVersion: apps/v1
kind: Deployment
metadata:
name: hot-potato-deployment
spec:
replicas: 2
selector:
matchLabels:
app: hot-potato
template:
metadata:
labels:
app: hot-potato
spec:
restartPolicy: Always
volumes:
- name: shared-data
emptyDir: {}
containers:
- name: hot-potato
image: alexandervalerian/referee:depl
volumeMounts:
- name: shared-data
mountPath: /usr/src/app/logs
ports:
- containerPort: 8000
- name: player-one
image: alexandervalerian/player:test
volumeMounts:
- name: shared-data
mountPath: /usr/src/app/logs
command: ["/bin/sh"]
args: ["-c", "uvicorn player:app --reload --port=8001"]
- name: player-two
image: alexandervalerian/player:test
volumeMounts:
- name: shared-data
mountPath: /usr/src/app/logs
command: ["/bin/sh"]
args: ["-c", "uvicorn player:app --reload --port=8002"]
- name: player-three
image: alexandervalerian/player:test
volumeMounts:
- name: shared-data
mountPath: /usr/src/app/logs
command: ["/bin/sh"]
args: ["-c", "uvicorn player:app --reload --port=8003"]
Zu Beginn haben wir wieder Metadaten, wie wir sie auch schon aus dem Service kennen. Danach folgen Replikationen und Selektoren. Die Replikate geben an wie viel Kopien eines Pods zur Verfügung stehen. Replikate legen so fest, wie verfügbar eine Anwendung ist. Wenn beispielsweiße eine Pod ausfällt, kann bei zwei Replikaten immer noch der zweite einspringen.
Ein Selektor sorgt dafür das die richtigen Pods für die jeweilige Anwendung ausgewählt werden. Die Adresse der Pods kann einfach im entsprechenden Feld des Selektors angegeben werden.
Der nächste große Teil eines Kubernetes Deployments ist das Template. Hier kann genau beschrieben werden wie die Pods aussehen und was sie beinhalten. Dies ist unserer Ansicht nach der signifikanteste und interessanteste Teil. Werfen wir hier also einen genaueren Blick darauf. Innerhalb des Templates können wir festlegen, wie viel Container die Anwendung besitzt, wie jeder Container aussieht und was er genau tut. In unserem konkreten Beispiel wollen wir auch einen Blick auf den Bereich Volumen werfen. Hier finden wir auch einen Bereich mit shared-data. Um die Kartoffel zwischen den Instanzen hin und her zu werfen nutzten wir ein geteiltes Objekt, auf dass alle Spieler zugreifen können. Shared-data beschreibt dieses File. Unter Container finden wir dann die vier Instanzen der Spieler. Darunter ist auch der Schiedsrichter. Wir geben in der Containerkonfiguration an, dass jeder Spieler auf unser geteiltes Objekt zugreifen darf. Außerdem können wir über den Parameter args die nötigen Argumente mitgeben, die der Container benötigt und die normalerweise über das Terminal angegeben werden müssen, würde man die Spieler händisch starten.
Bemerkung
Hier sei nochmal auf unseren zweiten Versuch Docker verwiesen. Dort wird klar, warum genau diese args angegeben werden müssen. Sehen Sie sich dafür die Spiellogik genauer an.
Wir wissen nun über das wichtigste in Kubernetes Bescheid und haben uns einen Überblick verschafft, wie das Cluster aufgebaut werden kann. Es fehlt noch die Bedienung. Darüber wollen wir in unserem nächsten Kapitel sprechen.
5.4. Kubernetes bedienen¶
Kubernetes verfügt über den kube-control-manager. Dieser wird verwendet um die Befehle für ein Kubernetes-Cluster auszuführen. Zu Beginn müssen wir jedoch unseren minikube starten, den wir zu Beginn des Abschnittes Architektur angesprochen haben. Dies machen wir mit folgendem Befehl:
minikube start
Mit minikube status können wir immer den aktuellen Stand unseres minikubes einsehen.
minikube status
Ist unser minikube-cluster erfolgreich gestartet, so können wir den Kubernetes-Pod starten, indem wir den Kube-control-manager nutzen um die kubernetes.yaml Datei auszuführen.
kubectl apply -f kubernetes.yaml
Damit haben wir unseren Deployment gebaut und wir verfügen nun über einen lauffähigen Kubernetes-Pod. Im nächsten Schritt wollen wir dann das Cluster über unseren Service starten, den wir auch schon im Abschnitt Architektur beschrieben haben. Wir tippen also:
minikube service hot-potato-service
Damit ist unser Cluster aufgesetzt und einsatzbereit. Wir können nun damit fortfahren, dass wir unsere Anwendung starten, die wir in einem Cluster verteilen wollen. In unserem Fall ist es das Spiel Hot-Potato.
Wir möchten jedoch noch etwas weiter ausholen und eine Erweiterung von Kubernetes ansprechen. Das Paket k9s.
Bemerkung
Für das Starten der Anwendung wollen wir hier auf die README verweisen, dort können Sie genau nachverfolgen, wie Sie unsere konkrete Hot-Potato Anwendung starten können.
5.5. Das Paket k9s¶
Das Paket k9s für Kubernetes bietet eine terminalbasierte Benutzeroberfläche, die die Interaktion mit einem Kubernetes-Cluster erheblich erleichtert. Es hilft dabei, den Aufbau und die Funktionsweise von Kubernetes besser nachzuvollziehen, indem es eine klar nachvollziehbare visuelle Struktur bereitstellt. Durch die intuitive Darstellung ermöglicht k9s den Verzicht auf viele kubectl-Aufrufe, die sonst erlernt werden müssten, was den Umgang mit Kubernetes effizienter und benutzerfreundlicher macht.
Für uns als Einsteiger in die Welt von Kubernetes eine absolute Empfehlung. Wenn Sie also ebenfalls zu den Einsteiger gehöre, wollen wir ihnen das Packet ans Herz legen, da keine kubctl Befehle gelernt werden müssen und die Bedienung wirklich erheblich vereinfacht wird.
Die nachfolgende Grafik soll Sie ein bisschen auf den Geschmack von k9s bringen uns zeigen, wie diese UI aussieht.
Abb. 1 K9S User Interface¶
5.6. Mögliche Erweiterungen¶
Kubernetes ist ein wunderbares Spielzeug, wenn man erst verstanden hat, wie man es zu verwenden hat. Wir wollen in diesem Abschnitt noch ein paar mögliche Erweiterungen oder auch Spielereien vorstellen, die man mit einem Kubernetes-Cluster machen kann. Wir haben uns dafür entschieden einen Grafana Pod und einen Prometheus Pod zu integrieren um ein bisschen statistische Auswertungen über unser Cluster machen zu können. Sehen wir uns also beide Teile einmal an.
Grafana: Ist ein leistungsstarkes Analysetool zum Visualisieren und Darstellen von Daten. Man verfügt dort über ein Dashboard, auf dem dann die Auswertung dieser Daten einsehbar ist.
Prometheus: Ist ein Paket, das zur Überwachung von containerbasierten Anwendungen und Infrastrukturen verwendet wird. Damit lassen sich Metriken sammeln und im Nachhinein Analysen erstellen.
Der einfachste Weg Grafana und Prometheus zu installieren ist Helm zu verwenden. Helm ist ein Package-Manager für Kubernetes. Über ihn können sogenannte Helm Charts bzw. Pakete installiert werden. Der Begriff „Chart“ hat seine Wortherkunft übrigens von Karten aus der Seefahrt und hat an sich nichts mit Diagrammen zu tun wie der Name möglicherweise vermuten lässt. Der Einsatz von Helm Charts ermöglicht es, Anwendungen ohne großen Konfigurations-Overhead in einem vorhandenen Cluster zu deployen [HELM_HOMEPAGE] - so beispielsweise Prometheus und Grafana.
Dabei werden zum Beispiel beim Installieren des Prometheus-Helm-Charts sofort alle beobachtbaren Ressourcen (solche mit einem /metrics-Endpunkt) im Cluster identifiziert und deren Daten erfasst. Darüber hinaus werden mithilfe des Helm-Charts gleich weitere Dependencies installiert, die zusammenarbeiten, bspw. der Alertmanager (alertmanager), der auftretende Alerts trackt oder ein Service, der die Metriken von den Cluster-Endpunkten holt (kube-state-metrics) [PROMETHEUS_ARTIFACTHUB]. Alternativ müsste für jede dieser Ressourcen eine yaml-Konfiguration erstellt werden. Das Ziel von Helm-Charts ist es, diesen Mehraufwand zu reduzieren und sozusagen Plug-n-Play für Anwendungen der Kubernetes-Welt zu ermöglichen.
Zunächst müssen dazu die notwendigen Repositories geklont und geupdatet werden:
Dann werden die Helm Charts im Cluster installiert:
Schließlich werden die Cluster-Services der Außenwelt zugänglich gemacht, indem sie zu NodePorts umgewandelt werden:
Wie bereits mit unserem Hot-Potato-Service können wir den Prometheus Server und Grafana aufrufen, um zu deren Web-Nutzeroberflächen weitergeleitet zu werden:
Bemerkung
An dieser Stelle soll wieder auf die README verwiesen werden für eine Beschreibung, wie der Login bei Grafana funktioniert und wie mit wenigen Klicks Prometheus als Datenquelle verbunden werden sowie schließlich ein Dashboard mit den von Prometheus gesammelten Daten erstellt werden kann.
Mit dem so erstellten Dashboard kann die Input-Output-Belastung des Clusters beobachtet werden sowie die CPU-, Memory- und Filesystem-Nutzung. Mit nur wenigen Schritten erhält man so auf eine sehr einfache, aber effektive Art ein Überblick über die eigene Umgebung. Prometheus und Grafana sind für uns in Kombination machtvolle Tools, um die Gesundheit des Clusters im Blick zu behalten.
5.7. Erfahrungen/Fazit¶
Kubernetes ist ein sehr mächtiges, jedoch auch komplexes Tool. Erfahrungen, die wir im Docker-Projekt gemacht haben, halfen uns sehr beim Einstieg in Kubernetes. Dennoch ist Kubernetes für Anforderungen wie schnelles Prototyping ungeeignet. Mit einer Docker-Compose konnten wir dasselbe Ziel in sehr viel kürzerer Zeit erreichen.
Trotz der Komplexität macht die Nutzung von Kubernetes Spaß, und es entsteht das Gefühl eines echten DevOps. Allerdings ist die Lernkurve steil, besonders aufgrund der Vielzahl an unterschiedlichen Port- und IP-Typen wie port, targetPort, NodePort, Cluster-IP und Node-IP. Dennoch ermöglichen Parameter wie replicas und restartPolicy eine sehr robuste Anwendungsarchitektur zu kreieren.
Zudem waren wir begeistert davon, welche Möglichkeiten die Verwendung von Helm-Charts in Kubernetes Clustern eröffnen. Mit wenigen Schritten kann mithilfe eines Charts eine völlig neue Funktionalität in ein Cluster eingebaut werden, was es einfach macht, neue Dinge auszuprobieren.
5.8. Literatur¶
Helm: (abgerufen am 04.06.2024): https://helm.sh/
Dokumentation: (abgerufen am 01.06.2024): https://kubernetes.io/de/
Dokumentation: (01.06.2024): https://k9scli.io/
Dokumentation: (abgerufen am 03.06.2024): https://minikube.sigs.k8s.io/docs/
Dokumentation: (abgerufen am 04.06.2024): https://artifacthub.io/packages/helm/prometheus-community/prometheus