User Experience

Anwenderfreundlich, aber wie? Kubernetes und sein Imageproblem

Lukas Gentele

© Shutterstock / fizkes

Kubernetes ist populär wie nie zuvor. Kein Wunder, denn der Containerorchestrator bietet begehrte Features wie Rolling Updates, Zero Downtime, Self-Healing und Auto-Scaling. Zudem verspricht er ein nie zuvor dagewesenes Maß an Portabilität zwischen Plattformen. Doch je größer das Wertversprechen von Kubernetes wird, desto größer wird das Imageproblem, das über die Jahre entstanden ist.

Von vielen Entwicklern wird Kubernetes als zu komplex und kaum beherrschbar wahrgenommen. Kubernetes hat ein Imageproblem. Wenn Anwendungsentwickler aus diesem Grund Kubernetes meiden, dann werden die Vorteile von Kubernetes kaum realisierbar sein, denn es wird schlicht an Anwendungen fehlen, die für den Betrieb mit Kubernetes entwickelt werden.

Die mehr als 2.000 Contributor von Unternehmen wie Google, Microsoft oder Red Hat haben Kubernetes zur mächtigsten Technologie für den Betrieb und die Skalierung von Containern gemacht. Kubernetes löst einige der kompliziertesten Probleme beim Betrieb von Software auf sehr intelligente Weise, aber zur gleichen Zeit macht es sehr simple Aufgaben deutlich komplizierter. In Zeiten von Microservices und DevOps möchten Entwicklerteams kleine Anwendungen schnell aufbauen und in den Betrieb überführen. Nutzt man hierbei Kubernetes, muss der Entwickler plötzlich neben dem Konzept des Containers auch verstehen, was ein Pod ist und wie ein solcher durch ein ReplicaSet gesteuert wird, das wiederum von einem Deployment oder einem StatefulSet erzeugt wurde. Um eine Anwendung dann nach außen verfügbar zu machen, müssen zusätzlich noch Networking-Ressourcen wie Services, Ingresses oder Load Balancer konfiguriert werden. Die Anforderungen, die die Nutzung von Kubernetes mit sich bringt, sind selbst bei kleinsten Anwendungen so hoch, dass es insbesondere für Anwendungsentwickler zur Herausforderung werden kann, Kubernetes effizient einzusetzen.

Warum Kubernetes so komplex sein muss

Grundsätzlich ist Kubernetes als Containerorchestrator kein klassisches Entwicklertool, sondern überwiegend eine Technologie für Systemadministratoren. Dass Kubernetes entwicklerfreundlicher werden muss, stand bisher kaum im Fokus und daher ist es verständlich, dass Kubernetes als kompliziert und das Ökosystem als kaum zu überblicken gilt. Als Kubernetes 2014 von Google als Open-Source-Software auf GitHub veröffentlicht wurde, konnte wohl kaum einer ahnen, dass sich ein riesiges Ökosystem um diesen Containerorchestrator entwickeln würde. Heute zählt die Cloud Native Computing Foundation (CNCF), die im August 2018 die operative Kontrolle über das Kubernetes-Projekt übernommen hat, zu den aktivsten Initiativen innerhalb der Linux Foundation. Die CNCF hat mittlerweile knapp 100 Kubernetes-Distributionen, -Plattformen und -Installer zertifiziert und listet mehr als 600 Projekte auf der CNCF Landscape, in deren Entwicklung bereits mehr als 40 Milliarden US-Dollar geflossen sind.

Dass das Kubernetes-Ökosystem so vielseitig ist, mag auf den ersten Blick abschrecken, doch es ist notwendig, da die Architektur von Kubernetes ein großes Maß an Flexibilität bietet. Und genau das ist das Erfolgsrezept von Kubernetes: Egal ob in der Public-Cloud, im firmeneignen Rechenzentrum oder in hybriden Szenarien, Kubernetes lässt sich dank der Vielzahl an Plug-ins, Operatoren und Controllern auf nahezu jeder Infrastruktur betrieben. Und damit wird die Vision von infrastrukturunabhängiger, leicht portabler Software Realität. Kubernetes ist also unvermeidlich so komplex, doch führt das zwangsläufig dazu, dass Kubernetes auch eine schlechte Developer Experience haben muss?

DevOpsCon Istio Cheat Sheet

Free: BRAND NEW DevOps Istio Cheat Sheet

Ever felt like service mesh chaos is taking over? As a follow-up to our previous cheat sheet featuring the most important commands and functions, DevOpsCon speaker Michael Hofmann has put together the 8 best practices you should keep in mind when using Istio.

