Verwaltung Cloud-nativer Microservices mit Istio – Teil 1

Eine Einführung in Istio: Keine Angst vorm Service Mesh bei Microservices-Architekturen

Michael Hofmann, Markus Lackner

© Shutterstock.com / ProStockStudio

Je umfangreicher und verflechteter eine Microservices-Architektur wird, desto unübersichtlicher wird es. Man spricht hierbei vom sogenannten „Service Mesh“. Viele solcher Architekturen werden heutzutage nativ in der Cloud entwickelt und an diejenigen, die diese Microservices dann verwalten sollen, werden besondere Anforderungen gestellt. Das Tool Istio soll dabei behilflich sein, die Übersicht zu behalten.

Mit dem Einzug von Microservices als Grundlage einer modernen, verteilten Anwendungsarchitektur entstehen immer öfter komplexe Laufzeitumgebungen. Als Konsequenz stößt man bei der Verwaltung der steigenden Zahl an Services und Instanzen sehr schnell auf typische Problemstellungen. Das dabei entstehende Geflecht an Services wird als Service Mesh bezeichnet. Da die Microservices in der Regel auf Cloud-Plattformen betrieben werden und deswegen auch Cloud-nativ entwickelt wurden, wäre es wünschenswert, Werkzeuge zu besitzen, die bei der Verwaltung dieses „Service Mesh“ in der Cloud helfen. Istio ist ein Vertreter dieser Werkzeuge, welches helfen soll, diesen Zoo an Services in den Griff zu bekommen.

Service Mesh

Der Begriff Service Mesh umschreibt ein Geflecht von (Micro-)Services, welche über Netzwerkaufrufe miteinander interagieren und somit eine gesamtheitliche Anwendung bilden. Mit steigender Anzahl an Services wird das Aufrufverhalten der einzelnen Komponenten untereinander immer komplexer und somit auch schwieriger zu verstehen und zu beherrschen.

Eine Microservice-Anwendung, die zum Beispiel aus einer zweistelligen Anzahl von Microservices besteht, kann bezüglich der Verwaltung schon problematisch werden. In der Regel wird jede neue Version eines Microservices parallel zu vorhandenen Versionen desselben Microservices in Produktion deployt. Das geschieht deswegen, weil eine Abkündigung einer alten Version des Microservices nicht so einfach durchsetzbar ist und man die neue Version des Microservice, ohne Anpassungen an die älteren Versionen, mit weniger Nebeneffekten einfacher in Produktion bringt. Der Kompromiss, der dabei eingegangen wird, führt dazu, dass mehrere Versionen eines Microservices parallel existieren. Wenn durchschnittlich jeder Service in zwei oder drei Versionen parallel existiert, was nicht unüblich ist, so verdoppelt bzw. verdreifacht sich die Anzahl der Services ganz schnell. Eine Microservice-Anwendung, die ursprünglich mal mit beispielsweise fünfzehn Services gestartet hat, ist somit schnell bei knapp fünfzig Services angelangt.

Was gerne bei der Betrachtung der Services vernachlässigt wird, sind die notwendigen Datenbanksysteme, da ein Microservice in der Regel auch Persistenzanforderungen mit sich bringt. Die beteiligten Datenbankinstanzen gehören somit auch zum Service Mesh. Dabei kann man noch froh sein, wenn sich mehrere Versionen eines Microservices dieselbe Datenbank teilen können, weil man es geschafft hat, das Datenbankschema abwärtskompatibel zu gestalten. In Erweiterung an das obige Beispiel der Microservice-Anwendung kommen zu den knapp fünfzig Services auch noch mindestens fünfzehn Datenbank-Services hinzu. Ergibt als Zwischenergebnis ca. sechzig Prozesse.

Doch damit noch nicht genug. Die verteilte Anwendung sollte auch bezüglich Last und Ausfallsicherheit genügend Reserven haben. Eine Verdopplung der Service-Anzahl zur Erhöhung der Verfügbarkeit ist dabei das Minimum, das man einplanen sollte. Somit wurde in unserem Anwendungsbeispiel die magische Grenze von einhundert Prozessinstanzen gesprengt und das bei anfänglich nur fünfzehn Microservices. Zusätzliche Faktoren wie etwa Staging Umgebungen oder spezielle Multi Mandant Anforderungen können die Zahl nochmals deutlich erhöhen oder lassen somit mehrere komplexe Service Meshes entstehen die auch verwaltet werden müssen.

