Softwareentwicklung auf lokalen Kubernetes Clustern

Softwareentwicklung auf lokalen Kubernetes Clustern

Kurzeinführung in Container & Kubernetes

Container sind, im einfachsten Sinne, Prozesse auf einem Hostsystem, die zwar, ähnlich zu virtuellen Maschinen, voneinander isoliert sind (in sogenannten Namespaces), sich aber den gemeinsamen Betriebssystem-Kernel teilen.
Dabei beinhaltet ein Container sein eigenes Dateisystem, sodass eine App als eine Einheit mit all ihren Abhängigkeiten (Programmbibliotheken, Werkzeuge, Konfigurationsdateien, etc.) verteilt werden kann, ohne vom Hostsystem abhängig zu sein.
Somit können viele verschiedene Container mit Hilfe einer Container Runtime wie Docker¹ auf einem einzigen Host laufen und relativ problemlos auf andere Hosts umgezogen werden.
Aus Google’s interner Software Borg heraus entstanden ist Kubernetes im Grunde ein Container-Orchestrierungs-System, welches mehrere Abstraktionsebenen einführt, um den Lebenszyklus mehrerer Container auf einer Gruppe (Cluster) von Hosts (Nodes) zu verwalten. Dabei kann es z.B. Serverausfälle mitigieren, indem die ebenfalls abgestürzten Container auf einer anderen Node im Cluster wieder neu gestartet werden.
Kubernetes wird deklarativ verwaltet, d.h. als Entwickler oder Betreiber übergibt man Kubernetes einen Zielstatus des Systems (bspw. wie viele App-Container sollen laufen, wie kann darauf über das Netzwerk zugegriffen werden, usw.) und Kubernetes kümmert sich darum, dass dieser Status erreicht wird und anschließend erhalten bleibt (Reconciliation).

Der Zielstatus wird meist in Manifesten (YAML Dokumente) abgespeichert, die jeweils einem Kubernetes API Objekt entsprechen, bspw. einem Pod oder einem Deployment

Die Darstellungen sind weiterhin stark vereinfacht und sowohl das Konzept der Container als auch die Software Kubernetes haben noch viel mehr zu bieten.

 „Es läuft auf meiner Maschine, aber es funktioniert nicht im Produktionscluster“

Kubernetes entwickelt sich in den letzten Jahren mehr und mehr zum Defacto-Standard in der Orchestrierung von containerisierten Applikationen.

Während sich die Plattform in der Produktionsumgebung auf gut ausgestatteten Servern bei Google, Amazon & Co. oder im eigenen Rechenzentrum ausbreitet, bleibt die Entwicklungs- und Testumgebung auf den Laptops der Entwickler oft gleich.

Ist das Arbeitsumfeld bereits seit längerem in die Welt der Container eingestiegen, so findet sich dort meist Docker und dessen Mini-Orchestrierungs-Tool docker-compose.

Aufgrund seiner vielfältigen Features und simplen Handhabung funktioniert dieses Setup meist sehr gut, allerdings unterscheidet es sich auch immer stärker von der Produktionsumgebung in welcher die Apps letztendlich laufen sollen.

Diese Differenz zwischen lokaler Entwicklungs- und Testumgebung und den entfernten Kubernetes Clustern kann spätestens beim Deployment oder auch schon beim Ausarbeiten der Kubernetes Manifeste einiges an Kopfzerbrechen bereiten.

Dem DevOps-Prinzip folgend, wird mehr Verantwortung über den gesamten Software-Lebenszyklus auf den Entwickler übertragen und so wird auch die erforderliche Kenntnis über die Laufzeitumgebung der Applikation wichtiger. In dieser Situation bekommt man sowohl als Softwareentwickler als auch als Betreiber des Clusters mehr und mehr die Unterschiede zwischen „Es läuft auf meiner Maschine“ und „Es funktioniert nicht im Produktionscluster“ zu spüren. Dann zusätzlich noch sehr unterschiedliche Konfigurations- und Deployment-Dateien für beide Bereiche zu pflegen (bspw. docker-compose Konfiguration + Kubernetes Manifeste) kostet mehr Zeit und mentalen Einsatz als nötig sein sollte.

Daher ergibt es Sinn, die lokale Entwicklungsumgebung so ähnlich wie möglich zur Produktionsumgebung zu gestalten, sodass nahezu identische Konfigurationen und Deployment-Manifeste verwendet werden können.