Wie man Kubernetes anwenderfreundlicher macht

Einer der Gründe, warum Kubernetes zurzeit nicht besonders anwenderfreundlich ist, liegt darin, dass kaum ein Unternehmen Kubernetes so bereitstellt, dass Entwickler es mühelos als Service konsumieren und in ihren bestehenden Workflow integrieren können. Viele Unternehmen experimentieren zurzeit zwar mit Kubernetes, doch das Betreiben von Kubernetes-Clustern allein schafft noch keinen Mehrwert. Wenn wir Kubernetes-Cluster aufbauen und dann an Entwicklerteams übergeben, befruchten wir das Image von Kubernetes als komplexes Monster, das kaum zu managen ist. Übergibt man für Entwicklung nicht-optimierte Cluster an die Anwendungsentwickler, ist es nicht verwunderlich, dass Entwicklerteams sich von der Komplexität des Kubernetes-Ökosystems überwältigt fühlen. Die überwiegende Mehrheit der CNCF-Projekte ist für den Anwendungsentwickler jedoch kaum relevant. Für ein Entwicklerteam ist es unerheblich, welche Kubernetes-Distribution im Unternehmen verwendet wird und welches Storage-/Networking- oder Monitoring-Plug-in dabei genutzt wird.

Daher sollte man beim Betrieb von Kubernetes von Anfang an den Anwendungsentwickler im Blick haben, Cluster gemäß den Bedürfnissen der Entwickler ausstatten und die Developer Experience entsprechend optimieren. Wenn es Unternehmen gelingt, ihre Entwickler in die Lage zu versetzen, schnell und effizient Anwendungen zu entwickeln, die auf Kubernetes betrieben werden können, können die Vorteile von Kubernetes deutlich schneller und einfacher realisiert werden. Dabei ist es wichtig, Kubernetes als Service für Entwickler bereitzustellen und ihnen die richtigen Werkzeuge an die Hand zu geben, um Kubernetes reibungslos in ihre Arbeitsprozesse zu integrieren.

Developer Experience steht zunehmend im Fokus

Bislang stand das Thema Developer Experience kaum im Fokus der Community, doch zunehmend realisieren Unternehmen, dass es wichtig ist, Kubernetes für Entwickler zugängig zu machen, um die Vorteile von Kubernetes voll ausschöpfen zu können. Daher ist es kein Wunder, dass es seit etwa eineinhalb Jahren Bestrebungen innerhalb der Community gibt, Kubernetes anwenderfreundlicher zu machen. Zahlreiche Open-Source-Projekte wie etwa Skaffold, Draft, DevSpace CLI oder Telepresence versuchen Entwicklern das Arbeiten mit Kubernetes deutlich zu vereinfachen. In den folgenden Abschnitten zeige ich Ihnen, welche Fortschritte die Community bereits in den Bereichen

  • Vereinfachung des Projekt-Set-ups
  • Automatisierung des Deployment-Workflows
  • Verbesserung des Loggings und Debuggings

erzielt hat.

Vereinfachung des Projekt-Set-ups

Abb. 1: Kubernetes Manifests

Abb. 1: Kubernetes Manifests

Nirgendwo kommt die Komplexität von Kubernetes so zutage, wie bei der Erstellung der sogenannten Manifests, mit denen die für eine Anwendung benötigten Ressourcen definiert werden. Jeder, der schon einmal mit Kubernetes gearbeitet hat, kennt die endlos langen YAML-Dateien, die mit dem Kubernetes-API-Server ausgetauscht werden (Abbildung 1). Wie aufwendig die Erstellung dieser Dateien ist, zeigt sich nicht nur in der umfangreichen Spezifikation der verfügbaren Kubernetes-Ressourcen, sondern wird einem bei jeder Konferenz mit Vorträgen zu Kubernetes vor Augen geführt: Ich habe noch keinen Vortrag gesehen, bei dem ein Referent diese Dateien von Grund auf während des Vortrags selbst erstellt hat. Abgesehen von der Menge der Zeit, die nötig wäre, ist die Spezifikation so umfangreich und generell gehalten, dass es schwer ist, ein Manifest, das auf Anhieb funktioniert, aus dem Stehgreif und ohne Blick in die Dokumentation zu erzeugen. Es ist absolut nachvollziehbar, dass die Spezifikation von Ressourcen so aufwendig ist, denn sonst könnte Kubernetes nicht so reich an Funktionalität sein, wie es heute ist. Dennoch muss ich mich fragen: Müssen wir wirklich permanent auf Copy and Paste zurückgreifen, um Manifests für Kubernetes zu erzeugen?