Als Konsequenz eines Service Mesh ergeben sich nun verschiedene Funktionalitäten, die ein Verwaltungswerkzeug bereitstellen muss. Angefangen bei Service Discovery und Load Balancing bis hin zu Resilienz und Failure Recovery. Damit wären zumindest die minimalen Notwendigkeiten der Service-zu-Service-Kommunikation abgedeckt. Für die Fehleranalyse ist es notwendig, die Aufrufketten der einzelnen Services nachverfolgen zu können, was in der Regel mit Tracing-Werkzeugen ermöglicht wird. Für die OPs-Kollegen sind Metrics und Monitoring für den stabilen Betrieb der verteilten Anwendung unerlässlich und ohne Security (Access Control und End-to-End Authentication) kommen die wenigsten Anwendung aus. Auch ein Rate Limiting ist manchmal notwendig, um eine Überlastung der verteilten Anwendung zu vermeiden. Darüber hinaus gibt es noch Anforderungen basierend auf weiterführenden Konzepten wie zum Beispiel A/B Testing oder Canary Releasing, um neue Versionen von Microservices geordnet in Produktion zu bringen. Abschließend könnte noch der Wunsch nach Content-based Routing bestehen, um Aufrufe untereinander mittels Aufrufinhalt gezielt zu steuern. Für Entwicklung, Tests aber auch die Reproduktion von Fehlverhalten ist es des öfteren notwendig, Fehler oder Time-outs gezielt bereitstellen zu können.

Typische Vertreter, die beim Beherrschen eines Service Mesh helfen sollen, basieren auf einem leichtgewichtigen Reverse Proxy, der als eigenständiger Prozess parallel zum Service-Prozess arbeitet. Dieser sogenannte Sidecar-Prozess kann dabei unter Umständen in einem eigenen Container, neben dem eigentlichen Service Container, deployt werden. Jede eingehende und ausgehende Service-Kommunikation erfolgt somit über das Sidecar. Darüber hinaus kommuniziert das Sidecar mit Service Registrys und den Identity-Providern oder kümmert sich um das Tracing der Aufrufketten. Durch den Ansatz eines Sidecars bekommt der eigentliche Microservice nichts von all dem mit, wodurch der Service-Entwickler keine Zeile Code schreiben muss, um diese Funktionalitäten zu ermöglichen. Das hat den enormen Vorteil, dass dieselbe Technologie für eine polyglotte Microservice-Anwendung verwendet werden und der Entwickler sich der eigentlichen Implementierung des Microservice widmen kann. Die Verwendung von speziellen Frameworks (Service Discovery, Resilienz, Circuit Breaker, …) ist nicht mehr notwendig.

Derzeit existieren als Vertreter dieser Service-Mesh-Werkzeuge:

Istio

Istio an sich ist nicht neu, sondern entstanden aus einem Zusammenschluss von mehreren Open-Source-Projekten. Die Urväter von Istio, namentlich Google, IBM und Lyft, haben sich dafür offiziell zu einer Kooperation zusammengeschlossen. Die Namensgebung wurde von Googles Projekt Istio übernommen. IBM beteiligt sich mit Amalgam8 und Lyft bringt Envoy in die Ehe mit ein. Somit bleibt das einzig Neue am heutigen Istio das Zusammenwirken der einzelnen Komponenten.

Im Detail wurden beim Zusammenschluss folgende Funktionalitäten der einzelnen Parteien eingebracht. Googles Istio liefert das inhaltsbasierte Request Routing zwischen unterschiedlichen Versionen eines Microservices. Somit kann auf Basis von geographischen Daten oder nur auf Basis des angemeldeten Users entschieden werden, welcher Service in welcher Version angesprochen werden soll. Hinzu kommt das Rate Limiting, die Auswertung von ACLs und die Sammlung der Telemetriedaten. Aber der wichtigste Teil ist die Integration von Istio in die Kubernetes-Laufzeitumgebung. Amalgam8 von IBM steuert unter anderem das Thema Service Discovery sowie Fehler-Resilienz zusammen mit dem Test der Resilienz und Load Balancing bei. Ein erweitertes Content-basiertes Routing ermöglicht außerdem noch ein Canary Releasing. Lyft liefert mit den Envoy Proxy, das sogenannte Sidecar und damit das Herzstück von Istio. Bei der Entwicklung des Envoy Proxy hat man sich stark auf die Themen Performance und Security fokussiert. Auch der Anschluss an das Tracing-System Zipkin ist ebenfalls im Paket enthalten. Nach eigenen Angaben von Lyft können Sie damit mehr als 10.000 virtuelle Maschinen mit mehr als 100 Microservices ohne großen Aufwand betreiben. Die Kunst des Zusammenschlusses wird nun sein, die einzelnen Projekte zu einem Guß zu vereinen und dabei doppelte Funktionalitäten zu eliminieren, was aktuell stattfindet.

