Compute ist nicht die Plattform
Warum moderne Anwendungen heute aus zwei Plattformen bestehen.
Es gibt einen bemerkenswerten Nebeneffekt technologischer Abstraktion. Je erfolgreicher sie wird, desto schwieriger fällt es uns, ihre eigentlichen Grenzen überhaupt noch wahrzunehmen. Kubernetes ist dafür vermutlich eines der besten Beispiele. Kaum eine Technologie hat die Art und Weise, wie wir Anwendungen entwickeln und betreiben, nachhaltiger verändert. Compute-Ressourcen werden abstrahiert, Workloads deklarativ beschrieben und Container unabhängig von einzelnen Hosts geplant. Aus Sicht eines Entwicklers erscheint die zugrunde liegende Infrastruktur beinahe grenzenlos. Ein Deployment wird erstellt, der Scheduler übernimmt den Rest und wenige Augenblicke später verarbeitet eine Anwendung bereits produktiven Traffic. Vielleicht liegt genau darin jedoch eine interessante Beobachtung. Je erfolgreicher Kubernetes darin geworden ist, Compute von der darunterliegenden Infrastruktur zu abstrahieren, desto häufiger entsteht der Eindruck, Kubernetes sei inzwischen die Plattform. Tatsächlich beginnt die eigentliche Plattform jedoch deutlich früher.
Betrachten wir noch einmal den Weg eines Requests. Nicht den Teil, den Kubernetes verarbeitet. Sondern den Teil davor.
Browser
│
▼
DNS
│
▼
Internet
│
▼
Routing
│
▼
Anycast
│
▼
Edge
│
▼
Kubernetes
│
▼
Anwendung
Interessanterweise besitzt Kubernetes auf den ersten sieben Stationen dieses Diagramms keinerlei Einfluss. Es entscheidet weder darüber, welchen Netzwerkpfad ein Request durch das Internet nimmt, noch darüber, an welchem Point of Presence eine Verbindung terminiert wird. Es kennt keine BGP-Routen, keine Peering-Beziehungen, keine TLS-Handshakes und auch keine Web Application Firewall. Selbst die Frage, ob eine TCP-Verbindung überhaupt bis zum Ingress Controller gelangen darf, wurde längst beantwortet, bevor der erste Pod von ihrer Existenz erfährt. Vielleicht wird genau an dieser Stelle sichtbar, dass wir zwei völlig unterschiedliche Klassen infrastruktureller Probleme miteinander vermischen.
Compute beantwortet Fragen über Anwendungen. Edge beantwortet Fragen über Verbindungen. Diese beiden Aussagen klingen zunächst beinahe selbstverständlich. Ihre Konsequenzen reichen jedoch erstaunlich weit. Ein Kubernetes-Cluster interessiert sich dafür,
- welcher Pod eine Anfrage verarbeitet,
- welche Ressourcen einem Container zur Verfügung stehen,
- welche Version einer Anwendung aktuell produktiv ist,
- wie Deployments ausgerollt werden,
- oder welche Services innerhalb eines Clusters miteinander kommunizieren.
All diese Entscheidungen setzen jedoch voraus, dass eine Verbindung den Cluster überhaupt erreicht. Die Edge beantwortet dagegen eine vollkommen andere Klasse von Fragestellungen.
- Welcher Netzwerkpfad führt überhaupt zu dieser Plattform?
- An welchem Standort wird die Verbindung angenommen?
- Ist das Zielsystem aktuell erreichbar?
- Soll die TLS-Verbindung hier terminiert werden?
- Ist der Request legitim?
- Handelt es sich um einen Benutzer oder um automatisierten Traffic?
- Soll diese Verbindung überhaupt bis zur Compute-Plattform gelangen?
Es handelt sich nicht um dieselben Probleme. Und genau deshalb sollten sie auch nicht von derselben Plattform gelöst werden.
Historisch betrachtet war diese Trennung kaum notwendig. Ein Webserver beantwortete HTTP-Anfragen. Die Anwendung lief auf demselben System. Der Reverse Proxy terminierte TLS. Vielleicht existierte noch eine Firewall. Mehr Infrastruktur war häufig nicht erforderlich. Ein einzelner Server konnte nahezu sämtliche Verantwortlichkeiten gleichzeitig übernehmen. Heute wäre derselbe Server mit Aufgaben konfrontiert, die sich gegenseitig widersprechen. Er müsste gleichzeitig globale Routingentscheidungen treffen, DDoS-Angriffe erkennen, Zertifikate verwalten, TLS terminieren, Layer-4- und Layer-7-Loadbalancing durchführen, Kubernetes-Services erreichen und anschließend auch noch die eigentliche Anwendung ausführen. Nicht weil eine dieser Aufgaben besonders schwierig wäre. Sondern weil jede einzelne von ihnen auf vollkommen unterschiedlichen Informationen basiert.
Vielleicht wird dieser Unterschied deutlicher, wenn wir nicht über Produkte sprechen, sondern über Verantwortlichkeiten.
| Edge | Compute |
|---|---|
| Verbindungen annehmen | Anwendungen ausführen |
| Routing | Scheduling |
| TLS | Container |
| DDoS-Mitigation | Deployments |
| Layer-4-Loadbalancing | Services |
| Layer-7-Routing | Business Logic |
| WAF | Datenhaltung |
| Traffic Engineering | Autoscaling |
Bemerkenswert ist dabei weniger die Aufteilung selbst. Bemerkenswert ist, dass sich beide Seiten nahezu vollständig unabhängig voneinander weiterentwickeln können. Eine neue Kubernetes-Version verändert keine BGP-Routen. Ein neues Peering verändert keine Deployment-Pipeline. Eine Änderung an der Web Application Firewall beeinflusst keine StatefulSets. Und ein neues Storage-System besitzt keinerlei Auswirkungen auf die Art und Weise, wie ein Request überhaupt bis zum Cluster gelangt. Genau darin liegt der eigentliche Wert klar definierter Verantwortlichkeiten. Sie reduzieren nicht die Anzahl der Komponenten. Sie reduzieren die Anzahl ihrer gegenseitigen Abhängigkeiten.
Diese Trennung besitzt jedoch noch einen weiteren Vorteil, der häufig erst im operativen Betrieb sichtbar wird.
Betrachten wir zwei vollkommen unterschiedliche Fehlerszenarien.
Im ersten Fall verliert ein Point of Presence sämtliche Upstream-Verbindungen.
Im zweiten Fall schlägt ein Kubernetes-Deployment fehl und alle Pods einer Anwendung wechseln in den Status CrashLoopBackOff.
Aus Sicht eines Benutzers führen beide Ereignisse zunächst zum selben Ergebnis.
Die Anwendung ist nicht erreichbar.
Architektonisch unterscheiden sich beide Situationen jedoch grundlegend.
Szenario A
Internet
│
▼
PoP nicht erreichbar
→ Routingproblem
Szenario B
Internet
│
▼
Edge funktioniert
│
▼
Kubernetes
│
▼
Pods fehlerhaft
→ Computeproblem
Die Ursache liegt in unterschiedlichen Plattformen. Sie wird von unterschiedlichen Teams analysiert. Sie erfordert unterschiedliche Werkzeuge. Und sie wird auf vollkommen unterschiedlichen Ebenen gelöst. Gerade deshalb erscheint es wenig sinnvoll, beide Verantwortlichkeiten künstlich in einer einzigen Plattform zusammenzuführen.
Vielleicht erklärt genau das auch, weshalb moderne Plattformen zunehmend aus mehreren Plattformen bestehen. Compute ist eine Plattform. Storage ist eine Plattform. Observability ist eine Plattform. Und Edge ist es ebenfalls. Nicht weil jede dieser Ebenen zwangsläufig von unterschiedlichen Produkten umgesetzt werden müsste. Sondern weil jede Ebene über ihren eigenen Informationsraum verfügt. Routing benötigt Routinginformationen. Scheduling benötigt Clusterzustände. Storage benötigt Konsistenzmodelle. Observability benötigt Telemetriedaten. Keine dieser Plattformen kann die Aufgaben einer anderen sinnvoll übernehmen, ohne dabei Wissen vorauszusetzen, das sie eigentlich gar nicht besitzen sollte.
Vielleicht besteht genau darin eines der größten Missverständnisse moderner Cloud-Architekturen. Wir sprechen häufig darüber, Anwendungen auf Kubernetes zu betreiben. Tatsächlich betreiben wir sie jedoch auf einer Infrastruktur, deren erster Berührungspunkt mit dem Benutzer weit vor Kubernetes liegt. Der Cluster beginnt erst dort, wo die eigentliche Ausführung einer Anwendung startet. Die Plattform beginnt bereits dort, wo das Internet entscheidet, welchen Weg ein einzelner Request überhaupt nehmen wird. Genau deshalb endet moderne Infrastruktur nicht am Loadbalancer. Und sie beginnt auch nicht im Kubernetes-Cluster. Sie beginnt an der Grenze zwischen dem öffentlichen Internet und der ersten Entscheidung darüber, ob eine Verbindung überhaupt Teil unserer Plattform werden darf.