Bereits im Sommer 2016 hat die Community mit Kompose einen Vorstoß zur Verringerung dieses Problems gewagt. Das praktische Konsolentool Kompose lässt Entwickler existierende docker-compose.yaml-Dateien in Kubernetes Manifests konvertieren. Wer also Docker Compose verwendet, kann sich hiermit das Leben deutlich erleichtern. Als kleiner Bonus erstellt das Tool mit dem Befehl kompose convert –chart sogar die grundlegende Struktur für ein Helm Chart und packt die aus der docker-compose.yaml generierten Manifests in den entsprechenden templates-Ordner.

Neben Kompose kann Helm selbst ein Schritt hin zu automatisch generierten Manifests darstellen. Helm ist als Package Manager für Kubernetes bekannt und erlaubt uns, sogenannte Helm Charts in einem Kubernetes-Cluster zu installieren. Bisher ist dabei die Installation der server-seitigen Helm-Komponente Tiller notwendig, die in der kommenden Version 3 nicht mehr benötigt werden wird. Neben der Standardisierung von Installations- und Upgradeabläufen, lassen sich mit Helm Anwendungen wiederverwenden und als Dependencies definieren. Ich sehe das als wichtigen Schritt weg von Copy and Paste und hin zu einer strukturierten Definition von wiederverwendbaren Anwendungskomponenten. Zusätzlich beinhaltet Helm eine umfangreiche Templating Engine, die uns erlaubt, verschiedene Anwendungen mit demselben Chart zu deployen.

GitLab hat 2017 als eines der ersten Unternehmen das Potenzial des Templating mit Helm erkannt und mit Auto DevOps ein Feature veröffentlicht, das Deployments zu Kubernetes auch ohne große Vorkenntnisse ermöglichen sollte. Im Kern stellt GitLab dabei ein standardisiertes Helm Chart zur Verfügung, das den gängigsten Aufbau einer Anwendung abbildet und sich durch einige wenige Parameter konfigurieren lässt. Während Auto DevOps für sehr einfache Anwendungen durchaus geeignet ist, gelangt man mit den bereitgestellten Konfigurationsoptionen bei etwas komplexeren Anwendungen schnell an den Punkt, an dem man sein eigenes Helm Chart schreiben muss.

Tools wie Draft von Microsoft können hier Abhilfe schaffen. Führt man den Befehl draft create in einem Projekt aus, versucht das Konsolenprogramm die Programmiersprache zu erkennen und kopiert dann ein entsprechendes Pack in das Projekt, das sowohl ein Dockerfile als auch ein frei anpassbares Helm Chart enthält. Draft schafft es, sehr nahe an eine Heroku-ähnliche Developer Experience heranzukommen, doch einige Fragen bleiben auch hier ungeklärt. So kann das erstellte Chart beispielsweise nach der Erstellung nicht mehr geupdated werden, wodurch man letztlich doch nicht weit entfernt ist von der einmaligen Erstellung des Manifest via Copy and Paste.

Mit einem ähnlichen Ansatz wie Draft lässt sich auch mit dem Open-Source-Tool DevSpace CLI ein flexibel anpassbares Helm Chart erstellen. Der Clou bei diesem Chart ist jedoch, dass es so aufgebaut ist, dass man die Templates in der Regel nicht direkt verändern muss. Das erlaubt es, mittels devspace update chart immer auf dem neusten Stand zu bleiben. Sollte man trotz der vielen Einstellungsmöglichkeiten mit den vordefinierten Templates an seine Grenzen stoßen, kann man zusätzlich Custom-Templates hinzufügen, die beim Update nicht verloren gehen.

Die Vereinfachung der Erstellung von Kubernetes Manifests und Helm Charts ist eine notwendige Voraussetzung, um Entwickler in die Lage zu versetzen, ihre Anwendungen für ein Kubernetes-basiertes Deployment vorzubereiten. Die Community hat hier bereits einige sinnvolle Ansätze entwickelt und entsprechende Open-Source-Projekte gestartet (Tabelle 1). Doch wenn Kubernetes wirklich anwenderfreundlich werden soll, dann muss das Deployment von Anwendungen mit Kubernetes ebenfalls vereinfacht werden.

Projekt Setup Automatic Deployments Logging und Debugging
Dockerfile Generation Chart Generation instant GitOps Logstreaming Code-Sync Service Proxy Debugging
Draft
DevSpace CLI
Gitkube
Knative
Kompose (✓)
ksync
Skaffold
squash
Stern
Tilt
Telepresence