Istio, das mit der Laufzeitplattform von Kubernetes gestartet ist, kann mittlerweile auch auf Nomad und Consul betrieben werden. Weitere Plattformen wie Cloud Foundry und Apache Mesos sind für die Zukunft geplant. Nach Aussagen auf der Homepage von Istio haben sich andere Mitbewerber (etwa Red Hat und Pivotal) dazu entschieden, deren existierende Service-Discovery-Mechanismen durch Istio zu ersetzen. Dadurch soll die Kompatibilität von Istio bezügliche Kubernetes, Cloud Foundry und OpenShift erreicht werden. Somit unterstützen weitere mächtige Player in diesem Marktsegment die Einsatzmöglichkeiten von Istio. Einziger “Pferdefuß” ist die Tatsache, dass nach eigenen Aussagen Istio noch keine Produktionsreife erreicht hat. Doch das sollte bei der Menge und Macht der beteiligten Firmen nur noch eine Frage der Zeit sein. Aktuell sind für folgende Kubernetes-Plattformen Installationsskripte und -anweisungen vorhanden:

  • Minikube (für lokale Tests)
  • Google Kubernetes Engine
  • IBM Cloud Kubernetes Service (IKS)
  • IBM Cloud Private
  • OpenShift Origin
  • AWS

Somit kann Istio auf den gängigsten Kubernetes-Cluster-Systemen entweder in der Cloud oder „on premise“ betrieben werden (sogar eigene Tests auf Minikube zusammen mit Istio sind ohne Probleme möglich).

Architektur von Istio

Istio unterteilt den Service Mesh logisch in zwei Ebenen: Data Plane und Control Plane. Die sogenannte Arbeitsebene (Data Plane) setzt sich aus den Envoy Proxys, welche als Sidecars neben dem Microservice deployt werden, zusammen. Jeglicher inbound- und outbound-Netzwerkverkehr mit dem Microservice werden durch das Sidecar geleitet. Die Kontrollebene (Control Plane) kümmert sich um die Verwaltung und Konfiguration der Proxys und ermöglicht somit eine zentrale Steuerung der Security und des Netzwerkverkehrs innerhalb des Service Mesh.

Die Architektur von Istio / Quelle: Istio

Envoy Proxy

Der Envoy Proxy, aus Performanzgründen in C++ entwickelt, wird als eigener (Docker) Container zusammen mit dem Container des Microservice gemeinsam in einen Kubernetes Pod deployt. Durch Veränderung der Einstellungen der IP-Tables kann sich das Sidecar unmerklich für den Microservice als “Man-in-the-Middle” in die Kommunikation einschalten. Mit diesem Modell können die Istio-Funktionalitäten auch noch nachträglich in vorhandene Microservice-Anwendungen integriert werden, ohne dafür die Microservices selbst zu verändern. Der Envoy steht in enger Kommunikation mit dem Mixer. Beide tauschen eine Menge an Telemetrieinformationen untereinander aus, welche dem Mixer erlauben, die gewünschten Policys zu ermitteln und diese an alle beteiligten Envoys weiterzuleiten. Darüber hinaus kümmert sich der Envoy noch um die Service Discovery, Load Balancing, Health Checks und Metrics. Zur Verbesserung der Resilienz werden Circuit-Breaker-Aufgaben von Envoy übernommen zusammen mit der Möglichkeit, per Fault Injection diese auch zu testen.

Mixer

