Die Einführung von Microservices verschiebt einen großen Teil der Komplexität der Anwendungsentwicklung in die Infrastruktur. Vorgehen und Werkzeuge müssen sich grundlegend ändern, um dieser Komplexität gerecht zu werden. Von diesen Änderungen stark betroffen sind:

  • Bereitstellung von Microservices im Betrieb
  • Versionierung und Releasemanagement mit Kubernetes
  • Monitoring von Microservices

Monolithische Anwendungen und deren Handhabung sind in der Regel nach jahrelanger Erfahrung gut verstanden. Dieser Blogbeitrag gibt eine Übersicht, welche Punkte beim Übergang zu Microservices aus betrieblicher Sicht beachtet werden müssen.

Stellen wir uns als Analogie ein Bild vor, das an die Wand genagelt wird: Altes Bild abhängen, neues Bild hinhängen. Falls es Probleme gibt, altes Bild (als Rollback) wieder hinhängen.

Bei Microservices haben wir es nun mit einer großen Anzahl von Deployments zu tun, wovon jedes eine eigene Version besitzt, d.h. unser Bild wird zum Puzzle, bei dem jedes Einzelteil eine eigene Version besitzen kann. Hier kann ein Rollback ziemlich schwierig werden und wir wollen auch nicht jedes Puzzleteil einzeln an die Wand hängen.

Beginnen wir damit, wie das Microservice-Puzzle im Betrieb bereitgestellt und verwaltet werden kann.

Bereitstellung von Microservices im Betrieb

Typische Betriebsthemen im Microserviceumfeld umfassen:

  • Replizierung und Skalierung (die richtige Anzahl starten)
  • Loadbalancing
  • Health check (lebt die Anwendung noch)
  • Wiederherstellung/Aufrechterhaltung des gewünschten Zustandes (z.B. falls ein Health check nicht antwortet)
  • Bereitstellung/Veröffentlichung des Service (myService:7777)
  • Verteilung auf die Hardware
  • Versionierbarkeit/Nachvollziehbarkeit

Diese Punkte werden im Wesentlichen durch Kubernetes abgedeckt. Man kann Kubernetes auch als Laufzeitumgebung für Container bezeichnen.

Setzt man kein Kubernetes ein, wird man eigene Lösungen für die aufgeführten Punkte finden müssen – und keiner der Punkte ist trivial.

Auf den Punkt Versionierbarkeit soll im Folgenden weiter eingegangen werden. Denn Kubernetes enthält erst einmal nur die Möglichkeit der Versionierung. Um diese tatsächlich zu implementieren ist, wie der nächste Abschnitt zeigt, noch einiges zu tun.

Versionierung und Releasemanagement mit Kubernetes

Grundsätzliche Anforderungen an das Releasemangement sind die Beantwortung folgender Fragen:

  • Welche Version ist in welcher Umgebung?
  • Welche Features (aus Geschäftssicht) sind in welcher Umgebung?
  • Was muss ich für ein Rollback tun, bzw. welche Features verliere ich im Falle eines Rollbacks?

Wirklich relevant ist dabei die Frage nach den Features. Die Versionen sind Hilfsmittel, um Features an eine Softwareversion zu knüpfen.

Bei einer monolithischen Anwendung ist die Versionierung relativ klar. Werden hingegen jede Menge Microservices von unterschiedlichen Teams in eine Zielumgebung deployed, wird der Gesamtzustand der Zielumgebung schnell unklar: „Seit ca. 30min. funktioniert die QA-Umgebung nicht mehr richtig, welcher der 8 zuletzt deployten Microservices könnte das Problem sein. Und wenn einer davon zurückgerollt werden muss, ist das dann der Einzige?“

Setzt sich eine Anwendung nun aus vielen Microservices zusammen, stellt sich die Frage, auf welcher Ebene man nun versionieren soll. Hierzu gibt es verschiedene Ansätze (und Mischungen aus diesen Ansätzen):

Versionierung auf Ebene der Microservices:

Für den Entwickler ist alles wie immer. Der Microservice wird versioniert, wie früher der Monolith. Es kann allerdings sein, dass ein neues Feature Änerungen in mehreren Microservices benötigt. Bei diesem Ansatz muss Buch geführt werden, welches Feature welche Microservice in welchen Versionen benötigt.

Versionierung über alle Microservices

Einfach gesagt befinden sich alle Microservices im selben Source Code Repository und jeder Tag versioniert automatisch alle Microservices. Das sieht aus Sicht des Repositories erstmal nicht so elegant aus, erspart aber die zusätzliche Buchführung aus obigem Ansatz.

Gar keine Versionierung

Dieser Ansatz kann tatsächlich von Teams verfolgt werden, die so gut aufgestellt sind, dass die Umsetzung eines Features oder das Fixen eines Bugs fast immer schneller geht als diesen zu verwalten. Die Gefahr dieses Ansatzes besteht darin, dass das Team doch nicht so gut aufgestellt ist, wie gedacht.

Kommen wir auf die Versionierbarkeit von Kubernetes-Artefakten. Diese sind – als Textdatei – alle wunderbar versionierbar, ABER bei zunehmender Zahl von Microservices steigt nicht nur die Anzahl, sondern auch die Komplexität der zu verwaltenden Artefakte stark an.