Tabelle 1: Open-Source-Dev-Tools für Kubernetes im Überblick

Automatisierung des Deployment-Workflows

Der Prozess, Anwendungen zu Kubernetes zu deployen, sieht in der Regel wie folgt aus:

    1. Man erstellt ein Docker Image aus dem entsprechenden Dockerfile.
    2. Man taggt das Image und legt damit fest, zu welcher Registry es gepushed werden soll.
    3. Man authentifiziert sich mit den entsprechenden Credentials gegenüber der Image Registry.
    4. Man pusht das Image zur Registry.
    5. Man erstellt ein Image Pull Secret, mit dem Kubernetes das Image von der Registry pullen kann.
    6. Man erstellt die anwendungsspezifischen Kubernetes-Ressourcen (Deployments, StatefulSets, Services, Ingresses etc.) ggf. mittels Helm Chart.

Während man bei Platform-as-a-Service-Umgebungen wie Heroku lediglich ein Command für das Deployment benötigt, zeigt sich, dass der Prozess mit Kubernetes deutlich aufwendiger für Entwickler wird. Regelmäßiges Deployment von Anwendungen in eine produktionsähnliche Staging-Umgebung ist jedoch wichtig, um die Funktionsfähigkeit einer Software in der späteren Ausführumgebung zu gewährleisten und um Mängel frühzeitig zu erkennen und zu beheben. Natürlich könnte man den oben genannten Prozess mit CI-/CD-Tools wie Jenkins automatisieren, doch die Konfiguration einer solchen Pipeline ist ebenfalls nicht trivial und insbesondere in der frühen Entwicklungsphase eines Projekts oft aus Zeit- und Kostengründen nicht angebracht.

Im Kubernetes-Ökosystem gibt es jedoch auch für dieses Problem bereits einige spannende Projekte. Tools wie Skaffold, Tilt, Draft und DevSpace CLI lassen Entwickler mit wenigen Commands eine lokal ausführbare Pipeline erstellen, die entweder durch Ausführen eines einzelnen Commands durchläuft oder sogar vollautomatisiert nach vorgegebenen Triggern gestartet wird. So lassen sich alle hier genannten Tools so konfigurieren, dass sie bei jeder Änderung der Sourcecodes die Staging-Instanz des Entwicklers updaten. Das spart enorm viel Zeit und macht Anwendungsentwicklern das Testen von Anwendung innerhalb von Kubernetes deutlich einfacher; insbesondere weil diese Tools in der Regel einfache Konfigurationsdateien generieren, die ein Entwickler erstellen und dann direkt über das Version-Control-System (z. B. Git) zusammen mit dem Sourcecode speichern kann. So kann auch der Rest des Teams diesen Workflow ganz ohne Detailkenntnisse in Sachen Kubernetes-Deployment nutzen.

Daneben gibt es außerdem Projekte wie Gitkube von Hasura oder die noch sehr junge Knative-Initiative, die es Entwicklern ermöglichen, das sogenannte GitOps-Prinzip für Kubernetes Deployments anzuwenden. Dabei wird ein Build- und Deployment-Prozess durch ein einfaches git push gestartet. Während Knative noch in den Kinderschuhen steckt und von den Entwicklern noch als Alphaversion bezeichnet wird, ist Gitkube bereits stabiler, scheint aber leider nicht mehr aktiv weiterentwickelt zu werden.

Verbesserung von Logging und Debugging

Neben einfachen und schnellen Deployments sind vielfache Möglichkeiten für das Logging und Debugging von Fehlern sehr wichtig für die Steigerung der Produktivität von Softwareentwicklungsprozessen. Wer bislang überwiegend die Befehle kubectl describe, kubectl logs sowie kubectl exec zum Aufspüren und Analysieren von Fehlern nutzt, wird feststellen, dass diese Art des Debuggings auf Dauer extrem ineffizient ist. Abhilfe können hierbei Log-Tailing-Tools wie Stern oder voll umfängliche Microservices-Debugger wie squash bieten. Während squash als IDE-Plug-in genutzt wird und Entwicklern erlaubt, Breakpoints in verschiedenen Services direkt in der IDE zu setzen, hat vor kurzem das Konzept der non-breaking Breakpoints Aufsehen erregt. Das Tool Rookout erlaubt Entwicklern sogenannte non-breaking Breakpoints in bereits laufenden Anwendungen zu definieren und Echtzeitdaten über die Ausführung des Codes an der entsprechenden Codestelle zu sammeln.

