Service Mesh – die unverzichtbare Infrastruktur für Microservices?
Die rosarote Brille haben viele Architekt*innen und Entwickler*innen beim Thema Microservices mittlerweile abgelegt. Schließlich sind die vielen Vorteile wie Auslieferungsgeschwindigkeit, Skalierbarkeit und Technologieunabhängigkeit nur im Tausch gegen viele neue Probleme zu haben. Anders als Monolithen bilden Microservices ein verteiltes System, das schwerer zu kontrollieren, zu observieren und abzusichern ist. Außerdem kommunizieren die Microservices über das Netzwerk und sind dadurch nicht nur langsamer, sondern auch weniger stabil.
Dass Microservices nach wie vor beliebt sind beweist aber, dass ihre Vorteile häufig schwerer wiegen als die zusätzliche Komplexität. Ein Service Mesh verspricht nun, diese Komplexität zu reduzieren. Es verlagert Funktionen in die Infrastruktur, die bis jetzt in jedem Microservice implementiert werden mussten. Jeder Microservice wird somit schlanker und damit weniger komplex. So kann der Fokus bei der Entwicklung wieder zur Fachlichkeit zurückkehren. Doch ein Service Mesh ist keine Magie, sondern basiert auf komplexen Komponenten, die unsere kognitiven und technischen Kapazitäten herausfordern.
Was ist ein Service Mesh?
Als Infrastruktur wird die Umgebung einer Anwendung bezeichnet, die keine fachlichen, sondern technische Funktionen erfüllt. Beispiele dafür sind ein Container-Orchestrierer wie Kubernetes oder ein Monitoring-System wie Prometheus. Ein Service Mesh (übersetzt "Service-Netz") gehört zur Infrastruktur. Anders als Kubernetes und Prometheus steuert ein Service Mesh jedoch das Laufzeitverhalten und kann damit auch als Applikations-Infrastruktur betrachtet werden.
Ein Service Mesh macht intensiven Gebrauch vom Sidecar-Pattern. Der Begriff ist abgeleitet vom Beiwagen eines Motorrads. Wenn Funktionen, die von mehreren Services benötigt werden, in eine Anwendung ausgelagert werden, wird diese als Sidecar bezeichnet. Das Sidecar wird jedem Service zur Seite gestellt. Typische Funktionen, die auf diese Weise ausgelagert werden, sind Ver- bzw. Entschlüsselung, Authentifizierung oder das Sammeln und Bereitstellen von Metriken. Die Kommunikation zwischen Service und Sidecar findet über Standard-Netzwerkprotokolle statt. Ein Sidecar kann damit unabhängig von Implementierungsdetails des Service genutzt werden. Häufig besteht ein Sidecar aus einem Service Proxy, durch den automatisch alle Netzwerkverbindungen geleitet werden. Abb. 1 stellt die Nutzung von Bibliotheken und die Auslagerung in Sidecars gegenüber.
Mit einem Sidecar wird eine Anwendung also erweitert, ohne dass sie davon Kenntnis haben oder verändert werden muss. Auch in einem Service Mesh wird neben jeden Microservice ein solcher Service Proxy als Sidecar platziert. Die Gesamtheit aller Service Proxys wird in einem Service Mesh als Data Plane bezeichnet. Dieser Begriff ist darauf bezogen, dass jegliche Kommunikation zwischen den Services über die Service Proxys stattfindet, die Metadaten zum Netzwerkverkehr erfassen und bereitstellen.
Das Konzept von Sidecars gab es schon lange vor dem Service Mesh. Die Sidecars wurden manuell bereitgestellt und das Netzwerk so konfiguriert, dass Anfragen den Service Proxy durchlaufen. Wenn jedoch Änderungen an der Konfiguration des Sidecars vorgenommen werden sollen, ist dies – insbesondere in größeren Systemen – mit viel manueller Arbeit verbunden. Ein Service Mesh kann als eine Erweiterung des Sidecar-Patterns aber vor allem als dessen Automatisierung betrachtet werden.
Die zweite Ebene des Service Mesh – genannt Control Plane – besteht aus Anwendungen, die mit den Service Proxys kommunizieren. Einerseits kann eine neue Konfiguration einmalig auf die Control Plane angewendet und automatisch an die Proxys verteilt werden. Andererseits sammelt die Control Plane die von den Service Proxys erfassten Daten und gibt sie an ein Monitoring-System weiter.
Service Mesh Features
In einem als Sidecar bereitgestellten Service Proxy können Funktionen untergebracht werden, die alle Microservices benötigen. Die Control Plane kann diese Funktionen steuern und die gesammelten Daten verarbeiten. Grundsätzlich kann ein Service Mesh Features in vier Bereichen bieten:
- Monitoring: Die Service Proxys zeichnen Metriken zur Netzwerkkommunikation auf. Diese werden regelmäßig an die Control Plane gesendet und dort von Monitoring-Systemen abgerufen und verarbeitet.
- Routing: Die Control Plane kann Routing-Regeln an die Proxys verteilen, die diese auf alle Anfragen anwenden. Die Regeln können auf Basis von HTTP-Metadaten wie URL-Segmenten oder Header formuliert werden.
- Resilienz: Ähnlich wie Routing-Regeln können auch Maßnahmen für die Widerstandsfähigkeit gegenüber Netzwerkfehlern oder Service-Ausfällen einmalig formuliert und von der Control Plane an die Proxys verteilt werden. Beispielsweise können Anfragen automatisch nach einem Zeitablauf abgebrochen (Timeout) und anschließend neu versucht werden (Retry).
- Sicherheit: Die Control Plane kann automatisch Zertifikate erstellen, entziehen und erneuern, sodass die Service Proxys Anfragen automatisch ver- und entschlüsseln können. Außerdem können – analog zu Routing und Resilienz – Autorisierungs-Regeln formuliert und lokal von den Service Proxys umgesetzt werden.
Monitoring
Eines der beeindruckendsten Features eines Service Mesh ist das flächendeckende Basis-Monitoring. Ohne dass Anwendungscode oder Konfiguration geändert werden muss, können Metadaten zum Netzwerkverkehr erfasst und aufbereitet werden. Dazu gehören unter anderem:
- Fehlerraten anhand von HTTP-Statuscodes,
- Latenz und
- Anfragen pro Sekunde.
Mit diesen Daten ist es möglich, ein Dashboard zum aktuellen Status des Microservice-Systems zu erstellen. In Abb. 3 ist das Dashboard Kiali für das populäre Service Mesh Istio zu sehen [1].
Die Visualisierung basiert ausschließlich auf Daten, die durch Service Proxys aufgezeichnet, an die Control Plane gesendet und von dort regelmäßig von einer mitgelieferten Prometheus-Instanz abgefragt werden. Ähnlich ist das Monitoring im Linkerd Service Mesh umgesetzt [2]. Anders als Istio ermöglicht es Linkerd, die Netzwerk-Metriken pro HTTP-Endpunkt aufzuschlüsseln, wie Abb. 4 des Linkerd Dashboards zeigt.
Sowohl Istio als auch Linkerd bereiten die Prometheus-Metriken nicht nur in den eigenen Dashboards sondern auch in vorkonfigurierten Grafana-Instanzen auf.
Ein Service Mesh kann außerdem Ende-zu-Ende-Tracing von konkreten Anfragen unterstützen, indem es automatisch Tracing-Daten an ein entsprechendes Backend sendet. Dafür müssen die Services jedoch bestimmte Header aus der eingehenden Anfrage in alle ausgehenden Anfragen kopieren.
Routing
Die Routing-Konfiguration wird über die Control Plane automatisch verteilt. Außerdem kann die Control Plane dafür sorgen, dass jeder Service Proxy ein aktuelles Abbild des Netzwerks hält, innerhalb dessen er Anfragen verteilen kann. Damit können die Service Proxys auch selbständig Load Balancing durchführen.
Die Service Proxys können pro Service auch sehr detaillierte Routing-Konfiguration umsetzen. Beispielsweise:
- Sende 90 Prozent der Anfragen an die Version 1 und 10 Prozent an Version 2 eines Service.
Sende alle Anfragen an api an Version 1 und alle Anfragen an api/v2 an Version 2. - Wenn der HTTP-Header locality=berlin gesetzt ist, sende 20 Prozent der Anfragen an Version 2.
Sende die restlichen 80 Prozent und alle Anfragen bei denen der Header anders gesetzt ist, an Version 1.
Mit derartigen Regeln können A/B-Tests und Canary Releases durchgeführt werden. Tools wie Flagger [3] setzen bereits auf einem Service Mesh auf und automatisieren das schrittweise Ausrollen eines Canary Releases.
Resilienz
In einer Microservice-Architektur ist kein Verlass auf das Netzwerk und auf die Verfügbarkeit der anderen Services. Aus diesem Grund werden häufig Bibliotheken eingesetzt, die diesem Problem mit Methoden wie Circuit Breaking, Retry und Timeout begegnen.
Circuit Breaking wendet das Prinzip einer elektrischen Sicherung auf die Kommunikation zwischen Microservices an. Ziel ist, das Gesamtsystem (Haus-bzw. Microservice-System) im Falle eines Fehlers (Kurzschluss bzw. ein instabiler Microservice) stabil zu halten. Dafür wird der fehlerhafte Teil zeitweise abgeschaltet. Eine elektrische Sicherung unterbricht bei der Gefahr für das Haus den gesamten Stromkreislauf. In einem Microservice-System hingegegen werden Service-Instanzen, die wiederholt Fehler produzieren, zeitweise vom Netzwerkverkehr abgeschirmt. Nach einer bestimmten Zeit werden wieder Anfragen zugestellt und damit geprüft, ob der Service sich von einer eventuellen Überlast erholt hat. Ein Circuit Breaker wird häufig mit Bibliotheken wie Hystrix implementiert, kann aber auch von einem Service Proxy umgesetzt werden. Der Proxy des absendenden Microservice sammelt Daten zur Fehlerhäufigkeit von Service-Instanzen, mit denen er kommuniziert. Wird die zulässige Anzahl von Fehlern überschritten, entfernt der Proxy den fehlerhaften Endpunkt zeitweise aus dem Pool potenzieller Empfänger von Anfragen.
Weitere verbreitete Maßnahmen gegen Fehler und Verzögerungen bei der Netzwerkkommunikation sind das Abbrechen von Anfragen nach einem bestimmten Zeitablauf (Timeout) und das automatische Neuversuchen (Retry) nach einem Timeout oder einem Fehler. Entwickler*innen können Retry und Timeout pro Service konfigurieren. Die Control Plane verteilt diese Konfiguration und die Service Proxys setzen sie um.
Sicherheit
In der Praxis wird häufig nur die in das Microservice-System ein- und ausgehende Kommunikation abgesichert, sodass Angreifer, die diese Hürde einmal überwunden haben, auf ein komplett ungeschütztes System treffen.
Eine weitere Aufgabe der Control Plane ist die Ausstellung von Zertifikaten (Certificate Authority) für die automatische beidseitige Authentifizierung von Netzwerkverbindungen (mTLS). Das manuelle Aufsetzen und Konfigurieren einer solchen Certificate Authority ist sehr aufwändig. Durch die Automatisierung mit einem Service Mesh kann die Gültigkeit der Zertifikate kurz gehalten und bei Bedarf annulliert werden. Falls Angreifer also doch Zugang zum System erhalten, kann so der Schaden begrenzt werden.
Da die Service Proxys von der Control Plane Zertifikate zur Verfügung gestellt bekommen, können sowohl Sender als auch Empfänger einer Netzwerkanfrage die Identität des jeweils anderen Partners verifizieren (beidseitige Authentifizierung/ mutual TLS) und den Inhalt der Anfrage verschlüsseln.
Ein Service Mesh kann neben beidseitiger Authentifizierung auch den Zugriff beschränken (Autorisierung). Beispielsweise kann Konfiguration formuliert werden, durch die ein Service nur unter einem bestimmten Pfad angefragt werden kann.
Die Preisfrage
Häufig wird beim Hype um Innovationen wie einem Service Mesh das Preisschild umschifft. Bei einem Service Mesh sind aber der Lernaufwand, die erhöhte Latenz und der zusätzliche Ressourcenverbrauch nicht zu unterschätzen.
Lernaufwand
Technisch gesehen ist ein Service Mesh ein starker Eingriff in ein Microservice-System. Die meisten Implementierungen versuchen diesen – aus gut nachvollziehbaren Gründen – so unsichtbar wie möglich zu machen. So ist die außen sichtbare Komplexität eines Service Mesh vorerst gering. Wenn die Service Proxys sich jedoch unerwartet verhalten, müssen die Entwickler*innen die Fähigkeit haben, die Ursachen zu finden. Dazu müssen sie die Komponenten eines Service Mesh und deren Zusammenspiel detailliert verstanden haben. Bei der Einführung eines Service Mesh muss außerdem das Konfigurationsmodell verstanden und umgesetzt werden. Der Lernaufwand ist je nach Service-Mesh-Implementierung aufgrund der Qualität der API, der Dokumentation und der Tools sehr unterschiedlich.
Latenz & Ressourcen
Die Einführung von vielen zusätzlichen Anwendungen für die Control Plane und vor allem die Data Plane führt logischerweise zu einem erhöhten Ressourcenverbrauch. Was sich allerdings nicht durch mehr Ressourcen beheben lässt, ist die Beeinträchtigung der Antwortzeit (Latenz). Jede Anfrage durchläuft bis zu zwei zusätzliche Anwendungen. Die Latenz verschlechtert sich in den meisten Fällen nur um wenige Millisekunden. Jedoch kann sie sich bei langen Verkettungen von Services auf eine relevante Zeit aufsummieren. Empfehlenswert ist in jedem Fall, ein Benchmark in der individuellen Umgebung durchzuführen. Dazu sollten Latenz und Ressourcenverbrauch mit und ohne Service Mesh gemessen und verglichen werden. Sinnvoll ist es dabei auch, mehrere Service Mesh Implementierungen zu vergleichen.
Service-Mesh-Implementierungen
Das Potenzial von Service Meshes ist nicht zu übersehen. So ist es auch nicht verwunderlich, dass Tech-Giganten wie Google, IBM/RedHat, AWS, Microsoft und HashiCorp entweder eigene Lösungen entwickeln oder sich an der Entwicklung von Schnittstellen beteiligen.
Istio
Die größte Aufmerksamkeit und gleichzeitig die höchsten Erwartungen richten sich an Istio (griechisch für "segeln"), das maßgeblich von Google und IBM entwickelt wurde. Es wurden keine Kosten und Mühen gescheut, die vielen Features zu bewerben und die Community zu ermutigen, Istio einzusetzen. Allerdings hat sich schnell gezeigt, dass es Istio an einer durchdachten, benutzerfreundlichen API und technischer Reife mangelt. Seit dieser etwas übermütigen Version 1.0 hat Istio sich konstant verbessert, allerdings ist dies, insbesondere die Verbesserung der API, ein langer Prozess. Denn teilweise ist die Komplexität von Istio auch gerechtfertigt. Anders als andere Service Meshes will Istio sich nicht auf Kubernetes, der führenden Plattform für den Betrieb von Containern, beschränken.
Linkerd
Es scheint so, als hätten die Entwickler*innen hinter dem ersten Service Mesh Linkerd vor zwei Jahren ähnliche Erfahrungen gemacht wie Istio heute. Auch die erste Version von Linkerd war sehr flexibel hinsichtlich der technischen Umgebung und hat Nutzer*innen mit zu vielen Konfigurationsmöglichkeiten überfordert. Als immer deutlicher wurde, dass Kubernetes sich zur Standard-Plattform entwickelt, hat Linkerd einen Neuanfang gewagt. Das neue Linkerd 2 ist ausschließlich mit Kubernetes nutzbar. Von dieser Einschränkung profitiert das Service Mesh immens, da es viele Annahmen über die Infrastruktur treffen kann. Linkerd 2 profitiert außerdem von den Erfahrungen mit Linkerd 1 was die Benutzbarkeit angeht. Anders als Istio weist Linkerd 2 eine sehr durchdachte und konsistente API vor. Im Vergleich zu Istio fehlen Linkerd 2 zum aktuellen Zeitpunkt noch die Features Tracing, Circuit Breaking und Autorisierung.
Service Mesh Interface
Im Mai 2019 hat Microsoft das Service Mesh Interface (SMI) vorgestellt, das aus einer yaml-Spezifikation für Service Mesh Features besteht [4]. Sie wurde unter anderem gemeinsam mit HashiCorp und Buoyant, der Firma hinter Linkerd, entwickelt. Service Meshes können mithilfe von Adaptern Kompatibilität zum SMI herstellen. Endnutzer*innen haben den Vorteil, dass sie sich nicht an die API eines konkreten Service Mesh binden, sondern die Service-Mesh-Implementierung austauschen können. Vielleicht noch interessanter ist das SMI für Tools, die auf einem Service Mesh aufsetzen. Anstatt sich an die API des konkreten Service Mesh wie Istio oder Linkerd zu binden, können Features auf Basis des SMI entwickelt werden. Die Tools können anschließend mit allen SMI-kompatiblen Service Meshes genutzt werden.
Sonstige
Neben Istio und Linkerd gibt es mittlerweile fünf weitere nennenswerte Service-Mesh-Implementierungen:
- HashiCorp Consul [5]: Ursprünglich war Consul eine Service-Discovery-Lösung, die sich heute als Service Mesh bezeichnet. Tatsächlich wurde Consul in den letzten Releases mit immer mehr Service Mesh Features bestückt.
- AWS App Mesh [6]: In beeindruckender Geschwindigkeit hat AWS ein eigenes Service Mesh entwickelt, das von AWS bereits für den Einsatz in Produktion empfohlen wird. Es ist kompatibel mit AWS Fargate, ECS, EKS und EC2 und mit AWS CloudWatch und X-Ray integriert.
- Red Hat OpenShift Service Mesh [7]: Hinter diesem Wortungetüm steckt ein für OpenShift konfiguriertes Istio Service Mesh.
- Mæsh [8]: Dieses brandneue Service Mesh für Kubernetes kommt aus dem Hause Containous, die auch das API Gateway Træfik entwickeln. Mæsh basiert auf Træfik [8], ist kompatibel mit dem Service Mesh Interface und installiert einen Proxy auf jedem Kubernetes Node statt für jede Service-Instanz.
- Kuma [9]: Die Webseite des API Gateway Kong [9] gibt bereits seit langem an, dass Kong auch als Service Mesh betrieben werden kann. Doch erst viele Monate später ist nun das Service Mesh Kuma von Kong erschienen, das überraschenderweise nicht auf Kong sondern auf dem leichtgewichtigen Envoy Service Proxy basiert, der auch von Istio, Consul und AWS App Mesh genutzt wird, Kuma gibt an, mit und ohne Kubernetes nutzbar zu sein.
Fazit
Der Hype ums Mesh ist im Angesicht der vielen Features rund um Monitoring, Routing, Resilienz und Security mehr als berechtigt. Ein Service Mesh scheint dem Netzwerk genau die richtige Menge Intelligenz hinzuzufügen. Durch die Abgrenzung von der Fachlichkeit wird vermieden, dass ein schwer wartbares Monstrum à la Enterprise Service Bus entsteht. Die beiden populärsten Implementierungen Istio und Linkerd haben aus ersten Fehlern gelernt und gelten mittlerweile als reif für den produktiven Einsatz.
Wer heute Microservices einführt, spart sich mit einem Service Mesh viel Implementierungsaufwand. Aber auch der größte Teil aktueller Microservice-Systeme würde mit hoher Wahrscheinlichkeit von einem Service Mesh profitieren. Voraussetzung dafür ist, dass das Team Kapazität für mehr kognitive Komplexität hat. Außerdem muss geprüft werden, ob die aktuelle Infrastruktur mit einem Service Mesh kompatibel ist und ob genug technische Ressourcen zur Verfügung stehen. Vor einer Einführung sollte außerdem die tatsächliche Latenz in der individuellen Umgebung gemessen werden.
Auch wenn die Performance in Randfällen noch nicht ausreichend sein mag: das Service Mesh wird wohl auf absehbare Zeit zu einem selbstverständlichen Bestandteil jeder Microservice-Architektur werden.
Erste Schritte gehen Interessierte am besten mit den offiziellen Tutorials von Linkerd und Istio [10]. In kürzester Zeit ist damit ein Service Mesh für eine Beispielanwendung aufgesetzt. Weitere Schritte führen verständlich durch die Service Mesh Features und deren Konfiguration.
Mehr Informationen zum Service Mesh generell und zu den Implementierungen bietet der kostenlose Service Mesh Primer [11]. Darüber hinaus zeigt er die Konfiguration von Service-Mesh-Funktionen wie Monitoring, Resilienz, Routing und mTLS mit Istio anhand eines praktischen Beispiels.
Vielen Dank an Anja Kammer, Lars Hupel und Martin Otten für das wertvolle Feedback und die Verbesserungsvorschläge zu diesem Artikel.
- Istio
- Linkerd
- Flagger
- Service Mesh Interface
- HashiCorp Consul
- AWS App Mesh
- Red Hat OpenShift Service Mesh
- Mæsh & Træfik
- Kuma & Kong
- Offizielle Tutorials von Linkerd und Istio
- Primer