Weiterführende Aufgaben des Mixer liegen darin, die Plattformunabhängigkeit von Istio herzustellen. Damit werden Eigenschaften und Eigenheiten der Laufzeitumgebungen von Envoy und den anderen Steuerungskomponenten von Istio fern gehalten. Die gesammelten Telemetriedaten werden an Monitoring-Systeme geschickt, um diese mit den notwendigen Informationen über das Verhalten des Service Mesh zu versorgen.

Istio Mixer / Quelle: Istio

Diese Infrastructure Backends beinhalten weiterführende Funktionalitäten, wie zum Beispiel Access Control, Quota Enforcement oder Billing. Ohne den Envoy Proxy und den Mixer wäre der Microservice-Entwickler gezwungen, diese Einbindung in seinem Code vorzunehmen. Auch diese Teile werden von Istio übernommen und halten somit den Service frei von Abhängigkeiten zu diesen Systemen. Damit wird die Arbeit der OPs-Kollegen erleichtert, da sie über zentrale Stellen auf diese Funktionalitäten einwirken können, ohne dies in jedem Microservice separat machen zu müssen.

Pilot

Das Service Discovery wird durch den Pilot übernommen, indem dieser die Envoy Proxys mit den notwendigen Informationen versorgt. Diese Informationen ermöglichen dem Envoy unter anderem die Resilienz-Patterns (etwa Timeout, Retry und Circuit Breaker) umzusetzen. Auch die Themen A/B-Deployment und Canary Releasing wird durch dieses Zusammenspiel ermöglicht. Jeder Envoy verwaltet Load-Balancer-Informationen, die er vom Pilot erhält, wodurch der Envoy die Last optimal im Service Mesh verteilt. Auch hier werden plattformspezifische Service-Discovery-Mechanismen abstrahiert und zugehörige Informationen in ein Istio-Format übertragen, welches den Envoys dann mitgeteilt werden kann. Dadurch ist es Istio möglich, auch beim Thema Traffic Management durch geeignete Adapter an jede Laufzeitumgebung angeschlossen werden und für die OPs-Kollegen steht ein einheitliches Admin-API zur Verfügung.

Der Istio Pilot / Quelle: Istio

Der Platform Adapter Layer übernimmt dabei die Kommunikation, zum Beispiel mit dem Kubernetes API, und holt sich Informationen über die Pod-Registrierung, um so über die vorhandenen Laufzeitinstanzen informiert zu sein. Das Abstract Model transformiert diese in das kanonische Modell von Istio und zusammen mit den Rules werden diese an die Envoys weitergeleitet.

Istio-Auth

Die dritte Komponente der Istio Control Plane ist für die Security zuständig. Istio bietet bereits Service-to-Service- und End-User-Authentifizierung auf TLS-Basis an. Admins können so erst einmal rudimentäre Policys aktivieren. Leider wird erst in kommenden Releases eine feinere Zugriffskontrolle zusammen mit Auditing zur Verfügung stehen. Vorübergehend müssen also die Services selbst die benötigten Zugriffsprüfungen und Audit-Ausgaben implementieren.

Traffic Management

Die Kernaufgaben von Istio besteht in intelligentem Management der Aufrufe zwischen den Services im Service Mesh. Dazu wird ganz bewusst der sog. traffic-flow von der Skalierung der Infrastruktur entkoppelt. Man gibt dabei nur an welches Aufrufverhalten man erreichen will, ohne angeben zu müssen, welcher Kubernetes Pod oder welche VM diese Aufrufe verarbeiten sollen. Die Ableitung des Aufrufverhaltens und damit die Zuordnung der Aufrufe zu den Laufzeit-Instanzen übernehmen Pilot und Envoy im intelligenten Zusammenspiel.

Traffic Management in Istio / Quelle: Istio

Das Beispiel in der Grafik zeigt, dass eine einfache Konfiguration in Istio es ermöglicht, 5% der Aufrufe auf eine neue Version von Service B (svcB’) umzuleiten (Canary Releasing). Man muss sich dabei nicht um das Routing auf die eigentlichen Pods mit Service B‘ kümmern, da die benötigte Anzahl der Canary-Instanzen von Service B‘ von Kubernetes selbst übernommen wird. Mit den gleichen einfachen Einstellungen ist es möglich, das Routing auf Basis von Request-Inhalten zu steuern. So kann zum Beispiel angegeben werden, dass Aufrufe von Android-Geräten auf Service B geleitet werden und nur Aufrufe von iPhone-Geräten an die neue Version von Service B (svcB’) geschickt werden.