Neben diesen Debuggingtools können natürlich auch klassische Remotedebugger eingesetzt werden. Ein hilfreiches Kubernetes-Feature für das Anschließen von Remotedebuggern ist dabei das sogenannte Port-Forwarding, das kubectl bereits von Haus aus bietet. Mit Port-Forwarding lässt sich der Traffic, der auf lokalen Ports auf dem Entwicklerrechner ankommt, direkt zu remote Ports innerhalb der in Kubernetes laufenden Pods weiterleiten. Da die Verbindung dabei über einen TLS-geschützen Tunnel über den Kubernetes API-Server läuft, muss man keine zusätzlichen Verbindungsverschlüsselungen konfigurieren und kann Remotedebugger sehr einfach auf localhost verbinden. Um den manuellen Aufwand zu reduzieren kann man außerdem Tools wie Skaffold oder DevSpace CLI nutzen, um das Port-Forwarding automatisch auch für mehrere Pods gleichzeitig zu starten.

Neben der Verwendung von Logging- und Debuggingtools ist es manchmal auch hilfreich, Änderungen direkt unmittelbar innerhalb der Container zu testen. Für diesen Fall gibt es zwei grundlegende Optionen: proxy-basierte und sync-basierte Entwicklertools. Telepresence, das als Sandbox Project innerhalb der CNCF gilt, fällt dabei in die erste Kategorie. Folgt man dem Microservices-Architekturpattern, so kann man mit Telepresence einen der Services lokal auf seinem Rechner ausführen und der Telepresence-Client sorgt dafür, dass der Networktraffic zwischen dem lokal ausgeführten und den übrigen, im Cluster laufenden Services so abläuft, als würde der lokale Service direkt im Kubernetes-Cluster laufen. Diese Methode ist praktisch, um einzelne Services lokal zu debuggen, hat aber erhebliche Limitierungen, insbesondere wenn der Entwickler auf einem Windows-Rechner arbeitet.

Sync-basierte Entwicklertools haben weniger Einschränkungen, da der zu entwickelnde Service nicht lokal ausgeführt wird, sondern direkt im Cluster läuft. Tools wie ksync, Tilt und DevSpace CLI erlauben es Entwicklern, File-Watcher zu starten, die Sourcecodeänderungen zwischen Ordnern auf dem Entwicklerrechner und den Containern, die in Kubernetes laufen, in Echtzeit zu synchronisieren. Ändert man also mittels Codeeditor oder IDE eine Datei, wird diese Änderungen unmittelbar auch im laufenden Container abgebildet. Das kann insbesondere bei Verwendung sogenannte Hot-Reloading-Tools (z. B. nodemon für Node.js) hilfreich sein, wenn man möchte, dass der Code direkt innerhalb des Containers neu gebaut und wieder ausgeführt wird. Voraussetzung dafür ist natürlich ein entsprechendes Dockerfile für die Entwicklung zu nutzen, dass die notwendigen Build-Tools mit in das Container-Image baut und den Entrypoint so setzt, dass das Hot-Reloading-Tool statt des für den Produktivbetrieb gedachten Start-Scripts ausgeführt wird.

Fazit

Kubernetes gilt als kompliziert und wenig anwenderfreundlich. Doch es gibt zahlreiche Möglichkeiten, die Developer Experience von Kubernetes zu verbessern. Neben einer ganzen Reihe von Dev-Tools, die die Kubernetes-Community über die letzten Jahre hinweg entwickelt hat, müssen wir darauf achten, dass Kubernetes so für Entwickler bereitgestellt wird, dass diese es nutzen können, ohne von seiner Komplexität eingeschüchtert zu werden. Es liegt in unserem Interesse, Kubernetes als einen Service für Anwendungsentwickler bereitzustellen, um ihnen schnell verfügbare und einfach bedienbare Deployment-Umgebungen zu bieten, die möglichst nah an der späteren Produktivumgebung sind. Erreichen wir dieses Ziel gemeinsam mit Entwicklern und Administratoren, dann wird das schlechte Image vom komplizierten Kubernetes künftig der Vergangenheit angehören.

Geschrieben von
Lukas Gentele
Lukas Gentele
Lukas Gentele ist Gründer und Geschäftsführer der covexo GmbH mit Standorten in Mannheim, Ludwigshafen und Berkeley (Kalifornien). Mit seinem Team arbeitet er an Open-Source-Tools für Kubernetes und betreibt seit 2018 den ersten Hostingservice für Kubernetes Namespaces.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
4000
  Subscribe  
Benachrichtige mich zu: