Dieser Blog ist der erste in einer Blog-Reihe, die verschiedene Aspekte dessen behandelt, was für den Aufbau und Betrieb unseres SaaS- Dienstes erforderlich war:
Wie wir in unserem früheren Blog beschrieben haben, entwickeln unsere Kunden komplexe und vielfältige Geschäftslösungen – etwa intelligente Fertigung, Videoforensik für die öffentliche Sicherheit, algorithmischen Handel, 5G-Telekommunikationsnetze – und daher müssen wir für diese Anwendungen und ihre Endbenutzer eine stets verfügbare, vernetzte und zuverlässige Erfahrung bereitstellen.
Da diese Anwendungen in mehreren Clustern bei verschiedenen Cloud-Anbietern oder an den Randstandorten der Kunden ausgeführt werden könnten, musste unser Plattformteam eine verteilte Steuerungsebene und einen PaaS-Dienst erstellen, um mehrere Kubernetes-Cluster mit mehreren Mandanten bereitzustellen, zu sichern und zu betreiben. Diese verteilte Steuerebene hat viele Betriebs-, Skalierungs- und Leistungsvorteile gebracht, die wir in unserer Präsentation ( Videolink ) behandeln werden – z. B. wie man Tausende von Edge-K8s-Clustern mit GitOps verwaltet – und in den kommenden Wochen auch in einem separaten Blog-Beitrag.
Wir haben uns für Kubernetes (K8s) als Kern unserer Plattform zur Verwaltung verteilter Anwendungen entschieden, da es einen umfangreichen Funktionsumfang bietet, ohne zu normativ zu sein. Dies gibt uns die Flexibilität, bei Dingen Innovationen einzuführen, die unserer Ansicht nach für unsere Kunden wichtig sind. Wir haben dies als Grundlage für den Aufbau unseres Dienstes verwendet und mit der wachsenden Popularität von K8s ist es auch einfacher, Entwickler und Betreiber zu finden, die damit vertraut sind.
Allerdings ist die Bereitstellung und Verwaltung einer großen Anzahl produktionsreifer Kubernetes-Cluster in einer Hybridumgebung (mehrere Clouds, Netzwerk-POPs und Edge-Standorte) nicht sehr einfach, da es keine sofort einsatzbereiten Lösungen für Kubernetes gibt, die Folgendes können:
Nach mehreren Proof-of-Concept mit mehreren Cloud-Anbietern und Open-Source-Plattformen wie GKE, AKS, EKS und RKE sowie OpenShift und Cloud Foundry stellten wir fest, dass keiner von ihnen alle fünf oben genannten Anforderungen erfüllen konnte. Aus diesem Grund haben wir uns entschieden, unsere eigene PaaS zu entwickeln – angefangen mit „Standard“-Kubernetes und mehreren Ergänzungen – für Identität, Netzwerke, Sicherheit, Mandantenfähigkeit, Protokollierung, Metriken usw. Obwohl wir Kubernetes zur Erfüllung unserer internen Anforderungen verwenden, mussten wir einige schwierige Entscheidungen treffen, z. B. diese Kubernetes-Cluster nicht direkt unseren internen Benutzern und/oder Kunden zur Verfügung zu stellen, damit diese ihre Workloads ausführen können (mehr dazu später, da Multi-Tenancy ein wichtiges Ziel für uns war).
Zusätzlich zu den zahlreichen neuen Funktionen, die wir hinzufügen mussten, bestand auch die Notwendigkeit, unsere Workloads/Dienste parallel zu den Workloads der Kunden an vielen Standorten am Edge, in unserem Netzwerk und in öffentlichen/privaten Clouds auszuführen. Dies bedeutete, dass wir zusätzliche Funktionen zum Verwalten mehrerer Cluster in mehreren Umgebungen entwickeln mussten … alle verbunden über unser globales Netzwerk und unsere verteilten Anwendungs-Gateways, um Zero-Trust-Konnektivität und Konnektivität auf Anwendungsebene zwischen diesen Clustern bereitzustellen.
Das Erstellen und Betreiben von Anwendungen, die in einem einzelnen Kubernetes-Cluster ausgeführt werden, ist keine triviale Aufgabe, selbst wenn ein vom Cloud-Anbieter verwalteter Cluster verwendet wird. Aus diesem Grund minimieren DevOps- und SRE-Teams häufig ihren Aufwand und müssen sich nicht mit der Komplexität vieler Cluster befassen. Es kommt häufig vor, dass Teams einen großen Kubernetes-Cluster erstellen und alle Arten von Ressourcen im selben Cluster platzieren. Dies erscheint zwar großartig, da dadurch die Abläufe vereinfacht und der Cluster mit maximaler Rechenleistung und zu maximalen Kosten betrieben werden kann, es ist jedoch aus mehreren Gründen nicht die beste Idee. Erstens unterscheiden sich die Anforderungen an Produktions-Workloads stark von denen für Entwicklungstests und Staging. Instabile Entwicklungs-Workloads können möglicherweise Probleme für stabilere Produktions-Workloads verursachen.
Neben den Anforderungen unterschiedlicher Workloads sind die Sicherheits- und Isolationsbeschränkungen von K8 ein weiterer Grund für die Verwendung mehrerer Cluster. Ein typischer Ansatz zur Lösung der Sicherheits- und Ressourcenisolierungsprobleme von K8 besteht darin, mithilfe eines Multi-Tenant-Modells unabhängige Cluster für jeden Mandanten zu erstellen. Während dies in der Cloud möglicherweise möglich ist, ist es am Rand nicht möglich, mehrere Cluster auszuführen. Edge-Sites unterliegen Einschränkungen bei Rechen- und Speicherressourcen sowie einer eingeschränkten Netzwerkbandbreite, um Protokolle und Messdaten für jeden zusätzlichen Cluster an die zentrale Cloud zu senden.
Um das Problem mehrerer Kubernetes-Cluster zu lösen, haben wir Rancher für die zentrale Verwaltung unserer Kubernetes-Cluster (als wir begannen, gab es Anthos und Azure Arc noch nicht) und KubeFed evaluiert. Die beiden damals verfügbaren Ansätze waren (und sind auch heute noch die gleichen):
Nach der kürzlichen Ankündigung von GCP Anthos und Azure Arc haben wir unsere ursprüngliche Entscheidung zum Aufbau einer verteilten Steuerungsebene überdacht und sind zu dem Schluss gekommen, dass selbst diese beiden neuen Angebote zwei kritische Probleme mit verteilten Clustern nicht hätten lösen können. Diese beiden Schlüsselfunktionen benötigten wir für unsere Plattform:
Zur Lösung dieser beiden Probleme mussten wir eine neue Technik entwickeln – eine verteilte Steuerungsebene –, um den Betriebsaufwand „mehrerer“ Cluster zu verringern und ein Äquivalent „mehrerer Cluster“ für Multi-Tenancy in Umgebungen mit eingeschränkten Ressourcen bereitzustellen.
Unser Plattformteam hat beschlossen, eine verteilte Steuerungsebene für Kubernetes zu erstellen, die Kubernetes-APIs für die Verwendung durch unser Team bereitstellt. Diese APIs stammen jedoch aus „virtuellen“ Clustern, die nur in unserer Steuerungsebene vorhanden sind – einem virtuellen K8s (vK8s)-API-Server für einen virtuellen K8s-Cluster (siehe Abbildung 1 ). Diese Steuerebene ordnet die Absicht des Benutzers mehreren physischen Kubernetes-Clustern zu, die an unserem Edge, unseren Netzwerk-POPs und an öffentlichen Cloud-Standorten ausgeführt werden. Auf diese physischen Cluster kann nur über unsere verteilte Steuerungsebene zugegriffen werden, nicht jedoch über einzelne Mieter/Benutzer.
Diese Steuerebene stellt jedem Mieter einen oder mehrere „virtuelle“ Anwendungscluster zur Verfügung, in denen er seine Anwendung(en) bereitstellen kann. Je nach Konfiguration repliziert und verwaltet die Steuerebene diese über mehrere physische Kubernetes-Cluster hinweg. Zusätzlich zu den Konfigurations- und Bereitstellungsvorgängen werden diesem „virtuellen“ Cluster auch Überwachungsvorgänge unterzogen, ohne dass Tools zum Sammeln und Analysieren von Daten aus mehreren physischen Clustern entwickelt werden müssen.
Nehmen wir als Beispiel eine UI-Anwendung namens „productpage“, die der Benutzer verteilt an drei Standorten ausführen möchte – pa2-par, ny8-nyc und ams9-ams mit jeweils zwei Replikaten. Wenn der Benutzer ein vK8s-Objekt erstellt und es an einen virtuellen Cluster anfügt, wird sofort ein vK8s-API-Server bereitgestellt, der mit Standard-Kubectl verwendet werden kann.
Als nächsten Schritt lädt der Benutzer die Kubeconfig für diesen virtuellen Cluster herunter und erstellt ein Standard-YAML, um eine K8s-Bereitstellung für die Produktseite zu beschreiben.
Nach der Erstellung der Bereitstellungsspezifikation kann der Benutzer mit der Erstellung einer Bereitstellung auf diesem virtuellen Cluster fortfahren:
Wenn der Benutzer jetzt seine Bereitstellung überprüft, sieht er, dass 6 Replikate gestartet wurden, davon 2 an jedem Standort (pa2-par, ny8-nyc und ams9-ams).
Die folgende Ausgabe zeigt 2 Pods, die an jedem Standort ausgeführt werden und einem bestimmten physischen Knoten zugeordnet sind
Dieses einfache Beispiel zeigt, wie einfach es ist, innerhalb von Minuten eine Multi-Cluster-Replikation beliebiger Apps zu erreichen, ohne dass ein Installations- und Verwaltungsaufwand erforderlich ist. Neben der Abbildung der Absicht ermöglicht die verteilte Steuerungsebene auch die Beobachtung des virtuellen Clusters und nicht nur auf der Basis einzelner Cluster.
Wie Sie in Abbildung 2 sehen können, läuft unsere zentralisierte Verwaltungsebene über zwei öffentliche Cloud-Anbieter (jeweils eine Region) – einen in AWS und einen in Azure (aus Redundanzgründen). Diese Verwaltungsebene ermöglicht unserem SRE, Mandanten mit harter Multi-Tenancy zu erstellen – beispielsweise kann ein Entwicklungsteam, das an unserem VoltMesh-Dienst arbeitet, ein Mandant sein, und ein Kundenlösungsteam, das an Kunden-POCs arbeitet, kann ein eigener Mandant mit einem eigenen Benutzersatz sein.
Jeder dieser Mandanten kann mehrere Namespaces erstellen und einer Gruppe von Benutzern die Zusammenarbeit an diesen Namespaces zuweisen. Diese Namespaces sind keine Kubernetes-Namespaces – sie stellen eine Isolationsgrenze in unserer Plattform mit RBAC-Regeln und IAM-Richtlinien für Benutzer dar.
Wenn ein Benutzer innerhalb eines Namespace einen Anwendungscluster erstellen möchte, erstellt er ein vK8s-Objekt und das wiederum erstellt einen vK8s-API-Server in unserer Verwaltungsebene. Mit diesem vK8s-Objekt kann der Benutzer Bereitstellungen, Stateful Sets, PVCs usw. erstellen und die Steuerebene stellt sicher, dass diese Vorgänge auf einem oder mehreren physischen Clustern erfolgen, basierend auf Sites, die mit dem vK8s-Objekt verknüpft sind.
Da jeder Mieter und Benutzer standardmäßige K8s-Operationen ohne jegliche Änderungen verwendet, ist das System mit einer Reihe von Tools kompatibel, die bei Betreibern beliebt sind – z. B. Spinnaker, Helm, Jenkins usw.
Der große Vorteil einer verteilten Steuerungsebene besteht darin, dass sie den Betriebsaufwand für unsere SRE- und DevOps-Teams gelöst hat. Sie können jetzt Vorgänge (Konfiguration, Bereitstellung, Überwachung, Richtlinien usw.) über einen virtuellen Cluster ausführen und die Steuerebene ordnet diese automatisch mehreren physischen Clustern zu. Neben der betrieblichen Vereinfachung für mehrere Cluster hat die Steuerebene auch das Sicherheits- und Isolationsproblem für Multi-Tenancy gelöst.
Diese verteilte Steuerungsebene hat auch die Produktivität der Entwickler verbessert, die unserer Plattform neue Funktionen hinzufügen möchten – sie müssen nicht jedes Mal eine neue Automatisierung erstellen, wenn sie neue Funktionen hinzufügen, die sich auf die Konfiguration oder den Betrieb über mehrere Cluster hinweg auswirken. Sie verwenden das absichtsbasierte Konfigurationsmodell und die Steuerebene weiß, was zu tun ist. Darüber hinaus können sie weiterhin mit diesem verteilten und mehrfachen Clusterobjekt – virtuellen Kubernetes – interagieren, indem sie kubectl verwenden und nicht noch eine weitere CLI.
Nachdem wir dies nun über ein Jahr lang in unseren Entwicklungs-, Test-, Staging- und Produktionsumgebungen ausgeführt haben, wurde uns klar, dass diese global verteilte Steuerungsebene (die in unseren Netzwerk-POPs ausgeführt wird) auch erhebliche Vorteile hinsichtlich Skalierung, Leistung und Zuverlässigkeit bietet – etwas, das wir uns in der Anfangszeit nicht wirklich vorstellen konnten. Wir werden dieses Ergebnis in unserer kommenden KubeCon-Präsentation und in den kommenden Wochen in einem separaten Blogbeitrag behandeln.
In dieser Blogserie werden verschiedene Aspekte dessen behandelt, was für den Aufbau und Betrieb unseres weltweit verteilten SaaS-Dienstes mit vielen Anwendungsclustern in der öffentlichen Cloud, unseren privaten Netzwerk-PoPs und Edge-Sites erforderlich war. Als nächstes kommt Global Service Mesh für verteilte Apps …