Damit schrumpft am Ende der Unterschied zwischen Entwicklung und Produktion im Zweifel auf eine Manifestvorlage mit zwei Gruppen an Werten für die lokale und für die Produktionsumgebung, die lediglich je nach Einsatzort in die Vorlage eingesetzt werden bzw. diese erweitern müssen. Für diese Aufgabe haben sich bereits Tools wie Helm und Kustomize bewährt.

Somit sind einige der Vorteile der Anpassung der Entwicklungs- an die Produktionsumgebung klar, aber es stellt sich noch die Frage, ob die Entwicklungsumgebung wirklich auf dem eigenen Laptop laufen muss.

Für die Entwicklung auf und für Kubernetes gibt es eine große Auswahl an Möglichkeiten und so kann man seine App beispielsweise direkt im firmeneigenen Cluster, in temporären Clustern in der öffentlichen Cloud, in gemieteten Entwicklungs- bzw. Testumgebungen eines Software-/Platform-as-a-Service (SaaS/PaaS) Anbieters oder sogar direkt im Produktionscluster, in einem separaten Namespace, entwickeln und testen.

Damit bleiben die Laptop-Ressourcen größtenteils verschont und die Power der Serverfarmen kann gut ausgenutzt werden ohne dass man den eigenen Rechner wegen Überhitzung in den Kühlschrank stellen muss.

Vorteile lokaler Kubernetes Cluster

Warum also konzentrieren wir uns in diesem Artikel primär auf die Entwicklung und Testung auf lokalen Kubernetes Clustern, die direkt auf dem Entwicklergerät laufen?

Einige Vorteile dieser Variante sind die nicht vorhandenen Latenzzeiten bei der Kommunikation mit dem Cluster, die Möglichkeit, auch auf dem Nachhauseweg in der S-Bahn ohne Internetempfang noch schnell ein paar Tests durchzuführen und die Cluster auch ohne eventuell benötigten Admin-Zugriff auf die Serverumgebungen nach belieben anzupassen, zu zerstören und neu aufzuziehen.

Damit bei der Aufzucht einer oder mehrerer lokaler Cluster trotzdem noch der Internetbrowser funktioniert und der Laptop nicht unter der Last eines voll ausgewachsenen Kubernetes Clusters in die Knie geht, bedarf es angepasster Lösungen.
Dazu wurden bereits von verschiedenen Gruppen einige frei verfügbare Tools und leichtgewichtige Kubernetes Distributionen entwickelt, die sich speziell an Entwickler richten oder für Umgebungen mit wenig Hardware-Ressourcen optimiert sind.

Zu den bekanntesten Optionen zählen hier Minikube und kind (Kubernetes in Docker), welche Teil zweier Kubernetes SIGs (Special Interest Groups) sind, sowie Canonical’s MicroK8s, Mirantis‘ k0s (k0sproject) und SUSE Rancher’s K3s („Five less than Kubernetes“) zusammen mit dem Community-Projekt k3d (K3s in Docker).

All diese Optionen stellen vollkommen konforme Kubernetes Distributionen bereit.
Jedoch wurden bspw. K3s und k0s im Kern angepasst, um weniger Ressourcen zu beanspruchen und so neue Einsatzgebiete (IoT, Edge Computing) zu ermöglichen.
Trotzdem warten alle aufgezeigten Lösungen auch mit einigen Erweiterungen rund um Kubernetes auf (etwa Automatische Upgrade Mechanismen oder “vorinstallierte” Software), um die Bedienung zu erleichtern.

Kubernetes neben Linux so auch auf MacOS und Windows

Während K3s und k0s als leichtgewichtige Binaries gepackt sind und direkt und ohne Isolierung auf dem Hostsystem laufen, wodurch sie derzeit einen Linux-Host voraussetzen, setzen Tools wie Minikube oder auch Rancher Desktop auf virtuelle Maschinen, in welcher sie unberührtes Kubernetes respektive K3s installieren, sodass sie auf jedem Hostsystem bereitstellbar sind.

MicroK8s, kind und k3d setzen auf containerisierte Kubernetes Distributionen, wobei MicroK8s mit Canonical’s snapd und kind sowie k3d mit Docker betrieben werden.

Docker (und auch snapd) wiederum kann auf jedem beliebigen Hostsystem unter anderem mithilfe einer virtuellen Maschine (Docker for Desktop) bereitgestellt werden.

Durch die Isolierung der Kubernetes Nodes in einzelnen Container und ggf. der Cluster weiterhin in verschiedenen virtuellen Netzwerken, ist es mit diesen Lösungen möglich mehrere Cluster nebeneinander auf einer Maschine laufen zu lassen, wobei diese Cluster wiederum aus einer oder mehreren Nodes bestehen können.

Ein weiterer Vorteil der containerisierten Lösungen ergibt sich dadurch, dass sie keine virtuelle Maschine benötigen (abgesehen von ggf. der Docker VM in Docker for Desktop auf Windows und MacOS) und somit sehr geringe Startzeiten haben, gleichzeitig aber trotzdem ein einfaches Löschen der Cluster jede Datenspur der Container vom Rechner entfernt.

Diese Schnelllebigkeit der Cluster verbunden mit der einfachen und sauberen Nutzung macht sie besonders interessant für die lokale Entwicklung auf und für Kubernetes.

Hürden bei containerisierten Clustern und wie man sie überwindet

Doch auch hier gibt es einige Hürden, die auf verschiedenen Wegen mehr oder weniger überwunden werden können.

Bei den containerisierten Clustern bspw. läuft auf dem Entwicklerlaptop Docker als Container Runtime, während innerhalb der Node-Container mit (meist) einfachem containerd² eine andere Container Runtime läuft, sodass z.B.ein Container Image, welches in der lokalen Docker Umgebung gebaut wurde, nicht direkt im containerisierten Cluster zur Verfügung steht.

Hier muss dann der Umweg über die Importierung der Images, über eingebaute Lösungen wie k3d image import oder Drittanbieter-Tools wie Skaffold und Tilt gehen oder aber über eine Image Registry, welche lokal oder entfernt betrieben wird, gehen. Das führt zu mehr oder weniger kurzen Wartezeiten im Entwicklungsablauf.

Dieses Problem kann unter anderem bei interpretierten Sprachen wie Python umgangen werden, indem man den Programmcode direkt über Volumes bzw. Bind-Mounts in das Cluster und von dort in die Kubernetes Pods bzw. App-Container im Cluster einbindet, was die Möglichkeit von direktem Nachladen des Codes (Live-Reloading oder Hot-Reloading) einbringt.

Weitere Hürden ergeben sich bei der Verwendung bestimmter Kubernetes Objekte wie z.B.  Services vom Typ LoadBalancer, welche aber ebenfalls durch eingebaute Lösungen wie dem Serviceloadbalancer Klipper oder Drittanbieterlösungen wie MetalLB mitigiert werden können.

Lokale Kubernetes Cluster nicht nur für Entwickler, sondern auch Betreiber interessant

Davon abgesehen bieten lokale Kubernetes Cluster nicht nur Entwicklern, sondern auch Betreibern von Kubernetes Clustern interessante Optionen.

Während natürlich die Option besteht mit den „großen“ Kubernetes Clustern in der Cloud Umgebung herumzuprobieren, bieten auch die „kleinen“ Cluster auf dem Laptop die Möglichkeit, einige Kubernetes Konzepte durchzuspielen. Durch das stoppen eines einzelnen Node-Containers kann der Absturz eines Servers im Cluster simuliert werden und man kann beobachten, wie Kubernetes und seine Komponenten, wie z.B. etcd darauf reagieren, den Fehler mitigieren und den vorherigen Status des Clusters mit einer nun fehlenden Node wiederherstellen.

So kann auch die Ausfallsicherheit bzw. Resilienz einer App oder auch der „Blast Radius“ eines Serverausfalls ganz schnell auf dem eigenen Laptop simuliert werden, ohne dafür einen Server oder eine virtuelle Maschine herunterzufahren.

Fazit

Während sich die Anwendungsfälle, Hürden sowie Vor- und Nachteile zwischen den einzelnen Lösungen und insbesondere zwischen der Entwicklung/Testung auf entfernten und lokalen Kubernetes Clustern teils stark unterscheiden, so bringen doch alle Varianten die Vorteile einer Entwicklungs- und Testumgebung mit sich, die der letztlichen Produktionsumgebung maximal ähnelt und so den Feedback Zyklus klein und schnell hält und Überraschungen beim Deployment verringert.

Fußnoten
¹ Container Runtime ist hier im Detail das falsche Wort. Docker verschiedene Komponenten, von welchen mehrere (wie containerd und runc) die eigentliche Runtime aufbauen.
² Auch Docker läuft intern mit containerd, aber in angepasster Form, sodass bspw. der Image Layer Cache nicht zwischen containerd im Cluster und Docker geteilt werden kann

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.

Nachrichten und Ratgeber für IT Freelancer  

   + kostenlos

   + kompakt

   + monatlich

   + spamfrei

Das Neueste zum Wettbewerb 'IT Freelancer des Jahres'

Newsletter des IT Freelancer Magazins