Warum ein Service Mesh?

Die verfügbaren Ressourcen von Kubernetes sind in vielen Fällen zum Betrieb eines Angebots im Web ausreichend. Bei komplexeren Webseiten jedoch, die über einen längeren Zeitraum betrieben und gewartet werden, kommt man um ein flexibleres und dynamisches Routing nicht herum. Denn im Lebenszyklus einer jeden Webapplikation kommt der Zeitpunkt, an dem man eine neue Version testen möchte oder Teile der Anwendung nur speziellen Nutzergruppen anzeigen will. Dabei sollen im Wesentlichen zwei Dinge getestet werden:

Beide Punkte erfordern umfangreiche Messungen von Metriken und Verhalten. Auf Seite des Browsers werden beispielsweise Laufzeitverhalten, Klicks, Referrer, SEO oder Mausbewegungen aufgezeichnet. Auf der Seite des Backends zählen zu den Metriken: Anzahl der Requests, URLs, benötigte Prozessorzeit, verbrauchter Speicher, fehlerhafte oder zu lange dauernde “Sub”-Requests und fachliche Werte wie Umsätze. Bei all dem ist ein funktionierendes Produkt am Markt zu kostbar und das Risiko zu hoch, um eine Änderung gleich für 100% der Nutzer live zu schalten. Die Anfragen müssen prozentual oder anhand gewisser Parameter (z.B. bestimmte Mobilgeräte, Browser, Nutzer) gesteuert werden. Der Anteil des Traffics soll über mehrere Tage hinweg und unter ständiger Beobachtung der technischen und fachlichen Metriken in Schritten von 0% auf 100% erhöht werden. Das alles möglichst leichtgewichtig, ohne Code oder Deployments zu verändern. Mit Kubernetes Bordmitteln ist dies alles in gewissem Umfang erreichbar. Ingress- und Service-Ressourcen oder Labels bieten die notwendige Flexibilität. Allerdings ist das nicht besonders komfortabel. Unter anderem hier setzen die Konzepte der Service Meshes an. Istio, als einer der bekanntesten Vertreter, kann aber noch mehr als Traffic Management. Er beherrscht ebenso diverse Resilience Pattern und unterstützt das Aufspüren von Fehlern.

Traffic Management

Wie oben gezeigt ist das Aufteilen des Traffics bei modernen Webseiten eine Notwendigkeit. Istio unterstützt das durch sogenannte Routing Regeln. Diese werden in Kubernetes als Custom Resources hinterlegt und können somit jederzeit dynamisch neu konfiguriert werden. Sie erlauben eine inhaltsbasierte Traffic-Steuerung, z.B. nach Inhalt eines Cookies oder dem User Agent. Zusätzlich oder alternativ dazu kann eine prozentuale Aufteilung des Traffics konfiguriert werden. Sie ist unabhängig von der aktuellen Skalierung der Infrastruktur (also der Anzahl der laufenden Pods innerhalb eines Load Balancing Pools). Das kann man mit Kubernetes Services und Ingress nur mit Mühe erreichen.

Robustere Infrastruktur

Resilience Pattern

Moderne Architekturen sind komplex und bestehen aus einer Vielzahl von kleineren Servicen, die für das Anzeigen einer einzelnen Seite aufgerufen werden müssen. Bei einer solchen Kette von Aufrufen können eine Vielzahl von Fehlern und daraus resultierende Folgefehler auftreten. Istio minimiert die Auswirkungen solcher Fehler durch einige Resilience Patterns. In den meisten Fällen sollte diese Maßnahmen zur Absicherung der Applikation genügen. Der Code der Service kann somit weitgehend frei von eigenen Implementationen der Resilience Patterns bleiben. Unter Anderem ermöglicht Istio:

Load Balancing

Ein Kubernetes Service macht ein einfaches Round Robin Load Balancing unter den Pods, deren Labels seinem Selector entsprechen. Dies ist nicht immer die beste Strategie, da sie andere Metriken außer Acht lässt. Isio bietet aus diesem Grund neben den einfachen Vertretern wie Random oder Round Robin den zusätzlichen Algorithmus Weighted Least Request an, der die Anzahl aktiver Requests mit einbezieht. Dies kann helfen, die Last besser zu verteilen.

Fehlersimulation und Test

Neben dem Testen einer Applikation durch zufälligen Beenden von Services sind langsame oder zeitweise fehlerhafte Services sowohl schwieriger zu handhaben als auch schwieriger zu simulieren. Istio unterstützt solche Testszenarien durch das Verzögern oder Abbrechen von HTTP Requests zu einem einstellbaren Prozentsatz.

