Select Page

NETWAYS Blog

Kubernetes 101: Die nächsten Schritte

This entry is part 7 of 7 in the series Alles rund um Kubernetes

Im Laufe des letzten Jahres haben wir uns in dieser Blogserie ausführlich mit Kubernetes beschäftigt. Von leicht verständlichen Erklärungen zu Design und Funktionsweise über den Aufbau eines ersten (lokalen) Clusters bis hin zur Inbetriebnahme und Absicherung haben wir viele Aspekte behandelt.
Im besten Fall konntest du erste Erfahrungen zu sammeln und vielleicht schon die eine oder andere Anwendung eigenständig bereitstellen. Die naheliegende Frage ist nun, “wohin” geht die Reise von hier aus?

In diesem letzten Artikel unserer Serie werde ich daher einige Ausblicke geben. Was ist im täglichen Betrieb zu beachten? Wie wird das System heute noch genutzt? Und welche neuen Einsatzmöglichkeiten zeichnen sich gerade ab? Vielleicht ist ja der eine oder andere Anwendungsfall auch für dich interessant!

Kubernetes im Alltagsbetrieb

Nachdem du dein(e) Cluster eingerichtet hast, beginnt der Alltagsbetrieb in der schicken, neuen Cloud-nativen Umgebung. Und hier kann es (ungewollt) spannend werden! Die verteilte Architektur und das generelles Design erfordern eine andere Herangehensweise als in traditionellen IT-Umgebungen. Insbesondere beim Monitoring bzw. Observability oder beim Backup-Management.

Werden Anwendungen auf Kubernetes betrieben, reicht es nicht aus, nur die laufenden Anwendungen zu sichern und in das Monitoring einzubinden. Man muss sich auch um die zugrundeliegende Infrastruktur kümmern! Die Gründe hierfür sollten klar sein: Verliert man die Zustandsinformationen der Kubernetes-API in etcd, ist ein Betrieb nicht mehr möglich. Ist der Cluster selbst kompromittiert, sind auch die darauf laufenden Applikationen in Gefahr. Es gilt also, aufzupassen und vorzusorgen.

Zum Thema Sicherheit auf gibt es in dieser Blogserie bereits einen eigenen Beitrag, die wichtigsten Punkte möchte ich aber noch einmal zusammenfassen:
Anwendungen auf Kubernetes werden in der Regel als containerisierte Microservices betrieben, die über das clusterinterne Netzwerk miteinander kommunizieren. Eine entsprechende Absicherung der verwendeten Netzwerke, sowohl an den Clustergrenzen als innerhalb des Clusters, ist daher zwingend erforderlich. Hierzu gibt es die Möglichkeit der nativen Fähigkeiten von Kubernetes selbst (Stichwort NetworkPolicies) oder man greift auf externe Tools zurück, die in ihrem Funktionsumfang weniger eingeschränkt sind (z.B. CNIs wie Cilium oder Calico).

Darüber hinaus sollten auch die betriebenen Container selbst unter die Lupe genommen werden: Nutzen sie vulnerable Abhängigkeitenbenötigen sie alle zugewiesenen Privilegien, und wie sieht es mit der Aktualität der Images selbst aus? Für all diese Fragen gibt es Tools, die die Umsetzung erleichtern – von Imagescannern wie Trivyoder Docker Scoutbis zur Echtzeiterkennung von Sicherheitsproblemen mit NeuVector von unserem Partner SUSE.

Das Ökosystem bietet auch Lösungen für das Backup-Management: Angefangen bei Kasten, einer Enterprise-Backuplösung von Veeam, über Velero, einer FOSS-Lösung für Backups von Clusterzustand und PersistentVolumes, bis hin zu Kanister (ebenfalls von Veeam), das Backup-Management auf Anwendungsebene ermöglichen soll.
Je nach Anwendungsfall und Clusterspezifikationen (Anzahl an Nodes, onPrem vs. Cloud, etc.) wirst du dich wahrscheinlich für eine bestimmte Backup-Lösung und einen speziellen Ansatz für das Backup-Management wählen.
Mit den genannten Lösungen kannst du aber definitiv deine ersten Schritte gehen.

Kubernetes als Infrastruktur-Plattform

Ein stetig wachsender Anwendungsfall ist der Einsatz als zentrale Infrastruktur-Management-Plattform. Dank zahlreicher (Open-Source-) Projekte im Cloud-nativen Ökosystem ist Crossplane heute in der Lage, Ressourcen wie S3-Buckets, Cloud-VMs oder gemanagte Datenbanken in verschiedenen Public Clouds zu provisionieren und zu verwalten.

Du kannst das System auch als Hypervisor für deine VM-Flotte verwenden Möglich macht dies das Projekt kubeVirt, das KVM-VIrtualisierung auf Kubernetes bringt – alles unter einem Dach, quasi! kubeVirt selbst ist ein Projekt innerhalb der CNCF, das unter Anderem von namhaften Firmen wie SUSE, RedHat oder ARM unterstützt wird.

Kubernetes als Management-Plattform

Doch nicht nur für Infrastruktur kann Kubernetes als Plattform herhalten. Es bietet auch die Möglichkeit, dass andere Benutzer in der Organisation die zentrale Schnittstelle für Ihre tägliche Interaktion mit eurer IT-Landschaft werden. Das Schlagwort für diese Art der Nutzung lautet Internal Development Platform (IDP) und ist eines der Themen, die derzeit stark im Kommen sind:
Vorgelebt von Spotify und seiner modularen Plattform Backstage gibt es mittlerweile eine ganze Reihe von kommerziellen und nicht-kommerziellen Lösungen, die Entwicklern in Zeiten von SaaS-Lösungen und immer komplexeren Entwicklungsumgebungen helfen können, den Überblick zu behalten.

Ziel von IDPs ist es, verschiedene Informationen rund um den Entwicklungszyklus zusammenzuführen, Prozesse zu vereinheitlichen und “Golden Paths” zu etablieren. Mit seiner mächtigen API und seinen Orchestrierungsmöglichkeiten bietet sich Kubernetes für so ein Vorhaben an. Schließlich sollen verschiedenste Drittanwendungen mit der Plattform interagieren, Informationen bereitstellen und im Gegenzug Anweisungen von der Plattform erhalten. Nicht umsonst ist das Thema “Kubernetes als IDP” also eines der derzeit “heißesten” Themen auf Konferenzen wie z.B. der KubeCon.

Fazit

Kubernetes wird nicht langweilig und bietet viele Möglichkeiten zur Erweiterung und zum Ausbau. Das ist ein bisschen Fluch und Segen zugleich. Denn mit den Vorteilen entstehen auch neue Risiken. Es kann sinnvoll sein klein anzufangen, sein(e) Cluster nach und nach zu erweitern und an neue Anwendungsfälle anzupassen.
Eine der wichtigsten Regeln ist, von der ersten Minute an Sicherheit und Observability zu bedenken. Das Risiko einer unentdeckten Schwachstelle ist ansonsten aufgrund der verteilten Architektur und den darauf laufenden Anwendungen schwer zu überblicken.

Wenn du nach der Lektüre dieser Serie Lust bekommen hast loszulegen, du dich aber noch nicht zu 100% bereit fühlst direkt loszulegen, ist vielleicht unser Kubernetes Training etwas für dich!
Ansonsten kannst du jederzeit unser Sales Team kontaktieren, und mit einem unsere Kubernetes-Spezialisten über deine Fragen sprechen.

Daniel Bodky
Daniel Bodky
Platform Advocate