An dieser Stelle kommen Tools wie beispielsweise Helm zum Einsatz, die verschiedene Kubernetes-Artefakte zu deploybaren Objekten höherer Ordnung (Helm Charts) zusammenbinden. Das Helm Chart einer Anwendung kann aus mehreren Deployments, Services und weiteren Kubernetes Artefakten bestehen – aus Betriebssicht wird nur das eine Helm Chart ähnlich einer monolithischen Anwendung deployed.

In der Puzzleanalogie versuchen wir nicht mehr ein Puzzle aufzuhängen, sondern heften einen Zettel mit der gewünschten Beschreibung aller Puzzleteile und ihrer Versionen an die Wand. Das Zusammenpuzzeln der Teile und Aufhängen des fertigen Bildes übernimmt Kubernetes.

Monitoring von Microservices

Klassisches Monitoring kümmert sich um die Überwachung von Ressourcen (CPU, RAM, Filesystem,…) auf einzelnen Servern. Verteilte Anwendungen und Microservice stellen in diesem Zusammenhang eine Herausforderung dar: Ein Prozess läuft nicht mehr auf fest zuordbaren Ressourcen, sondern im Container, vom Deployment gemanaged und kann vom Cluster jederzeit auf komplett anderer Hardware neu gestartet werden. Zusätzlich zu den einzelnen Servern und Prozessen müssen also auch Metriken aus Gesamt-Clustersicht betrachtet werden. („Wieviel RAM steht im Gesamtcluster noch zur Verfügung?“, „Läuft die geforderte Anzahl von Pods über alle Clusterknoten?“).

Zudem besteht die Anforderung viele Server und Ressourcen auf einmal zu monitoren.

Ein Standardstack zum Monitoring für Kubernetes besteht aus Prometheus (ggf. mit Exportern) und Grafana. Prometheus sammelt über Scraper diverse Metriken ein, die von den Resourcen (Container, Server, Kubernetes-Cluster selber,…) bereitgestellt werden (Pull-Prinzip).

Diese Metriken können von Exportern abrufbar gemacht werden, falls die Ressource selber dies nicht beherrscht. Beispielsweise sorgt ein Node-Exporter dafür, dass jeder Node Metriken auf Maschienenlevel zur Verfügung stellt (CPU, RAM, Plattenplatz,…).

Die Metriken selber können in Grafana Dashboards visualisiert dargestellt werden.

Auch die Anwendungen selbst können Metriken bereit stellen um besser kontinuierlich überwacht werden zu können. Z.B: Anzahl Requests, Ladezeiten, Anzahl aufgetretener Fehler,….

Zusätzlich werden Alarme definiert (‚Über 5 Container-Neustarts in 10min‘, ‚Mehr als 80% des RAMs im Cluster belegt‘,….), die dann Nachrichten an definierte Endpunkte senden (Slack-Message, email, SMS,…).

Ziel ist es, eine Anwendung ‚observable‘ zu machen. War man bisher bemüht, möglichst viel brauchbare Information in ein Logfile zu schreiben, so soll heute diese Information idealerweise aktiv gemonitored werden, um direkt (und ggf. automatisiert) auf bestimmtes Anwendungsverhalten zu reagieren.

Die Anwendung wird hierbei direkt gemonitored (Error-Zähler, Antwortzeiten von Remote-Verbindungen, Anzahl bestimmter Funktionaufrufe,…) und muss solche Werte auch liefern (‚obervable‘ sein). ‚Observability‘ ist ebenso wie ‚Testbarkeit‘ eine wichtige Anwendungseigenschaft, die Zeit, Kosten und den Ruf eines Managers retten kann.

Das indirekte Monitoring der Anwendung (etwa über ihren Ressourcenverbrauch wie CPU, RAM) kommt noch on top, da Ressourcenverbrauch ja immer im Kontext des gesamten Clusters und nicht eines einzelnen Servers zu sehen ist.

Ähnlich wie bei der Versionierung besteht die Kunst auch hier darin durch geeignete Aggregation viele einzelne Ressourcen in einem Gesamtbild (und nicht zahlreichen Puzzleteilen) zu betrachten.

Fazit

Der Betrieb einer Landschaft aus vielen Microservices erfordert Änderungen an den bekannten Vorgehensweisen, ist mit den diskutierten Werkzeugen und Strategien aber gut beherrschbar.

In der Puzzle-Analogie generiert Helm Beschreibungen aller Puzzleteile (inkl. Versionsnummern) und Kubernetes kann diese automatisch korrekt zusammensetzen. Aus Betriebssicht ist die Vorgehensweise wieder wie beim Monolith.

Ohne diese Vorkehrungen bildet ein Umstieg in die Microservicewelt ein ständiges Risiko für das Unternehmen.

Mit den Punkten Bereitstellung, Versionierung/Releasemanagement und Monitoring sind die wichtigsten Vorbereitungen für den Aufbruch in die Welt der Microservices getroffen.

Dies sind natürlich nicht die einzigen Bereiche, in denen umgedacht werden muss. Über diese drei Punkte sollte man sich aber auf jeden Fall Gedanken gemacht haben.

Ein Gedanke zum Schluss: Beim Umgang mit Microservices sollte man sich ständig die Frage stellen: ‚Funktioniert das, was ich gerade tue auch mit der 10-fachen Anzahl von Services?‘ – dann ist noch Zeit, Maßnahmen zu ergreifen.


Jetzt teilen auf:

Jetzt kommentieren