Bessere Überwachung

Ein sehr wichtiges Thema der heutigen vielfältigen Microservice-Landschaft ist Logging, Tracing und Monitoring. Natürlich kann ein Service Mesh keinen fachlichen Code instrumentieren, somit fehlen die spezifischen fachlichen Metriken und Logausgaben. Den Datenverkehr aber kann er an seinen Schnittstellen abgreifen. Da die Servicenamen der Applikation bekannt sind, ergeben sich alleine daraus schon hilfreiche Erkenntnisse. Unter anderem durch:

Istio und Kubernetes

Cloud Native

Applications adopting the principles of
Microservices packaged and delivered as
Containers orchestrated by
Platforms running on top of a
Cloud infrastructure

Cloud Native ist ein Begriff, der nicht nur beschreibt, dass wir Microservices, Container und eine Plattform wie Kubernetes verwendet sollen. Er sagt auch, dass bestimmte Aufgaben, wie z.B. zeitlich wiederkehrende endliche Workloads (wie CronJobs) oder Service Discovery ebenso von der Plattform übernommen werden sollen, wie Scheduling, Health Checks, Self Healing, TLS Terminierung oder Rate limiting. Hinter allem steckt das Ziel der Applikationsorientierung für alle beteiligten Rollen (Dev, OPS, etc.). Kein Code soll eine nichtfunktionale Anforderung implementieren, die die Plattform nicht viel besser erfüllen kann. Notwendig soll alleine die Geschäftslogik sein.

Istio ist Cloud Native und so konzipiert, dass möglicht wenig Eingriffe in die vorhandenen Komponenten der Applikation notwendig sind.

Architektur von Istio

Hilfreich ist das Konzept „logischer Host“ von Kubernetes. Es ist ebenso nativ in der Container Runtime rkt vorhanden. Realisiert wird das durch die sogenannten Pod Ressource. Dabei werden die darin befindlichen Container immer gemeinsam, im selben Kontext (selbe IP, Zugriff untereinander über localhost) und auf derselben physikalischen Node gestartet. Istio z.B. verwendet dabei das folgende Sidekick Container Pattern:

Sidekick Container Pattern
Sidekick Container Pattern

Das macht es Istio möglich, sämtlichen Datenverkehr von und zu dem Main App Container über den Proxy zu leiten. Der Proxy heißt in diesem Fall Envoy und wird durch einen simplen Befehl in das eigene Applikations-YAML eingefügt:

kubectl -n myapp apply -f <(istioctl kube-inject -f myapp.yaml)

Zusammen mit einem Istio Ingress Controller und einigen Management-Pods ergibt das einen funktionsreichen Service Mesh, ohne dass dabei ein großer Aufwand für Installation und Konfiguration entsteht.

Aktuelle Vertreter

Verschiedene Implementationen eines Service Meshes gibt es schon seit geraumer Zeit. Die Geschwindigkeit, in der neue Features oder Frameworks entwickelt werden, macht einen Vergleich schwer. Grundsätzlich sind die grundlegenden Funktionen aber ähnlich. Im Umfeld von Kubernetes allerdings, sind bereits einige Komponenten vorhanden, die ein Service Mesh nutzen kann. Ein Mesh, der auch alleine betreiben werden kann oder auch für andere Cluster Manager funktioniert, schleppt einigen unnötigen Ballast mit sich herum. Einen Ballast, den sogenannte Kubernetes Native Implementierungen, wie Conduit oder Istio, nicht haben. Sie verwenden Custom Resources um Konfigurationen zu hinterlegen und das Operator Pattern zum Propagieren von Änderungen im Mesh. In vielen Fällen kann zur Konfiguration sogar die normale Kubernetes CLI kubectl verwendet werden.

Wer braucht nun einen Service Mesh?

Ein Service Mesh bietet die notwendige Erweiterung an Funktionalität zum Betrieb eines großen Webportals. Im Falle von Kubernetes ist der Service Mesh Istio ein Teil der Infrastruktur und folgt somit dem Cloud Native Paradigma, übliche nichtfunktionale Anforderungen und Routineaufgaben durch die Plattform ableisten zu lassen. Das ist großartig, da man dies durch ein simples Redeployment der eigenen Applikation quasi geschenkt bekommt. Weder sind Anpassungen des Codes noch neue Container notwendig. Dies und seine umfangreiche Funktionalität macht ein Service Mesh wie Istio so sexy.