Daniel kam nach Abschluss seines Studiums im Oktober 2021 zu NETWAYS und beriet zwei Jahre lang Kunden zu den Themen Icinga2 und Kubernetes, bevor es ihn weiter zu Managed Services zog. Seitdem redet und schreibt er viel über cloud-native Technologien und ihre spannenden Anwendungsfälle und gibt sein Bestes, um Neues und Interessantes rund um Kubernetes zu vermitteln. Nebenher schreibt er in seiner Freizeit kleinere Tools für verschiedenste Einsatzgebiete, nimmt öfters mal ein Buch in die Hand oder widmet sich seinem viel zu großen Berg Lego. In der wärmeren Jahreszeit findet man ihn außerdem oft auf dem Fahrrad oder beim Wandern.

Kubernetes 101: Wie sichere ich Kubernetes ab?

This entry is part 6 of 7 in the series Alles rund um Kubernetes

In meinen bisherigen Blogposts habe ich dir bereits einige wichtige Aspekte von Kubernetes näher gebracht. Von “Was ist Kubernetes” über “Wie richte ich Kubernetes auf Linux ein” zu “Wie installiere ich eine Anwendung in Kubernetes”. Im besten Fall hast du nun bereits Erfahrung in einer laufenden Umgebung sammeln können und bist bei der sogenannten “Day 2 Operation”, also dem alltäglichen, laufenden Betrieb angekommen. Eine Sache, die ich bisher allerdings ein wenig vernachlässigt habe, ist die Absicherung eines Kubernetes Clusters und der darin befindlichen Workloads.
In diesem Punkt ist Kubernetes‘ offener Standard Fluch und Segen gleichzeitig: Während die einfach erweiterbare Funktionalität ein großes Plus von Kubernetes ist, ist das Fehlen (fast) jeglicher Konfiguration von Security und Policing “out of the box” definitiv ein großes Minus.
Deswegen zeige ich dir in diesem Beitrag, wie du in diesem Bereich nachbesserst!

Wie ist Kubernetes aufgebaut?

Wenn du meine bisherigen Blogposts verfolgt hast (oder bereits Erfahrung mit Kubernetes gesammelt hast) weißt du: Kubernetes ist ein verteiltes System.
Auf mehreren Nodes werden containerisierte Workloads geplant, die dann die eigentlichen Anwendungen ausführen. Hinzu kommen je nach Kubernetes-Distribution mehrere lokal auf dem jeweiligen Node laufende Services (bspw. Kubelet, kube-apiservercontainerd, etc.) sowie Container, die aufgrund ihrer Aufgaben manchmal erweiterte Privilegien auf den Nodes genießen. Etwa um den clusterinternen Netzwerkverkehr zu regeln oder im Cluster verteilten Speicher bereitstellen zu können.
Es gibt also eine einigermaßen klare Trennung zwischen Clusterinfrastruktur und Workloads, die in einer idealen Welt auch nur wenig miteinander zu tun haben (sollten). Eine Anwendung sollte schließlich in der Lage sein, ordnungsgemäß laufen zu können, ohne dass sie Kenntnisse über ihre Laufzeitumgebung (in diesem Fall Kubernetes) besitzt.
Wie klar diese Trennung in der Realität auch ausfallen mag, im Folgenden werde ich die zwei Welten und mögliche Ansatzpunkte für mehr Sicherheit getrennt voneinander betrachten.

Clustersicherheit bei Kubernetes

Wie bereits eingangs erwähnt, ist ein Kubernetes Cluster nach seiner Installation nicht unbedingt umfassend abgesichert – das beginnt bereits beim Zugriff auf das Kubernetes Cluster. Die kubeconfig, mit der du als Admin normalerweise arbeitest, ist mit maximalen Privilegien ausgestattet und sollte unter keinen Umständen verteilt oder von anderen Nutzern verwendet werden.
Deshalb solltest du weiteren User:innen einen alternativen Clusterzugriff (und damit verknüpfte Regeln) einrichten.

Zugriff und Zugriffskontrolle einrichten

Von Haus aus besitzt Kubernetes ein feingranular einstellbares RBAC-System (Role-based Access Control), mit dem sich grundsätzlich gut arbeiten lässt: Mittels (Cluster-)Roles, (Cluster-)RoleBindings und Usern bzw. ServiceAccounts lassen sich Verknüpfungen zwischen beliebigen Sets an Privilegien und einzelnen, im Cluster agierenden, Identitäten herstellen.
Für jede Gruppe an existierenden API-Objekten können durch Verbs die Privilegien entweder auf Namespace– oder auf Cluster-Ebene eingestellt werden. Die verfügbaren Verbs sind getlistcreateupdatepatchwatchdelete, und deletecollection und implizieren verschiedene Privilegien für die verknüpften API-Objekte.

Möchtest du eine hierarchische Struktur mehrerer Rollen erreichen, kannst du mehrere Clusterrollen zu einer übergeordneten Clusterrolle aggregieren. Auf diese Weise behältst du den Überblick, auch wenn die Anzahl an verfügbaren Rollen mit der Zeit wachsen sollte.
Überblick ist zudem ein gutes Stichwort, denn ab einer gewissen Anzahl an Rollen, Nutzern und Verknüpfungen zwischen den beiden Konzepten leidet unweigerlich die Übersichtlichkeit des Berechtigungskonstrukts. Zwar liefert Kubernetes’ CLI kubectl mit dem Cmdlet auth can-i eine Möglichkeit des Auditings mit (siehe Auflistung aller Berechtigungen des Standard-Adminusers für den Namespace default unten), das Gelbe vom Ei ist dieser Ansatz der Nutzerverwaltung ab einer gewissen Clustergröße nicht mehr.

Oder möchtest du regelmäßig für alle User deines Clusters manuell die Berechtigungen prüfen?

kubectl auth can-i --list --namespace=default
Resources                                       Non-Resource URLs   Resource Names   Verbs
*.*                                             []                  []               [*]
                                                [*]                 []               [*]
selfsubjectaccessreviews.authorization.k8s.io   []                  []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                  []               [create]
                                                [/api/*]            []               [get]
                                                [/api]              []               [get]
                                                [/apis/*]           []               [get]
                                                [/apis]             []               [get]
                                                [/healthz]          []               [get]
                                                [/healthz]          []               [get]
                                                [/livez]            []               [get]
                                                [/livez]            []               [get]
                                                [/openapi/*]        []               [get]
                                                [/openapi]          []               [get]
                                                [/readyz]           []               [get]
                                                [/readyz]           []               [get]
                                                [/version/]         []               [get]
                                                [/version/]         []               [get]
                                                [/version]          []               [get]
                                                [/version]          []               [get]

 

Eine bessere Verwaltungsmöglichkeit für unsere Kubernetes Cluster User ist also dringend angeraten, sowohl aus Gründen der Übersichtlichkeit als auch der Sicherheit. Bei immer mehr Nutzern und komplexeren Berechtigungsstrukturen ist es sonst nur eine Frage der Zeit, bis bei einem Nutzer die falschen Berechtigungen gesetzt werden. Schaut man sich das Angebot an verfügbaren Lösungen für Zugriffskontrolle auf Kubernetes an, stechen ein paar Projekte heraus:

Als SUSE Partner setzen wir bei mehreren Kunden erfolgreich Rancher ein, ein Open-Source Tool zur ganzheitlichen Verwaltung von Clustern in der Cloud und on premise. Rancher setzt mit seinem Berechtigungskonzept direkt auf Kubernetes’ RBAC-Modell auf und erweitert es um Projekte, die eine Abstrahierung um einen oder mehrere Namespaces bilden.
Das Web-Frontend bietet die Möglichkeit, (Cluster-)Rollen mit einzelnen Usern oder Usergruppen aus der in Rancher integrierten Benutzerverwaltung zu verknüpfen, zu auditieren und sich einen schnellen Überblick darüber zu verschaffen, welcher User in welchem Cluster welche Berechtigungen hat.

Grundlage für das Berechtigungskonzept sowohl in Rancher’s WebUI als auch in den verwalteten Clustern bieten die vielen verschiedenen Authentifizierungsplugins: Rancher unterstützt LDAP (z.B. Active Directory, OpenLDAP, AzureAD), OAuth (z.B. Google, GitHub), OIDC (z.B. Keycloak) und SAML (z.B. Okta, Shibboleth, ADFS).

Ein weiteres bewährtes Tool zur Zugriffskontrolle für u.A. Kubernetes ist Teleport, das ebenfalls eine Open-Source Software ist und kostenlos genutzt werden kann. Teleport fungiert als vorgelagerter Proxy, der die Anfragen an das Cluster terminiert, den Nutzer authentifiziert und authorisiert und diese Anfragen dann weitergibt. Stärken von Teleport sind zum Beispiel Policy-as-Code, umfangreiche Auditierbarkeit aller Zugriffe und vergangenen Sitzungen sowie die Kompatibilität nicht nur mit Kubernetes, sondern auch anderen gemanagten oder selbst betriebenen Services und Cloudressourcen.

Netzwerkabsicherung bei Kubernetes

Die Zugriffskontrolle für Endnutzer und Serviceaccounts, also handelnde Identitäten, haben wir nun abgearbeitet. Doch wie steht es mit Zugriffsversuchen, die von Services inner- und außerhalb des Clusters stammen und anderweitig beschränkt werden müssen? Schließlich besteht je nach Architektur und genutzten Dritt-Tools selbst ein “leeres” Cluster aus (bis zu) mehreren hundert Containern, die untereinander kommunizieren (wollen), sich Updates aus dem Internet ziehen oder andere Services innerhalb der Infrastruktur deines Unternehmens (z.B. AD-Server) erreichen müssen.

Per Default können all diese Container das auch erst einmal ungestört. Kubernetes besitzt out-of-the-box kein Konzept einer “Firewall” oder ähnlicher Maßnahmen, die den Netzwerkverkehr einschränken könnte. Weder in Ost-West, noch in Nord-Süd-Richtung, übrigens. Hierfür bedarf es eines Container Network Interfaces (CNI), das in der Lage ist, NetworkPolicies zu interpretieren und umzusetzen.
NetworkPolicies sind ein natives Konzept der Kubernetes-API, deren Umsetzung aber an externe CNIs übergeben wird. Ohne passendes CNI also keine Einschränkung des Netzwerkverkehrs.

Das Angebot an verfügbaren CNIs ist recht groß, beliebte Lösungen mit Support für NetworkPolicies auf Namespaceebene und teilweise einer ganzen Bandbreite weiterer Features (BGP-Routing, Nodefirewall, Networkpolicies auf Clusterebene) sind bspw. Cilium bzw. Calico.

“Best Practices” für das Einrichten von Networkpolicies in Kubernetes gibt es wie Sand am Meer. Welche Blaupause für dein Unternehmen sinnvoll und geeignet sein könnte, ist meist eine Einzelfallentscheidung. Ein oft gesehenes Muster ist eine “globale” NetworkPolicy über alle Namespaces hinweg (das CNI muss dieses Feature mitbringen!), die keinerlei Ingress bzw. Egress bis auf Anfragen an den clusterinternen DNS-Service erlaubt.
Auf diese Weise sperrst du sämtlichen Netzwerkverkehr, der nicht innerhalb eines einzigen Namespaces stattfindet und etablierst ein “Opt-in”-Modell, bei dem die Operatoren der Anwendungen bei Deployment die benötigten Networkpolicies mitdeployen müssen. Einziges Caveat hierbei ist, dass eventuell bereits vorhandene Infrastruktur im Cluster natürlich ebenfalls von den Regelungen betroffen ist.  Es ist deshalb ratsam, dass also ein etwas genauerer Namespace-Filter als “alle Namespaces” zum Einsatz kommt.

Ressourcenverwaltung in Kubernetes

Ein weiterer wichtiger Punkt neben Zugriffskontrolle und Netzwerkpolicies ist das Verwalten der im Cluster vorhandenen Ressourcen. Der Grund hierfür ist einfach – hat ein Pod die Möglichkeit, alle Ressourcen eines Nodes für sich zu beanspruchen, nimmt er allen anderen Workloads auf diesem Clusternode buchstäblich die Luft zum Atmen. Doch nicht nur “herkömmliche” Ressourcen wie Arbeitsspeicher und CPUs sollten reguliert sein – auch abstraktere Dinge wie PIDs oder Sockets können zum Problem werden – die in Pods laufenden Container befinden sich schließlich nach wie vor in Namespaces des jeweiligen Nodes. Spielt ein Container verrückt, kann das unangenehme Nachwirkungen für den gesamten Node nach sich ziehen. So kann beispielsweise mit einer Fork Bomb ein Denial of Service (DoS) erreicht werden.

Fälle wie oben beschrieben gilt es natürlich zu unterbinden – für Arbeitsspeicher und CPUs lässt sich das entweder auf Container– oder Namespaceebene umsetzen: Für Container innerhalb eines Pods können unterhalb des Felds resources sowohl requests als auch limits gesetzt werden. Was hier konkret eingetragen werden sollte, um einen möglichst reibungslosen Betrieb bei möglichst kompletter Auslastung eines Nodes durch die dort geschedulten Workloads herzustellen, ist eine seit Jahren diskutierte Frage. Die inzwischen häufigste Antwort lautet:

Für CPUs sollten Requests, aber keine Limits gesetzt werden. Für Arbeitsspeicher sollten Requests==Limits gesetzt werden.

Die Gründe für diese Richtlinie mögen etwas unklar sein, ohne tiefer darauf einzugehen, deswegen verlinke ich an dieser Stelle zwei Blogposts – einen zum Thema CPU-Limits und einen zu Memory-Limits, inklusive lustiger Vergleiche 😉.

An dieser Stelle neben den gängigsten Verwaltungseinstellungen für CPUs und Arbeitsspeicher auf all die anderen zu berücksichtigenden Stellschrauben für sichere Workloads in Kubernetes einzugehen, würde den Rahmen dieses als Überblick gedachten Posts sprengen – deswegen hier nur eine kurze Auflistung einiger Dinge, die man im Hinterkopf behalten sollte:

  • PID Limits für Pods, Nodes und PID-based eviction
  • (un)privilegierte Container
  • Sicherheitskontexte für Container
  • zusätzliche Policies (bspw. Nutzung von ausschließlich signierten Images)
  • Handhabe von Secrets (bspw. Verschlüsselung at rest)

Nodesicherheit sicherstellen

Neben den einzelnen Workloads und Netzwerkverkehr im Cluster muss man natürlich auch die Nodes, aus denen das Cluster besteht, ordentlich absichern. Insbesondere gilt es, die Nodes des Controlplanes, auf denen typischerweise auch etcd mitläuft, abzusichern – Zugriff auf etcd ist gleichzusetzen mit unbegrenztem schreibenden Zugriff auf das Cluster selbst.

Für die Absicherung von Nodes können klassische Technologien wie lokale Firewalls, SELinux oder AppArmor und beliebige weitere Härtungsmaßnahmen zum Einsatz kommen. Doch auch hier gibt es einige Cloud-Native-Technologien, die helfen können:
So unterstützen einige CNIs das Einrichten von Networkpolicies auf Node-Level. Mit nur einem Tool kann also nicht nur Netzwerkverkehr im Cluster reguliert werden, sondern in erweitertem Rahmen auch schon auf den vorgelagerten Nodes selbst.

Darüber hinaus gibt es einige Tools, die in der Lage sind, die komplexen Abläufe, die im Kontext von Kubernetes im Kubelet, den Pods und der Containerlaufzeitumgebung vor sich gehen, zu durchleuchten und ungewünschtes Verhalten zu unterbinden. Oftmals kommt hierbei eBPF zum Einsatz, eine Technologie, die die modulare Erweiterung des Betriebssystemkernels mit kleinen Programmen ermöglicht.

Anwendungssicherheit erhöhen

Ist das Cluster erst einmal abgesichert, kann man sich den darauf betriebenen Anwendungen widmen – auch wenn einige Mechanismen aus dem vorherigen Abschnitt bereits greifen sollten, beispielsweise Netzwerkpolicies und Ressourcenverwaltung.
Damit ist es jedoch in vielen Organisationen nicht getan – vielleicht gibt es Richtlinien, welche Images genutzt werden dürfen, aus welchen Registries sie bezogen werden sollen, ob gewisse Scans laufen müssen oder ob gewisse Signaturen erforderlich sind. Und übrigens dürfen auch anfangs grob geschätzte Ressourcenlimits anhand der tatsächlichen Leistungsdaten angepasst werden 😉.

Für viele dieser Zwecke gibt es Werkzeuge, die das Einrichten individueller Policies im Cluster ermöglichen. Die am weitesten verbreiteten sind zum Einen der Open Policy Agent und zum Anderen Kubewarden. Mit solchen Tools lassen sich verschiedenste Policies entsprechend den Vorgaben eurer Organisationen und Prozesse definieren die -as-Code vorliegen, versioniert und deployed werden können.

Für das Scannen von Workloads und deren Konfiguration gibt es ebenfalls etablierte Lösungen zum Beispiel Trivy oder Kubescape.
Beide Lösungen ermöglichen die Integration von CI/CD-Pipelines, um Sicherheitsrisiken und Misskonfigurationen noch vor Deployment zu bemerken und darauf reagieren zu können.
Trivy bietet darüber hinaus einen Operator, der in regelmäßigen Abständen aus dem Cluster herausselbstständig nach Sicherheitslücken suchen kann.

Für das Finetuning von Ressourcenrequests oder -limits benötigst du hingegen in erster Linie Metriken. Diese können aus verschiedenen Quellen stammen, die sich unter dem Begriff Observability zusammenfassen lassen. Mit Hilfe von Prometheus können so zum Beispiel Performancedaten wie genutzter Arbeitsspeicher, CPU-Last, Netzwerkverkehr auf Anwendungsebene nachvollzogen werden, sofern die Anwendung entsprechend instrumentalisiert wurde.
Mithilfe dieser Daten lassen sich dann Rückschlüsse ziehen ob wir mit unseren initial gewählten Ressourcerequests/limits zu großzügig oder doch eher zu optimistisch umgegangen sind und nun nachbessern.

Ein weiteres Tool zur Erkennung von zu lockeren oder fehlenden Ressourcerequests/limits ist KRR (Kubernetes Resource Recommender), das ebenfalls anhand von Prometheus-Daten die bestehenden Konfigurationen für Pods analysiert und Verbesserungen vorschlägt.

Zu voll umfänglicher Anwendungssicherheit gehört jedoch auch die Absicherung und Überwachung der CI/CD-Pipeline mit der die Anwendung erstellt bzw. ausgeliefert wird. Hier empfiehlt sich die Orientierung an Frameworks wie SLSA (Supplychain Levels for Software Artifacts), eine von Google veröffentlichte Sammlung an Empfehlungen für Software-Entwickler, wie und wo sie ihre Anwendungen härten sollten.
Zusätzlich lassen sich Anwendungen auch im Betrieb in Kubernetes (automatisiert) überwachen. So erlauben Tools wie NeuVector, in Containern ausgeführte Prozesse und versuchte/erfolgte Netzwerkaufrufe zu protokollieren, gewünschtes Verhalten zu “erlernen” und nicht vorgesehene Aufrufe in Echtzeit zu unterbinden.

Fazit

Am Ende eines weiteren Blogposts in unserer “Kubernetes 101” Reihe angekommen stellen wir einmal mehr fest: Kubernetes ist komplex.

Eine Vielzahl an Tools können in Sachen Security in Betracht gezogen haben und welcher “Stack” letzten Endes für eure Anforderungen ausreichend und passend ist muss sich oft erst einmal herausstellen. Nicht zur Diskussion steht, dass eben aufgrund dieser Komplexität eine voll umfängliche Absicherung des Clusters als Plattform und der darin laufenden Anwendungen (ab dem Moment ihrer Entwicklung) oberste Priorität haben sollte. Denn ist erst einmal “der Wurm drin” kann es ansonsten schwierig werden, Sicherheitslücken klar zu benennen, “den Schuldigen” zu finden und das Ausmaß der Kompromittierung einzuschätzen.

Sollte dir dieser Blogpost gefallen haben, schau doch gerne noch die anderen in dieser Serie erschienenen Artikel an.
Und solltest du auf den Geschmack gekommen sein, aber an manchen Stellen noch Hilfe in Sachen Kubernetes brauchen, schau entweder einmal bei unseren Trainings zum Einstieg in Kubernetes vorbei oder buche direkt Consulting zu (fast) Allem rund um Kubernetes bei mir oder meinen Kolleg:innen.

Daniel Bodky
Daniel Bodky
Platform Advocate

Daniel kam nach Abschluss seines Studiums im Oktober 2021 zu NETWAYS und beriet zwei Jahre lang Kunden zu den Themen Icinga2 und Kubernetes, bevor es ihn weiter zu Managed Services zog. Seitdem redet und schreibt er viel über cloud-native Technologien und ihre spannenden Anwendungsfälle und gibt sein Bestes, um Neues und Interessantes rund um Kubernetes zu vermitteln. Nebenher schreibt er in seiner Freizeit kleinere Tools für verschiedenste Einsatzgebiete, nimmt öfters mal ein Buch in die Hand oder widmet sich seinem viel zu großen Berg Lego. In der wärmeren Jahreszeit findet man ihn außerdem oft auf dem Fahrrad oder beim Wandern.

Kubernetes 101: Anwendungen in Kubernetes skalieren

This entry is part 5 of 7 in the series Alles rund um Kubernetes

Für viele Anwender ist die einfache Skalierbarkeit und Flexibilität von Anwendungen im Cluster der Hauptgrund für einen Umstieg auf Kubernetes. Doch auch hier geschieht nichts (oder nur sehr wenig) “magisch” und von allein. Anwendungen müssen bereits zum Zeitpunkt der Entwicklung in Hinblick auf diese gewünschte Flexibilität gebaut und die Deployments entsprechend konfiguriert werden. Natürlich spielt die Infrastruktur, auf der K8s selbst läuft, ebenfalls eine wichtige Rolle. Aber bevor wir direkt zu tief einsteigen, fangen wir doch erstmal mit den Basics an und klären zunächst ein paar Begrifflichkeiten.

Bei Deployments handelt es sich um eine von Kubernetes definierte Abstraktion von zu betreibenden Anwendungen. Anstelle einer konkreten Konfiguration für genau einen Pod wird ein sogenanntes Template definiert, quasi eine Vorlage für eine beliebige Anzahl an zu betreibenden Pods. Durch diese Abstraktion können mehrere Pods des gleichen Deployments gebündelt betrachtet und verwaltet werden, was mehrere Vorteile mit sich bringt – unter anderem eine einfachere Skalierung.

Willst du deine Anwendungen nun skalieren, ist es wichtig den Unterschied zwischen horizontaler Skalierung und vertikaler Skalierung (Scaling out vs. Scaling up) zu verstehen.
Horizontale Skalierung beschreibt das Hinzufügen neuer Pods (oder Nodes, auf Clusterlevel) zum Cluster, um beispielsweise Anfragespitzen eines Webshops o.Ä. zu bewältigen. Vertikale Skalierung hingegen bezeichnet das Hinzufügen von mehr Ressourcen zu bestehenden Pods oder Nodes, beispielsweise in Form von mehr vCPUs oder Arbeitsspeicher.

Nachdem wir jetzt die wichtigsten Begriffe geklärt haben und (hoffentlich) auf dem gleichen Wissensstand sind, steigen wir ordentlich in das Thema Skalierung auf K8s ein!

Skalierung von Deployments

Wenn du und dein Team den Plan verfolgen Anwendungen auf Kubernetes skalieren, hast du dafür mehrere Möglichkeiten. Zum einen die grundlegende Unterscheidung zwischen horizontalem und vertikalem Scaling, zum anderen die Frage, ob und wie diese Skalierung automatisiert werden kann. Für Workload-Skalierung wird meistens horizontales Scaling genutzt. Wie du bereits weißt, ist das gleichbedeutend mit dem Hinzufügen neuer Pods zu dem bestehenden Deployment. Das kannst du theoretisch manuell umsetzen, bspw. mittels eines kubectl Befehls:

kubectl scale --replicas=5 deployment/application-a

In diesem Beispiel weist man Kubernetes’ API an, das Deployment application-a auf 5 Pods zu skalieren. K8s kümmert sich dann automatisch um den Rest. Optional können bei Verwendung von kubectl auch Voraussetzungen mitgegeben werden, die für eine Skalierung notwendig sind, etwa die Anzahl momentan laufender Pods oder eine erwartete Versionsnummer. Treffen die Voraussetzungen nicht zu, wird auch keine Skalierung vorgenommen.

Du merkst, der manuelle Ansatz funktioniert relativ simpel. Er bringt aber auch einige Schwierigkeiten mit sich! So müssen bestehende Deployments kontinuierlich auf die Anzahl ihrer Repliken geprüft werden. Denn nach einer Skalierung der Deployments auf mehr Repliken z. B. aufgrund von hoher Last auf der Anwendung, kann diese nicht automatisch wieder herunterskaliert werden. Hier lassen sich also sehr einfach Geld und Clusterressourcen verschwenden.
Des Weiteren muss jede Skalierung, egal in welche Richtung, von einem Clusternutzer mit entsprechenden Rechten vorgenommen werden. Und ab einer gewissen Anzahl an Skalierungsanfragen ist diese Art zu arbeiten einfach nicht mehr praktikabel. Es benötigt also eine Form der Automatisierung.

Voraussetzungen für automatisierte Skalierung

Damit du eine automatisierte Skalierung von Deployments aber überhaupt durchführen kannst, ist ein entsprechender Controller im Cluster notwendig. Dieser muss zum Einen die zu definierenden Anforderungen an die Deployments erkennen und (re-)evaluieren, und zum anderen die daraus resultierenden Skalierungen vornehmen. Das Kubernetes-Projekt bietet hier sowohl für horizontales Autoscaling als auch für vertikales Autoscaling einen entsprechenden Controller:

Egal für welche Vorgehensweise du dich entscheidest, die Controller übernehmen die gleiche Aufgabe. Sie prüfen in einem zu definierenden Intervall (standardmäßig alle 15 Sekunden), ob die festgelegten Grenzwerte für ein Auf- oder Herunterskalieren des betroffenen Deployments über- bzw. unterboten werden und passen die Anzahl an Repliken entsprechend an.
Für die Konfiguration dieser Grenzwerte gibt es eine eigene API-Ressource namens HorizontalPodAutoscaler.

Eine weitere Voraussetzung der automatisierten Skalierung ist die Installation des sogenannten Metricsservers. Er übernimmt die Aufgabe, deine Pod- und Containermetriken innerhalb des Clusters zu aggregieren und via Kubernetes-API für beliebige Drittanwendungen bereitzustellen – zum Beispiel für unsere Autoscaler.

Einrichtung automatisierter Skalierung

An diesem Punkt habe ich dir hoffentlich die Vorteile einer automatisierten Skalierung näherbringen können und du kannst es kaum abwarten, selbst damit loszulegen. Dafür kannst du dich (wie so oft) zwischen zwei Möglichkeiten entscheiden: Imperativ durch einen kubectl Befehl oder deklarativ durch ein Kubernetes-Manifest. Um dir beide Varianten besser zu veranschaulichen, habe ich Beispiele für den HorizontalPodAutoscaler eines Deployments nginx geschrieben.

Imperativ

kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10

Deklarativ

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nginx
  namespace: default
spec:
  maxReplicas: 10
  metrics:
  - resource:
      name: cpu
      target:
        averageUtilization: 50
        type: Utilization
    type: Resource
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx

Beide Varianten erstellen ein HorizontalPodAutoscaler Objekt, dass das Deployment nginx bei durchschnittlicher Auslastung von 50% hochskaliert bzw. bei 0% in einen Bereich zwischen 1-10 Pods herunterskaliert. Auf diese Weise lassen sich Kubernetes Deployments automatisch horizontal skalieren, die Grenzwerte sind dabei seit API-Version 2 des HorizontalPodAutoscalers sehr flexibel konfigurierbar.

Anstatt lediglich auf ein von der Kubernetes-Metrics-API bereitgestelltes Attribut zu schauen (CPU-Last/Memory) können mehrere Attribute kombiniert werden oder sogar externe Messwerte verglichen werden, beispielsweise resultierend aus einer Überwachung mittels PrometheusAußerdem können statt der Metriken von Pods die einzelnen Metriken für Container als Basis des Autoscalings genutzt werden.

Und auch ansonsten bietet die API-Definition des HorizontalPodAutoScalers eine Bandbreite an konfigurierbarem Verhalten. So lässt sich mittels Scaling Policies das Skalierungsverhalten für Hoch- bzw. Herunterskalierung separat einstellen. Etwa wenn du Kubernetes Pods schnellstmöglich hochfahren lassen willst, der Abbau überflüssiger Pods aber in Erwartung weiterer Lastspitzen langsam stattfinden soll.
Ein weiteres nützliches Feature ist die Existenz der Eigenschaft StabilizationWindowSeconds, die eine Art Filter für Flappingalso stark und häufig wechselndes Verhalten der beobachteten Metriken, darstellt. Eine genauere Auseinandersetzung mit den Konfigurationsmöglichkeiten des HorizontalPodAutoscalers würde den Rahmen dieses Blogposts sprengen, stattdessen verweise ich einmal mehr auf die oben verlinkte offizielle Dokumentation.

Der VerticalPodAutoscaler ist noch in einer frühen Betaversion (momentan v0.13.0) und deswegen noch nicht in der offiziellen Kubernetes Dokumentation enthalten. Eine Auflistung seiner Fähigkeiten und Dokumentation findet sich im oben verlinkten Repository des Projekts.

Skalierung von Nodes

Hast du über einen längeren Zeitraum eine hohe Last auf deinem Cluster, und/oder wurden nach und nach immer mehr verschiedene Deployments hochskaliert, kann es passieren, dass die Nodes des Clusters selbst an die Grenzen ihrer Ressourcenkapazitäten zu gelangen. Auch hier hat man nun die Möglichkeit, horizontal oder vertikal zu skalieren, um das Cluster weiter funktionsfähig zu halten.
Für die horizontale Skalierung eines Kubernetes-Clusters stellt das Kubernetes-Projekt auf GitHub den Cluster-Scaler zur Verfügung, der in der Lage ist, dynamisch Nodes bei einer Vielzahl an Public-Cloud-Providern zu (de-)provisionieren.

Die vertikale Skalierung der Nodes eines Kubernetes-Clusters kann dir noch nicht durch einen Controller abgenommen werden – hier ist manuelle oder extern automatisierte Arbeit notwendig. Hast du also deine Kubernetes-Cluster auf VMs aufgesetzt, kannst du deren zugewiesene Ressourcen (vCPUs, Arbeitsspeicher, Festplattenspeicher) anpassen. Läuft Kubernetes als “Managed Kubernetes“, ist es oftmals möglich, die Node Pools anzupassen zu einer leistungsstärkeren Klasse an Nodes.

 

Fazit

Auf den ersten Blick erscheint die Skalierung von Workloads und des Clusters selbst, wie so viele Dinge rund um Kubernetes, als machbares Vorhaben. Dank kubectl und der von der API angebotenen Objekttypen in Kombination mit den vorhandenen Autoscalern können Workloads sowohl imperativ als auch deklarativ und horizontal sowie vertikal skaliert werden. Für Cluster in der Cloud lassen sich auch Nodes horizontal skalieren.

Geht man allerdings weiter ins Detail, findet man viele Stellschrauben, fortgeschrittene Konzepte und Designfragen, die es bei der Definition eines Autoscaler-Objekts zu beachten gilt. Hier ist die Erfahrung der zuständigen Clusteradministratoren gefragt, um die Kapazitäten des Clusters durch Autoscaling optimal zu nutzen, ohne Ressourcen unnötig zu verschwenden oder Workloads zu spät oder gar nicht zu skalieren.
Auch Monitoring der Workloads kann helfen, um nach und nach ein Gespür für zu erwartende Auslastung des Kubernetes-Clusters zu bekommen und das Autoscaling einiger oder gar aller Anwendungen im Cluster feinjustieren zu können.

Daniel Bodky
Daniel Bodky
Platform Advocate

Daniel kam nach Abschluss seines Studiums im Oktober 2021 zu NETWAYS und beriet zwei Jahre lang Kunden zu den Themen Icinga2 und Kubernetes, bevor es ihn weiter zu Managed Services zog. Seitdem redet und schreibt er viel über cloud-native Technologien und ihre spannenden Anwendungsfälle und gibt sein Bestes, um Neues und Interessantes rund um Kubernetes zu vermitteln. Nebenher schreibt er in seiner Freizeit kleinere Tools für verschiedenste Einsatzgebiete, nimmt öfters mal ein Buch in die Hand oder widmet sich seinem viel zu großen Berg Lego. In der wärmeren Jahreszeit findet man ihn außerdem oft auf dem Fahrrad oder beim Wandern.

Kubernetes 101: So installierst und verwaltest du Anwendungen

This entry is part 4 of 7 in the series Alles rund um Kubernetes

Nachdem wir uns vergangene Woche damit befasst haben, welche Mittel und Wege existieren, um sich ein Cluster für Tests oder die Produktion zu installieren, sind wir nun (hoffentlich) an dem Punkt angekommen, an dem wir erste Anwendungen auf Kubernetes portieren oder neu installieren möchten. Da sich Kubernetes als Containerorchestrator deutlich von “althergebrachten” Betriebsumgebungen für Anwendungen unterscheidet, ist es nur logisch, dass sich auch Best Practices für die Installation und den Betrieb von Anwendungen unterscheiden. Grob lassen sich die zu beachtenden Gesichtspunkte in 5 Felder unterteilen:

  • Dateisystem vs. Container
  • Monolithen vs. Microservices
  • Stateful vs. Stateless
  • Blackbox vs. Whitebox
  • Monitoring vs. Observability

Diese Felder und ihre Implikationen bedingen einander teilweise. Fangen wir also mit dem evtl. offensichtlichsten an – der Installationsmethodik.

Dateisystem vs. Container

Der größte und für viele auch folgenschwerste Unterschied zwischen Anwendungen, die in Kubernetes laufen ,und solchen, die auf VMs oder physischen Servern installiert werden, ist Containerisierung der Workloads. Jede Anwendung muss als Containerimage definiert, gebaut, gesichert und verteilt werden – dies erfordert oftmals eine Umstellung bestehender Abläufe für Tests, Bau und Verteilung der Software, bspw. in den CI/CD-Pipelines der Entwickler- und DevOps-Teams. Des Weiteren muss oftmals neue Infrastruktur eingerichtet werden, um etwa Imagescans oder eine eigene Container- und Artefaktregistry für das Unternehmen bereitstellen zu können.

Des Weiteren gilt es natürlich, entsprechendes Know-How in den Teams aufzubauen – nicht jede/r Entwickler/in hat in der Vergangenheit mit Docker und containerisierten Anwendungen gearbeitet, geschweige denn entwickelt. Auch wenn Tools wie Docker Desktop oder Podman Desktop den Einstieg heutzutage erleichtern, müssen Mindset, Praktiken und Routinen oftmals erst aufgebaut werden. Gleiches gilt für die Handhabe der Containerimages nach dem Bau: Wie werden Sie gespeichert und für Pipelines und Cluster verfügbar gemacht? Nutzt man hierfür eine offene Plattform (GitHub Container Registry, DockerHub), eine SaaS-Lösung (Artifactory), oder baut eigene Infrastruktur auf (Harbor)?
Mit diesen möglichen Problematiken sollte man sich im Bestfall bereits im Vorfeld befassen und aufkommende Fragen initial klären, um einen möglichst reibungslosen Umstieg auf Kubernetes für alle beteiligten Teams zu gewährleisten.

Monolithen vs. Microservices

Eine direkte Folge der Containerisierung von Anwendungen ist die Transition von sog. Monolithen zu Microservices. Der Grund hierfür ist klar: In einer Umgebung, in der Softwarereleases oft mehrmals täglich stattfinden und ein Orchestrator installierte Anwendungen nach Belieben skalieren, verwerfen oder an anderer Stelle erneut initialisieren kann, sind Anwendungen mit einer Paketgröße von mehreren Gigabyte nicht praktikabel – man möchte schmale Pakete im Bereich von maximal einigen Hundert Megabyte, um flexibel und schnell in Sachen Verteilung und Installation zu sein.

Hierfür ist es gängige Praxis, bestehende Anwendungen umzustrukturieren bzw. bei der Entwicklung neuer Anwendungen bereits in der Designphase auf die spätere Installation als Microservices hinzuwirken, um Monolithen zu vermeiden. Unter einem Monolithen versteht man ein einzelnes Softwarepaket, das sich von Operatoren nur als eine Einheit installieren lässt und keinerlei Flexibilität und Unabhängigkeit seiner Komponenten bietet – alle Bestandteile sind unter der Haube fest miteinander “verdrahtet”. Hat man nun Probleme mit der Performanz eines bestimmten Features (ein sog. Bottleneck) bleibt einem keine andere Wahl, als den gesamten Monolithen zu skalieren – in den meisten Fällen Ressourcenverschwendung.

Viel sinniger wäre es doch, die einzelnen Bestandteile zu trennen – das Ergebnis sind viele verschiedene Microservices, die im Bestfall jeweils nur eine Aufgabe übernehmen. Ein solcher Ansatz ermöglicht die Skalierung einzelner Bestandteile der Anwendung, bspw. des viel frequentierten Webshops, anstatt direkt die gesamte Anwendung skalieren zu müssen. Die Kommunikation der einzelnen Microservices untereinander geschieht in solchen Szenarien über das (clusterinterne) Netzwerk bspw. via HTTP oder gRPC.

Stateful vs. Stateless

Eine direkte Folge der Umsetzung von Anwendungen als Microservices wiederum ist eine Transition von zustandsabhängigen (stateful) zu größtenteils zustandslosen (stateless) Anwendungen – während die meisten Monolithen zustandsabhängig sind (fast jede nennenswerte Anwendung muss an irgendeinem Punkt Daten persistent speichern können), müssen nur die wenigsten Microservices Daten persistent speichern. In vielen Fällen reicht ein lokaler Cache, bspw. zum Speichern von Nutzersitzungen oder dem Vorhalten von oft angefragten Daten.

Wirkliche Persistenz benötigen nur die Microservices, die sich unmittelbar mit der Verarbeitung und Speicherung von Daten befassen und hierfür bspw. mit rückgelagerten Datenbanken oder Dateisystemen kommunizieren. Mittlerweile gibt es allerdings genug Fallstudien, in denen auch Services wie Blockspeicher oder Datenbanken direkt auf Kubernetes betrieben werden.

Blackbox vs. Whitebox

Neben der Umstellung von “Stateful” auf “Stateless” betrifft eine weitere große Veränderung im Design von Anwendungen bestehend aus Microservices den Ansatz ihrer Überwachung: Anstatt lediglich von außen auf die Anwendung zu blicken und evtl. auftretende Symptome einer Fehlfunktion zu erkennen, bspw. durch HTTP-Anfragen an für Nutzer angebotene Webendpunkte (sog. Blackbox-Monitoring), instrumentalisiert man seine Microservices von vornherein so dass man tatsächliche Metriken aus den im Service ablaufenden Prozessen erhält (sog. Whitebox-Monitoring).

Beliebt für die Umsetzung ist hierbei Prometheus, was einen etablierten Standard für Metriken liefert, weit verbreitet ist und Funktionsbibliotheken für die Instrumentalisierung von Code in verschiedenen Programmiersprachen bietet. Prometheus sammelt die Metriken der Services über Webendpunkte ab und speichert sie in einer internen Timeseriesdatenbank (TSDB) ab. Ist Prometheus für euch ein gänzlich unbekannter Begriff, kann ich euch an dieser Stelle wärmstens unser Prometheus Fundamentals Training ans Herz legen, mit dem man in kürzester Zeit relativ vertraut mit Prometheus und seinem Funktionsumfang wird.
Verfolgt man also Whitebox- statt Blackboxmonitoring, hat man die tatsächlichen Metriken seiner Microservices zur Verfügung und kann bei aufkommenden Komplikationen Ursachen statt Symptomen bekämpfen. Des Weiteren können die Metriken zur permanenten Weiterentwicklung und Verbesserung der Serviceperformanzen genutzt werden – eine Win-Win-Situation!

Monitoring vs. Observability

Aufbauend auf dem letzten Absatz zu Blackbox- vs. Whiteboxmonitoring lässt sich die Monitoring-Philosophie im Hinblick auf K8s oder “Cloud-Native” generell noch vertiefen und erweitern: Man spricht von den Three pillars of observability (Drei Säulen der Beobachtbarkeit/Observability) Metrics, Traces und LogsMetriken werden von Anwendungen und Services selbst bereitgestellt und bieten wie bereits erklärt einen ungetrübten Einblick in das Innenleben einzelner Services. Traces erlauben es, Prozessketten über Servicegrenzen hinweg zu verfolgen und bspw. zu ermitteln, in welchen Stadien der Verarbeitung besonders hohe Latenzen entstehen. Logs ermöglichen die Verarbeitung von Events o.Ä., die von den einzelnen Anwendungen protokolliert werden.

Aus der Fülle an verschiedenen Datentypen und den dafür benötigten Praktiken entsteht die Entwicklung von Monitoring hin zu Observability – es ist nicht mehr ausreichend, lediglich “von außen” auf seine monolithische Anwendung zu blicken, sondern es gilt, stattdessen in den Services selbst anzusetzen und soviel Informationen wie möglich abzugreifen.
Für alle drei Arten an Beobachtungen gibt es umfangreiches Tooling in der Opensource-Gemeinschaft, das einem hilft, den Überblick über seine Cluster und die darauf betriebenen Anwendungen zu behalten, diese nach und nach zu optimieren und bei Fehlern schnell oder sogar proaktiv reagieren zu können. Auch bei der Einhaltung von Service Level Agreements (SLAs) gegenüber den Kunden oder internen Service Level Agreements (SLAs) hilft eine lückenlose Observability-Strategie.

 

Sollten diese Punkte etwas viel auf einmal gewesen sein oder du bereits absehbare Probleme bei der Umsetzung auf dich zukommen siehst, kann ich euch erneut auf unsere Services rund um Container, DevOps und Kubernetes verweisen – wir sind in vielen der genannten Bereichen bereit, dir mit Rat und Tat zur Seite zu stehen und bei der Umsetzung zu unterstützen. Ansonsten bleibt mir für heute nur, “bis zum nächsten Mal” zu sagen, wenn wir uns genauer anschauen, wie man Anwendungen auf Kubernetes denn nun im Detail verwaltet und skaliert.

Daniel Bodky
Daniel Bodky
Platform Advocate

Daniel kam nach Abschluss seines Studiums im Oktober 2021 zu NETWAYS und beriet zwei Jahre lang Kunden zu den Themen Icinga2 und Kubernetes, bevor es ihn weiter zu Managed Services zog. Seitdem redet und schreibt er viel über cloud-native Technologien und ihre spannenden Anwendungsfälle und gibt sein Bestes, um Neues und Interessantes rund um Kubernetes zu vermitteln. Nebenher schreibt er in seiner Freizeit kleinere Tools für verschiedenste Einsatzgebiete, nimmt öfters mal ein Buch in die Hand oder widmet sich seinem viel zu großen Berg Lego. In der wärmeren Jahreszeit findet man ihn außerdem oft auf dem Fahrrad oder beim Wandern.

Kubernetes 101: Welche Installationsmöglichkeiten bietet Kubernetes?

This entry is part 3 of 7 in the series Alles rund um Kubernetes

Nachdem wir uns in den vergangenen Artikeln bereits damit beschäftigt haben, was Kubernetes eigentlich ist, warum man es brauchen könnte und wie Kubernetes und seine API eigentlich funktionieren, juckt es dich inzwischen sicherlich in den Fingern, Kubernetes einmal selbst auszuprobieren.

Hierbei haben wir allerdings die Qual der Wahl – wie in vorangegangenen Blogposts bereits erwähnt, listet die CNCF fast 50 verschiedene Kubernetes-Distributionen auf ihrer Seite. Diese unterscheiden sich vor Allem durch ihren Fokus auf verschiedene Nutzergruppen oder Einsatzumgebungen voneinander:

  • Lokal
  • Auf Serverhardware oder in VMs
  • In der Cloud
  • “at the edge” oder im IoT-Bereich

Aus diesem Grund werde ich heute diese vier Anwendungsumgebungen etwas genauer beleuchten und für alle Domänen mögliche Installationskandidaten sowie zusätzliches, nützliches Tooling betrachten. Los geht’s!

Lokale Kubernetes-Installation

Kubernetes lokal zu installieren ist längst nicht so unsinnig, wie es zunächst scheinen mag – wie sinnvoll kann eine Container-Orchestrierung über mehrere Nodes hinweg auf einem Node schon sein? Die Antwort lautet: Sehr!

Für jeden Entwickler in einem Projekt ein eigenes Cluster auf firmeninterner Hardware oder in der Cloud zu provisionieren ist oftmals unrentabel, und eine lokale Kubernetes-Installation verhält sich zumindest ähnlich genug, um Feedback für die Entwickler zu geben. Auch für den Einsatz in CI/CD-Pipelines für Integrations- und End-to-End-Tests bietet sich die Installation eines “lokalen” Clusters zur Pipeline-Laufzeit an.

Welche Möglichkeiten zur Installation eines lokalen Clusters gibt es also? Hier ein kurzer Überblick:

  • Docker Desktop – genau, richtig gelesen! Docker Desktop bietet bereits seit einigen Versionen die Möglichkeit, ein lokales Kubernetes-Cluster  in der momentan aktuellsten Version mit einem Node zu installieren. Hierfür wird im Hintergrund von Docker eine VM erstellt, in die dann Kubernetes und Tools für persistente Speicherverwaltung und Netzwerkanbindung des Clusters installiert werden. Docker Desktop kümmert sich darüber hinaus um die automatische Konfiguration der lokalen kubeconfig des Nutzers.
  • Rancher Desktop – sehr ähnlich wie Docker Desktop, allerdings ohne Containerverwaltung – die GUI kümmert sich lediglich um die Konfiguration einer lokalen (versteckten) VM, in die ein Kubernetes-Cluster installiert wird, ebenfalls mit einem Node und zusätzlichen Onboard-Mitteln für Speicher und Netzwerk.
    Ebenfalls wie Docker Desktop kümmert sich auch Rancher Desktop um die automatische Konfiguration der lokalen kubeconfig. Ich persönlich bevorzuge von beiden Tools mittlerweile Rancher Desktop, da man hier nicht wie bei Docker Desktop auf die “aktuellste” Kubernetes-Version beschränkt ist.
  • Minikube – Das Projekt wird von einer offiziellen Kubernetes SIG (Special Interest Group) entwickelt und maintained, im Gegensatz zu Docker/Rancher Desktop erlaubt einem Minikube eine deutlich erweiterte Konfiguration des Clusters auf Komponentenebene. Auch die Aktivierung verschiedener Updates wie Dashboards uvm. ist möglich.
  • Microk8s – Microk8s ist eine von Canonical bereitgestellte Lösung für lokale Kubernetes-Installationen, die allerdings auch für die Installation “richtiger” Cluster über mehrere Nodes hinweg genutzt werden kann. Ähnlich wie bei Minikube können auch hier tiefergreifende Konfigurationen vorgenommen und Addons nach Bedarf an und ausgeschaltet werden.

Installation auf Hardware oder VMs

Hat man sich auf seinem lokalen Rechner oder Laptop ausgetobt, möchte man evtl. zum ersten Mal ein tatsächlich verteiltes Cluster als Proof of Concept oder sogar schon für den Produktionsbetrieb auf firmeneigener Hardware oder einer eigenen VM-Flotte einrichten. Neben dem bereits erwähnten Microk8s gibt es für dieses Szenario noch ein paar andere nennenswerte Möglichkeiten, sich ein Cluster einzurichten.

  • kubeadm – das “offizielle” Tool zur Installation von Kubernetes. Es kann dazu genutzt werden, um ein Cluster und seine Komponenten analog zu dem Aufbau einzurichten, der im letzten Teil dieser Serie zu Cluster-Architektur beschrieben wurde – kubelet, etcd, und die anderen Bestandteile eines Clusternodes laufen hierbei als einzelne Systemservices. kubeadm kümmert sich um Dinge wie Zertifikatsgenerierung und erstmalige Einrichtung sowie das einfache Hinzufügen neuer Nodes in das Cluster. Diese Art der Installation eignet sich auch für eine automatisierte Umsetzung bspw. via Ansible.
  • Rancher – ein Cluster-Management-Tool von SUSE, mit dem sich Cluster sowohl on-prem als auch in der Cloud erstellen und zentral verwalten lassen. Auf lokalen VMs oder Hardware lassen sich hierbei wahlweise Cluster auf der Basis von K3s oder RKE1/2, beides ebenfalls von SUSE verwaltete Kubernetes-Plattformen.
  • K3s – gerade eben bereits erwähnt, lässt sich K3s auch außerhalb des Rancher-Kontexts hervorragend für Kubernetes-Installationen nutzen. K3s besticht durch seinen abgespeckten Umfang und die Bündelung aller benötigten Komponenten in eine ausführbare Datei, was die Installation und Verwaltung enorm erleichtern kann. Auch hier ist eine Automatisierung durch Dritttools wie Ansible möglich.

Installation in der Cloud

In der Cloud hat man endgültig die Qual der Wahl – (fast) jeder Cloudanbieter hat dieser Tage eine sog. “Managed Kubernetes”-Lösung im Angebot, die mit einigen Klicks bestellt werden kann und nach ein paar Minuten verfügbar ist. Am beliebtesten sind hier natürlich die “Big Three” (Google Cloud, AWS, Azure Cloud), bei denen man aber in den meisten Fällen auch mehr Geld lässt als bei kleineren Mitbewerbern. Es gilt also, Kosten und Nutzen abzuwägen, oftmals reicht eine Lösung von kleineren Cloudanbietern wie bspw. unser Managed Kubernetes by NWS.

Natürlich kann man sich auch in der Cloud einzelne Server provisionieren und sich mit den oben erwähnten Tools sein eigenes Cluster, losgelöst von den gemanagten Angeboten der Provider, bauen. Auch die Verteilung eines Clusters über mehrere Cloud-Anbieter hinweg für eine maximale Fehlertoleranz ist ein Modell, das in der Vergangenheit bereits umgesetzt wurde. “Die Cloud” bietet also vielfältige Möglichkeiten, Kubernetes-Cluster ganz nach Bedarf, erwartbaren Risiken und Problemen aufzubauen, um maximal flexibel zu bleiben.

Kubernetes at the Edge

Immer beliebter wird auch der Betrieb von kleinen Kubernetes-Clustern “at the edge”, also möglichst nahe beim Endnutzer. So hat bspw. die amerikanische Fastfood-Kette “Chick-Fill-A” in jeder ihrer Filialen ein 3-Node-Cluster in Betrieb, in Summe über 2500 Cluster. Auch für solche Anwendungszwecke möchte man eine möglichst robuste und einfach zu wartende Kubernetes-Lösung einsetzen. Zwei beliebte Optionen hierfür sind – einmal mehr und auch von Chick-Fill-A genutzt – K3s sowie Talos.

Talos wird von SideroLabs entwickelt und ist eher Betriebssystem als nur Kubernetes-Plattform, wenn man es genau nimmt. Es spinnt quasi den Gedanken von K3s, eine gebündelte, vorkonfigurierte Zusammenstellung aller Komponenten bereitzustellen, einen Schritt weiter, und stellt direkt das Betriebssystem. Dieses ist minimal gehalten und immutable, was die Sicherheit drastisch erhöht und die Größe der zu installierenden Software minimiert. Sämtliche Konfiguration des Nodes und der Kubernetes-Installation darauf wird via API-Zugriffen vorgenommen.

Choose your Fighter

Wie eingangs erwähnt, sind die verschiedenen Umsetzungsmöglichkeiten einer Kubernetes-Installation schier endlos – weswegen auch dieser Artikel keinen Anspruch auf Vollständigkeit erhebt. Er kann allerdings trotzdem eine gute Übersicht über einige der momentan populärsten Lösungen geben und entspricht auch den von mir favorisierten Tools, um Kubernetes-Cluster in verschiedenen Umgebungen umzusetzen. Ich kann nur empfehlen, sich mit einigen aufgelisteten Lösungen vertraut zu machen, um ein Gespür dafür zu entwickeln, wie sich der Umgang mit Kubernetes auf verschiedenen Distributionen und Plattformen voneinander unterscheidet, angefangen bei einer lokalen Installation mit Docker/Rancher, und fortgeführt im eigenen Rechenzentrum oder der Cloud.

Daniel Bodky
Daniel Bodky
Platform Advocate

Daniel kam nach Abschluss seines Studiums im Oktober 2021 zu NETWAYS und beriet zwei Jahre lang Kunden zu den Themen Icinga2 und Kubernetes, bevor es ihn weiter zu Managed Services zog. Seitdem redet und schreibt er viel über cloud-native Technologien und ihre spannenden Anwendungsfälle und gibt sein Bestes, um Neues und Interessantes rund um Kubernetes zu vermitteln. Nebenher schreibt er in seiner Freizeit kleinere Tools für verschiedenste Einsatzgebiete, nimmt öfters mal ein Buch in die Hand oder widmet sich seinem viel zu großen Berg Lego. In der wärmeren Jahreszeit findet man ihn außerdem oft auf dem Fahrrad oder beim Wandern.