Um diese Beispiele zu realisieren, wird eine RouteRule im yaml-Format erstellt. Für das Canary-Release-Beispiel lautet die entsprechende Istio-Regel:

# canary-release.yaml

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: canary-release
  namespace: default
spec:
  destination:
    name: svcB
  precedence: 1
  route:
  - labels:
      version: current_version
    weight: 95
  - labels:
      version: canary_version
    weight: 5

Istio-Regeln werden über den destination-Parameter einem Ziel-Service (in diesem Fall svcB) zugeordnet. Die Auswertungsreihenfolge der verschiedenen Regeln wird über Prioritäten (precedence) festgelegt. Anhand der dem Service zugeordneten version-Labels wird das Routing definiert. In diesem Fall werden 95% der Requests auf alle Instanzen des svcB mit dem version-Label current_version verteilt. Installieren lässt sich diese Regel über das Kommandozeilen-Tool istioctl:

istioctl create -f canary-release.yaml

Bis auf wenige Ausnahmen (z.B. Sidecar Injection in einem Service) kann im Kubernetes-Umfeld auch das Kommandozeilen-Tool kubectl gleichwertig verwendet werden. Allerdings wird über istioctl noch eine erweiterte Schema-Validierung durchgeführt. Sobald die Regel angelegt wurde, übernimmt Pilot die Aufgabe, die neuen Routing-Informationen an alle Envoy Proxys zu verteilen und aktiviert so das neue Verhalten.

Ohne ein Werkzeug wie Istio bekommt man einen Service Mesh wohl kaum in den Griff. Die Stärken einer transparenten Sidecar-Infrastruktur liegen auf der Hand: Die Entwicklung von Anwendungen wird von wiederkehrenden Aufgaben befreit und kann sich auf das Wesentliche – die Business-Logik – konzentrieren. Istio bietet so über Pilot, Mixer und den Envoy Proxy die notwendigen Funktionen für Betrieb und Überwachung eines Service Meshs für die Anwendung transparent an. Auch die Migration von bestehenden Anwendungen lässt sich recht einfach verwirklichen. Alle Features stehen unabhängig von Programmiersprache und Laufzeitumgebung zur Verfügung. Für OPs-Kollegen steht wiederum ein mächtiges Tool zur Verfügung, das es ermöglicht, Anwendungen genau zu überwachen und gezielt über das Regelwerk mit dem Service Mesh zu interagieren. Durch die Beteiligung mächtiger Community-Mitglieder wie Google und IBM lässt Istio großes Potential und einen schnellen Fortschritt in Richtung Produktionsreife erwarten. Im Kern setzt Istio bereits auf produktionsreife Projekte und die Integration bestehender Tools. Auch die kommende Unterstützung für unterschiedliche, auch nicht Kubernetes-basierte Plattformen, ist ein großer Vorteil und ermöglicht Unabhängigkeit bei der Wahl einer Zielplattform.

Ausblick

Der zweite Teil dieser Serie beschäftigt sich mit den verschiedenen zur Verfügung stehenden Tools wie Prometheus (Monitoring) oder Zipkin (Tracing) und erläutert anhand von Beispielen in Kubernetes unterschiedliche Features. So werden Fault Injection, Request Mirroring, Zugriff auf externe Services oder auch die Einsatzmöglichkeiten von Circuit Breaker genauer betrachtet und deren mögliche Einsatzszenarien beschrieben.

Geschrieben von
Michael Hofmann
Michael Hofmann
Michael Hofmann ist freiberuflich als Berater, Coach, Referent und Autor tätig. Seine langjährigen Projekterfahrungen in den Bereichen Softwarearchitektur, Java Enterprise und DevOps hat er im deutschen und internationalen Umfeld gesammelt. Mail: info@hofmann-itconsulting.de
Markus Lackner
Markus Lackner
Markus Lackner ist Softwareentwickler beim österreichischen Bankenrechenzentrum ARZ. Seit mehr als 18 Jahren arbeitet er in verschiedenen Projekten an Design, Architektur und Entwicklung komplexer Java Enterprise Applikationen. Momentane Schwerpunkte liegen auf Microservice Architekturen, docker, kubernetes und Aufbau von CI/CD Umgebungen. Mail: markus.lackner@tetraeder.at
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu: