BLOG

Tausende Edge-Kubernetes-Cluster mit GitOps verwalten

F5 Miniaturansicht
F5
Veröffentlicht am 18. Dezember 2019

Bei Volterra besteht die Aufgabe des SRE-Teams darin, eine globale SaaS-basierte Edge-Plattform zu betreiben. Wir müssen verschiedene Herausforderungen bei der Verwaltung einer großen Anzahl von Anwendungsclustern in verschiedenen Zuständen (z. B. online, offline, Admin-Down usw.) lösen und tun dies, indem wir das Kubernetes-Ökosystem und die Tools mit einem deklarativen Pull-basierten Modell unter Verwendung von GitOps nutzen.

In diesem Blog beschreiben wir:

Verwendung von GitOps zur effektiven Verwaltung und Überwachung einer großen Flotte von Infrastrukturen (physische oder Cloud-Hosts) und K8s-Clustern

  1. Die Werkzeuge, die wir zur Lösung von CI/CD-Problemen entwickelt haben
  2. Objektorchestrierung und Konfigurationsmanagement
  3. Beobachtbarkeit über die gesamte Flotte von Infra- und K8s-Clustern

Wir werden tiefer in die im großen Maßstab (3.000 Edge-Sites) gewonnenen Erkenntnisse eintauchen, was auch in meinem jüngsten Vortrag bei Cloud Native Rejekts in San Diego behandelt wurde.

TL;DR (Zusammenfassung)

  1. Wir konnten keine einfache und sofort einsatzbereite Lösung finden, mit der Tausende (und möglicherweise Millionen) von Anwendungs- und Infrastrukturclustern in der öffentlichen Cloud, vor Ort oder an nomadischen Standorten bereitgestellt und betrieben werden konnten.
     
  2. Diese Lösung musste das Lebenszyklusmanagement für Hosts (physisch oder Cloud), die Kubernetes-Steuerebene, Anwendungsworkloads und die laufende Konfiguration verschiedener Dienste bereitstellen. Darüber hinaus musste die Lösung unsere SRE-Designanforderungen erfüllen – deklarative Definition, unveränderlicher Lebenszyklus, Gitops und kein direkter Zugriff auf Cluster.
     
  3. Nach der Evaluierung verschiedener Open-Source-Projekte – z. B. Kubespray+Ansible (für die Kubernetes-Bereitstellung) oder Helm/Spinnaker (für die Workload-Verwaltung) – kamen wir zu dem Schluss, dass keine dieser Lösungen unsere oben genannten Anforderungen erfüllen konnte, ohne an jedem Edge-Standort eine erhebliche Software-Aufblähung hinzuzufügen. Aus diesem Grund entschieden wir uns, unseren eigenen Golang-basierten Software-Daemon zu entwickeln, der das Lebenszyklusmanagement des Hosts (physisch oder Cloud), der Kubernetes-Steuerebene und der Anwendungs-Workloads durchführt.
     
  4. Als wir das System auf 3.000 Cluster und mehr (innerhalb eines einzelnen Mandanten) skalierten, brachen alle unsere Annahmen hinsichtlich unserer öffentlichen Cloud-Anbieter, der Skalierbarkeit unserer Software-Daemons, der Betriebstools und der Observability-Infrastruktur systematisch zusammen. Um diese Herausforderungen zu meistern, war jeweils eine Neustrukturierung einiger unserer Softwarekomponenten erforderlich.

Definition der Kante

  • Customer Edge (CE) – Dies sind Kundenstandorte in der Cloud (wie AWS, Azure, GCP oder private Cloud), Standorte vor Ort (wie Fabrikhallen, Öl-/Gasanlagen usw.) oder nomadische Standorte (wie Automobil, Robotik usw.). CE wird vom Volterra SRE-Team verwaltet, kann aber auch von Kunden bei Bedarf an Standorten ihrer Wahl eingesetzt werden.
  • Regional Edges (RE) – Dies sind Volterra-Präsenzpunkte (PoP) in Colocation-Einrichtungen in großen Metropolmärkten, die mit unserem eigenen, stark vermaschten privaten Backbone verbunden sind. Diese regionalen Edge-Sites werden auch verwendet, um Customer-Edge-Standorte (CE) sicher miteinander zu verbinden und/oder Anwendungsdienste dem öffentlichen Internet zugänglich zu machen. RE-Standorte werden vollständig vom Volterra Infrastructure Operations-Team (Infra SRE) verwaltet und sind Eigentum dieses Teams.
verwalten01
Abbildung 1: Systemübersicht

Das Architekturdiagramm (Abbildung 1) oben zeigt die logische Konnektivität zwischen unseren REs und CEs, wobei jeder CE redundante (IPSec- oder SSL-VPN-)Verbindungen zum nächstgelegenen RE herstellt.

Anforderungen für das Edge-Management

Als wir vor etwa zwei Jahren mit der Entwicklung unserer Plattform begannen, bat uns unser Produktteam, die folgenden Herausforderungen zu lösen:

  1. Skalierbarkeit des Systems – unsere Kunden benötigten von uns die Unterstützung Tausender (letztlich Millionen) von Edge-Sites, und das ist etwas ganz anderes, als eine Handvoll Kubernetes-Cluster in Cloud-Regionen zu betreiben. Einer unserer Kunden verfügt beispielsweise über ca. 17.000 Convenience Stores und ein anderer betreibt >20.000 Ladestationen. Dieser Maßstab bedeutete, dass wir unsere Werkzeuge ganz anders bauen mussten, als wenn wir nur ein paar Cluster handhaben wollten.
  2. Zero-Touch-Bereitstellung – da jeder in der Lage sein sollte, eine neue Site bereitzustellen, ohne viel über die Hardware, Software oder Kubernetes wissen zu müssen. Die Edge-Site musste sich wie eine Blackbox verhalten, die sich einschaltet, zu Hause anruft und online geht.
  3. Flottenmanagement – vereinfachte Verwaltung von Tausenden von Standorten und Arbeitslasten, ohne dass diese einzeln behandelt werden müssen. Zum Zeitpunkt einer angeforderten Änderung oder Aktualisierung kann es vorkommen, dass eine Site offline geht oder nicht mehr verfügbar ist. Daher müssen Websites Updates abrufen, wenn sie online gehen.
  4. Fehlertoleranz – Edge-Sites müssen auch nach dem Ausfall einer Komponente betriebsbereit sein. Alles muss ferngesteuert verwaltet werden können und im Fehlerfall Funktionen wie Zurücksetzen auf Werkseinstellungen oder Site-Neuaufbau bieten. Wir mussten davon ausgehen, dass es am Standort keinen physischen Zugang gibt.

Designprinzipien (Kein Kubectl! Kein Ansible! Keine Pakete!)

Angesichts unserer Anforderungen und Herausforderungen beim Betrieb eines stark verteilten Systems haben wir beschlossen, mehrere Grundsätze festzulegen, an die sich unser SRE-Team halten muss, um nachgelagerte Probleme zu reduzieren:

  1. Deklarative Definition – das gesamte System muss deklarativ beschrieben werden, da wir so ein einfaches Abstraktionsmodell erstellen und eine Validierung anhand des Modells durchführen können.
     
  2. Unveränderliches Lebenszyklusmanagement – in der Vergangenheit haben wir an großen privaten Cloud-Installationen mit veränderbaren LCM-Tools wie Ansible, Salt oder Puppet gearbeitet. Dieses Mal wollten wir das Basisbetriebssystem sehr einfach halten und versuchen, alles als Container ohne Paketverwaltung oder die Notwendigkeit von Konfigurationsverwaltungstools auszuliefern.
     
  3. GitOps – bietet ein standardmäßiges Betriebsmodell für die Verwaltung von Kubernetes-Clustern. Darüber hinaus können wir damit Genehmigungen, Audits und Änderungs-Workflows sofort umsetzen, ohne ein zusätzliches Workflow-Management-System aufbauen zu müssen. Daher haben wir entschieden, dass alles über Git laufen muss.
     
  4. Kein Kubectl – Dies war eines der wichtigsten Prinzipien, da niemand direkt auf Anwendungscluster zugreifen darf. Aus diesem Grund haben wir die Möglichkeit entfernt, kubectl innerhalb einzelner Edge-Cluster auszuführen oder Skripte zu verwenden, die von zentralen Orten, einschließlich zentralisierten CD-Systemen, ausgeführt werden. Zentralisierte CD-Systeme mit Push-Methode eignen sich gut für Dutzende von Clustern, sind aber ohne Garantie einer 100-prozentigen Netzwerkverfügbarkeit sicherlich nicht für Tausende geeignet.
     
  5. Keine Hype-Technologie (oder -Tools) – unsere Erfahrungen aus der Vergangenheit haben gezeigt, dass viele der beliebten Open-Source-Tools ihrem Hype nicht gerecht werden. Während wir mehrere Community-Projekte zur Bereitstellung von Infrastruktur, K8s und Anwendungs-Workloads (wie Helm, Spinnaker und Terraform) evaluierten, verwendeten wir letztendlich nur Terraform für den Teil der virtuellen Infrastruktur und entwickelten benutzerdefinierten Code, den wir in den folgenden Teilen dieses Blogs beschreiben werden.

Site-Lebenszyklusverwaltung

Im Rahmen der Lebenszyklusverwaltung der Edge-Site mussten wir eine Lösung finden, wie das Host-Betriebssystem bereitgestellt, grundlegende Konfigurationen vorgenommen (z. B. Benutzerverwaltung, Zertifizierungsstelle, Hugepages usw.), K8s gestartet, Workloads verteilt und laufende Konfigurationsänderungen verwaltet werden.

Eine der Optionen, die wir in Betracht gezogen, aber letztendlich verworfen haben, war die Verwendung von KubeSpray+Ansible (zur Verwaltung des Betriebssystems und Bereitstellung von K8s) und Helm/Spinnaker (zur Bereitstellung von Workloads). Der Grund für unsere Ablehnung lag darin, dass wir dafür zwei bis drei Open-Source-Tools hätten verwalten und anschließend erhebliche Änderungen vornehmen müssen, um unsere Anforderungen zu erfüllen. Diese Anforderungen stiegen immer weiter, je mehr Funktionen wir hinzufügten, beispielsweise die automatische Skalierung von Edge-Clustern, die Unterstützung sicherer TPM-Module, differenzielle Upgrades usw.

Da unser Ziel darin bestand, es einfach zu halten und die Anzahl der direkt im Betriebssystem ausgeführten Komponenten (außerhalb von Kubernetes) zu minimieren, beschlossen wir, einen leichten Golang-Daemon namens Volterra Platform Manager (VPM) zu schreiben. Dies ist der einzige systemd-Docker-Container im Betriebssystem und er fungiert als Schweizer Taschenmesser, das viele Funktionen erfüllt:

Host-Lebenszyklus

VPM ist für die Verwaltung des Lebenszyklus des Hostbetriebssystems einschließlich Installation, Upgrades, Patches, Konfiguration usw. verantwortlich. Es gibt viele Aspekte, die konfiguriert werden müssen (z. B. Zuweisung großer Seiten, /etc/hosts usw.).

  1. Verwaltung von Betriebssystem-Upgrades – leider geht es bei Edge nicht nur um Kubernetes, sondern wir müssen auch die Versionen des Kernels und des Betriebssystems im Allgemeinen verwalten. Unser Edge basiert auf CoreOS (oder CentOS, je nach Kundenbedarf) mit einer aktiven und passiven Partition. Wenn ein Upgrade geplant ist, werden Updates immer auf die passive Partition heruntergeladen. Als letzter Schritt des Updates erfolgt ein Neustart, bei dem die aktiven und passiven Partitionen vertauscht werden. Der einzige heikle Teil ist die Neustartstrategie (für einen Cluster mit mehreren Knoten), da nicht alle Knoten gleichzeitig neu gestartet werden können. Wir haben unsere eigene etcd-Neustartsperre (in VPM) implementiert, bei der Knoten in einem Cluster einzeln neu gestartet werden.
  2. Benutzerzugriffsverwaltung für das Betriebssystem – wir müssen Benutzer und deren Zugriff auf SSH und die Konsole remote einschränken. VPM führt alle diese Vorgänge aus, beispielsweise SSH-CA-Rotationen.
  3. Da wir unseren eigenen L3-L7-Datenpfad entwickelt haben, müssen wir je nach Hardwaretyp (oder Cloud-VM) 2M- oder 1G-Hugepages im Host-Betriebssystem konfigurieren.

Kubernetes-Lebenszyklus

Management zur Bereitstellung eines Lebenszyklus für das Kubernetes-Manifest. Anstelle von Helm haben wir uns für die Verwendung der K8s-Client-Go-Bibliothek entschieden, die wir in VPM integriert haben, und mehrere Funktionen aus dieser Bibliothek verwendet:

  1. Optimistische vs. pessimistische Bereitstellung – mit dieser Funktion können wir Anwendungen kategorisieren, bei denen wir warten müssen, bis sie fehlerfrei sind. Es achtet lediglich auf die Annotation im K8-Manifest ves.io/deploy: optimistic .

    Optimistisch = Ressource erstellen und nicht auf Status warten. Es ist dem Kubernetes-Apply -Befehl sehr ähnlich, bei dem Sie nicht wissen, ob die eigentlichen Pods erfolgreich gestartet wurden.

    Pessimistisch = Warten auf den Status der Kubernetes-Ressource. Beispielsweise wartet die Bereitstellung, bis alle Pods bereit sind. Dies ähnelt dem neuen kubectl-Wait- Befehl.

  2. Aktionen vor dem Update, z. B. Pre-Pull – manchmal kann man sich nicht auf die fortlaufenden Updates von K8 verlassen, insbesondere wenn die Netzwerkdatenebene ausgeliefert wird. Der Grund hierfür ist, dass die alte Kapsel zerstört und anschließend die neue Kapsel gezogen wird. Im Fall der Datenebene verlieren Sie jedoch die Netzwerkkonnektivität. Daher kann das neue Container-Image nicht abgerufen werden und der Pod wird nie gestartet. Die Metadatenannotation ves.io/prepull mit einer Liste von Bildern löst eine Pull-Aktion aus, bevor das K8-Manifest angewendet wird.
  3. Wiederholungsversuche und Rollbacks im Falle angewandter Fehler. Dies ist eine sehr häufige Situation, wenn ein K8s-API-Server zeitweise ausfällt.

Laufende Konfiguration

Zusätzlich zu den Konfigurationen im Zusammenhang mit K8s-Manifesten müssen wir auch verschiedene Volterra-Dienste über ihre APIs konfigurieren. Ein Beispiel sind IPsec/SSL-VPN-Konfigurationen – VPM empfängt die Konfiguration von unserer globalen Steuerebene und programmiert sie in einzelnen Knoten.

Werksrücksetzung

Mithilfe dieser Funktion können wir eine Box aus der Ferne in den Originalzustand zurücksetzen und den gesamten Installations- und Registrierungsprozess erneut durchführen. Dies ist eine äußerst wichtige Funktion für die Wiederherstellung einer Site, für die ein Konsolen-/physischer Zugriff erforderlich ist.

Auch wenn das Lebenszyklusmanagement von K8 für viele Leute ein großes Diskussionsthema zu sein scheint, macht es für unser Team wahrscheinlich nur 40–50 % des gesamten Arbeitsvolumens aus.

Zero-Touch-Bereitstellung

Die Zero-Touch-Bereitstellung der Edge-Site an jedem Standort (Cloud, vor Ort oder Nomadic Edge) ist eine kritische Funktion, da wir weder Zugriff auf einzelne Sites erwarten können, noch so viele Kubernetes-Experten für die Installation und Verwaltung einzelner Sites einsetzen möchten. Es lässt sich einfach nicht auf Tausende skalieren.

Das folgende Diagramm (Abbildung 2) zeigt, wie VPM am Prozess der Registrierung einer neuen Site beteiligt ist:

verwalten02
Abbildung 2 – Zero-Touch-Bereitstellungsablauf
  1. Nach dem Einschalten überreicht das auf dem CE ausgeführte VPM (dargestellt durch das grüne Kästchen) unserer globalen Kontrollebene (GC) ein Registrierungstoken, um eine neue Registrierung zu erstellen. Das Registrierungstoken wird als Teil der Cloud-Init der Cloud-VM bereitgestellt und kann ein Schlüssel sein, der während des Startvorgangs von einem Menschen eingegeben oder im TPM für Edge-Hardware programmiert wird.
  2. GC empfängt die Anforderung mit Token, wodurch eine neue Registrierung unter einem Mandanten erstellt werden kann (im Token codiert). Der Kundenbetreiber kann den neuen Randstandort sofort auf der Karte sehen und genehmigen, wobei er den Namen und andere Konfigurationsparameter eingeben kann.
  3. Der VP-Controller innerhalb des GC generiert Konfigurationen (z. B. entscheidet, wer K8s-Master, Minion usw. ist) und Zertifikate für etcd, K8s und VPM.
  4. VPM beginnt mit dem Bootstrapping der Site, einschließlich dem Herunterladen von Docker-Images, der Konfiguration von Hugepages, der Installation des K8s-Clusters und dem Starten der Volterra-Steuerebenendienste.
  5. VPM konfiguriert redundante Tunnel (IPSec/SSL VPN) zu den beiden nächstgelegenen Regional Edge-Standorten, die für den Datenverkehr und die Interkonnektivität zwischen Standorten und dem öffentlichen Netzwerk verwendet werden.

Wie Sie sehen, ist der gesamte Prozess vollständig automatisiert und der Benutzer muss nichts über die detaillierte Konfiguration wissen oder manuelle Schritte ausführen. Es dauert etwa 5 Minuten, bis das gesamte Gerät online ist und bereit ist, Kunden-Apps und -Anfragen zu verarbeiten.

Upgrades der Infrastruktursoftware

Das Upgrade ist eines der kompliziertesten Dinge, die wir lösen mussten. Definieren wir, was in Edge-Sites aktualisiert wird: 

  • Betriebssystem-Upgrades – dies umfasst den Kernel und alle Systempakete. Jeder, der schon einmal mit einer Standarddistribution des Linux-Betriebssystems gearbeitet hat, weiß, wie mühsam ein Upgrade zwischen Nebenversionen (z. B. von Ubuntu 16.04.x auf 16.04.y) ist und wie viel mühsamer ein Upgrade zwischen Hauptversionen (z. B. von Ubuntu 16.04 auf 18.04) ist. Bei Tausenden von Sites müssen Upgrades deterministisch sein und dürfen sich nicht an verschiedenen Sites unterschiedlich verhalten. Daher haben wir uns für CoreOS und CentOS Atomic mit der Möglichkeit entschieden, A/B-Upgrades mit 2 Partitionen und schreibgeschütztem Dateisystem auf Pfaden durchzuführen. Dies gibt uns die Möglichkeit, durch Ändern der Startreihenfolgepartitionen sofort zurückzukehren und die Konsistenz des Betriebssystems aufrechtzuerhalten, ohne Betriebssystempakete pflegen zu müssen. Allerdings können wir einzelne Komponenten im System, beispielsweise den OpenSSH-Server, nicht mehr einfach durch die Installation eines neuen Pakets aktualisieren. Änderungen an einzelnen Komponenten müssen als neue unveränderliche Betriebssystemversion veröffentlicht werden.
     
  • Software-Upgrades – dies umfasst VPM-, etcd-, Kubernetes- und Volterra-Steuerungsdienste, die als K8s-Workloads ausgeführt werden. Wie ich bereits erwähnt habe, besteht unser Ziel darin, alles in K8s als systemd-Container auszuführen. Glücklicherweise konnten wir bis auf drei Dienste alles als K8s-Workloads konvertieren: VPM, etcd und Kubelet.

Es gibt zwei bekannte Methoden, mit denen Updates an Edge-Sites übermittelt werden können: 

  1. Push-basiert – eine Push-Methode wird normalerweise von einem zentralisierten CD-Tool (Continuous Delivery) wie Spinnaker, Jenkins oder Ansible-basiertem CM durchgeführt. In diesem Fall müsste ein zentrales Tool Zugriff auf die Zielsite oder den Zielcluster haben und für die Ausführung der Aktion verfügbar sein.
  2. Pull-basiert – eine Pull-basierte Methode ruft Upgrade-Informationen selbstständig ab, ohne einen zentralen Bereitstellungsmechanismus. Es ist besser skalierbar und macht es überflüssig, die Anmeldeinformationen aller Sites an einem einzigen Ort zu speichern.

Unser Ziel für das Upgrade bestand darin, Einfachheit und Zuverlässigkeit zu maximieren – ähnlich wie bei herkömmlichen Mobiltelefon-Upgrades. Darüber hinaus gibt es noch weitere Aspekte, die bei der Upgrade-Strategie berücksichtigt werden müssen. So besteht der Upgrade-Kontext möglicherweise nur beim Site-Betreiber, oder das Gerät ist möglicherweise aufgrund von Verbindungsproblemen usw. für einige Zeit offline oder nicht verfügbar. Diese Anforderungen konnten mit der Pull-Methode leichter erfüllt werden und daher haben wir uns entschieden, diese Methode unseren Bedürfnissen entsprechend zu übernehmen.

GitOps

Darüber hinaus haben wir uns für GitOps entschieden, da es damit einfacher war, unserem SRE-Team ein standardisiertes Betriebsmodell für die Verwaltung von Kubernetes-Clustern, Workflows und Audit-Änderungen bereitzustellen.

Um die Skalierungsprobleme Tausender von Sites zu lösen, haben wir die in Abbildung 3 dargestellte Architektur für SRE entwickelt:

verwalten03
Abbildung 3 – GitOps-Flow

Zunächst möchte ich betonen, dass wir Git nicht nur zum Speichern von Status oder Manifesten verwenden. Der Grund dafür ist, dass unsere Plattform nicht nur K8s-Manifeste, sondern auch laufende API-Konfigurationen, K8s-Versionen usw. verarbeiten muss. In unserem Fall machen die Manifeste von K8 etwa 60 % der gesamten deklarativen Konfiguration aus. Aus diesem Grund mussten wir darauf aufbauend unsere eigene DSL-Abstraktion entwickeln, die in Git gespeichert ist. Da Git weder eine API noch Funktionen zum Zusammenführen von Parametern bereitstellt, mussten wir zusätzliche Golang-Daemons für SRE entwickeln: Konfigurations-API, Executor und VP-Controller.

Sehen wir uns den Workflow zur Veröffentlichung einer neuen Softwareversion beim Kunden mithilfe unserer SaaS-Plattform an: 

  1. Der Betreiber entscheidet sich für die Veröffentlichung einer neuen Version und öffnet einen Merge Request (MR) für das Git-Modell
     
  2. Sobald dieser MR genehmigt und zusammengeführt ist, löst CI die Aktion aus, eine Git-Modellkonfiguration in unseren SRE Config-API-Daemon zu laden. Dieser Daemon verfügt über mehrere APIs zum Zusammenführen von Parametern, zur internen DNS-Konfiguration usw.
     
  3. Die Konfigurations-API wird vom Executor-Daemon überwacht. Unmittelbar nach dem Laden der Git-Änderungen beginnt er mit der Darstellung der endgültigen K8s-Manifeste mit der Version in der Annotation. Diese Manifeste werden dann in den Artifact-Speicher (ähnlich wie S3) unter dem Pfad ce01-site// .yml hochgeladen.
     
  4. Sobald die neue Version gerendert und in den Artefaktspeicher hochgeladen wurde, erzeugt Executor einen neuen Status mit einer verfügbaren Version für die Kunden-API; dies ist der neuen Version, die in Mobiltelefonen verfügbar ist, sehr ähnlich.
     
  5. Der Kunde (oder Betreiber) kann ein Update seiner Site auf die neueste Version planen und diese Informationen werden an VP-Controller weitergegeben. VP-Controller ist der Daemon, der für die Site-Verwaltung verantwortlich ist, einschließlich Bereitstellung, Außerbetriebnahme oder Migration an einen anderen Standort. Dies wurde bereits teilweise in der Zero-Touch-Bereitstellung erläutert und ist für die Aktualisierung von Edge-Sites über die mTLS-API verantwortlich
     
  6. Der letzte Schritt im Diagramm erfolgt auf der Edge-Site. Sobald die IPSec/SSL-VPN-Verbindung hergestellt ist, benachrichtigt der VP-Controller den VPM am Edge, Updates mit der neuen Version herunterzuladen. Wenn die Verbindung jedoch unterbrochen ist oder zeitweise Probleme auftreten, fragt der VPM alle 5 Minuten nach einem Update.
     
  7. Neue K8s-Manifeste und -Konfigurationen werden abgerufen und in K8s bereitgestellt. Mithilfe der im vorherigen Abschnitt beschriebenen Funktion der pessimistischen Bereitstellung wartet VPM, bis alle Pods bereit sind
     
  8. Als letzten Schritt sendet VPM den Status des Upgrades zurück an den VP Controller und dieser wird als Status an die Kunden-API weitergeleitet.

Sie können sich hier eine Demo des gesamten Workflows ansehen:

Erkenntnisse aus dem Testen von 3.000 Edge-Sites

In den vorherigen Abschnitten haben wir beschrieben, wie unsere Tools zum Bereitstellen und Verwalten des Lebenszyklus von Edge-Sites verwendet werden. Um unser Design zu validieren, haben wir beschlossen, eine groß angelegte Umgebung mit dreitausend Kunden-Edge-Sites aufzubauen (siehe Abbildung 4).

verwalten04
Abbildung 4 – 3000 Kunden-Edge-Sites

Wir haben Terraform verwendet, um 3000 VMs über AWS, Azure, Google und unsere eigene Bare-Metal-Cloud vor Ort bereitzustellen und so die Skalierung zu simulieren. Alle diese VMs waren unabhängige CEs (Customer Edge Sites), die redundante Tunnel zu unseren regionalen Edge Sites (auch PoPs genannt) aufgebaut haben.

Der folgende Screenshot stammt von unserem SRE-Dashboard und zeigt Kantennummern an Positionen, die durch die Kreisgröße dargestellt werden. Zum Zeitpunkt der Erstellung des Screenshots hatten wir etwa 2711 gesunde und 356 ungesunde Randstellen.

verwalten05
Abbildung 5–3000 Bereitstellung am Kunden-Edge-Standort

Wichtigste Ergebnisse: Operationen

Im Rahmen der Skalierung haben wir einige Probleme bei der Konfiguration und im Betrieb festgestellt, die Änderungen an unseren Software-Daemons erforderlich machten. Darüber hinaus sind wir auf viele Probleme mit einem Cloud-Anbieter gestoßen, die zur Eröffnung mehrerer Support-Tickets führten – beispielsweise Latenz bei der API-Antwort, Unfähigkeit, mehr als 500 VMs in einer einzigen Region abzurufen usw. 

  1. VP-Controller optimieren – anfangs haben wir die Registrierungen seriell verarbeitet und jede dauerte etwa zwei Minuten, da wir verschiedene Zertifikate für etcd, Kubernetes und VPM erstellen mussten. Wir haben diese Zeit durch vorgenerierte Schlüssel mit höherer Entropie und Parallelisierung mit einer größeren Anzahl von Arbeitern optimiert. Dadurch konnten wir die Registrierung für 100 Sites in weniger als 20 Sekunden verarbeiten. Wir konnten alle 3000 Edge-Sites bedienen, indem wir auf unserem VP-Controller nur etwa eine vCPU und 2 GB RAM verbrauchten.
     
  2. Optimieren Sie die Bereitstellung von Docker-Images – als wir mit der Skalierung begannen, stellten wir fest, dass die Menge der für Edge-Sites übertragenen Daten riesig ist. Jeder Edge-Server lud etwa 600 MB (multipliziert mit 3000) herunter, sodass insgesamt 1,8 TB Daten übertragen wurden. Außerdem haben wir während unserer Tests Edge-Sites mehrmals neu erstellt, sodass diese Zahl tatsächlich viel höher sein dürfte. Daher mussten wir die Größe unserer Docker-Images optimieren und Cloud- und ISO-Images mit vorinstallierten Docker-Images erstellen, um den Download zu reduzieren. Während wir immer noch einen öffentlichen Cloud-Containerregistrierungsdienst verwenden, arbeiten wir aktiv an einem Design, um unsere Containerregistrierung über REs (PoPs) zu verteilen und inkrementelle (binäre Diff-)Upgrades durchzuführen.
     
  3. Optimieren Sie globale Steuerungsdatenbankvorgänge – alle unsere Volterra-Steuerungsdienste basieren auf dem Golang-Service-Framework, das ETCD als Datenbank verwendet. Jede Site wird als Konfigurationsobjekt dargestellt. Jedes Site-Konfigurationsobjekt hat einige Statusobjekte wie Software-Upgrade, Hardware-Info oder IPSec-Status. Diese Statusobjekte werden von verschiedenen Plattformkomponenten erzeugt und alle werden in einer globalen Konfigurations-API referenziert. Als wir 3000 Sites erreichten, mussten wir bestimmte Optimierungen in unserem Objektschema vornehmen. Begrenzen Sie beispielsweise die Anzahl der von der globalen Konfigurations-API akzeptierten StatusObjects-Typen, oder wir haben beschlossen, sie in eine dedizierte ETCD-Instanz zu verschieben, um das Risiko einer Überlastung der Konfigurationsobjekt-Datenbank zu verringern. Dadurch können wir eine bessere Verfügbarkeit und Reaktionszeit für die Konfigurationsdatenbank bereitstellen und die Statusdatenbank im Fehlerfall neu erstellen. Ein weiteres Optimierungsbeispiel war die Einstellung unnötiger Site-Object-List-Operationen für alle Mandanten oder die Einführung sekundärer Indizes zur Reduzierung der Datenbanklast.

Wichtigste Ergebnisse: Beobachtbarkeit

Die Beobachtbarkeit eines verteilten Systems stellte uns vor viel größere Herausforderungen, als wir das System skalierten.

Für die Metriken haben wir zunächst mit der Prometheus-Föderation begonnen – ein zentrales Prometheus mit globaler Steuerung, das Prometheus in regionalen Rändern (REs) föderiert, das seine Servicemetriken abruft und Metriken aus den verbundenen CEs föderiert. Der Prometheus der obersten Ebene wertete Warnungen aus und diente als Messquelle für weitere Analysen. Wir stießen schnell an die Grenzen dieses Ansatzes (ca. 1000 CEs) und versuchten, die Auswirkungen der wachsenden Zahl von CEs zu minimieren. Wir haben begonnen, vorkalkulierte Reihen für Histogramme und andere Metriken mit hoher Kardinalität zu generieren. Dadurch konnten wir ein oder zwei Tage sparen, danach mussten wir Whitelists für die Messgrößen einsetzen. Am Ende konnten wir die Anzahl der Zeitreihenmetriken von rund 60.000 auf 2.000 für jeden CE-Standort reduzieren.

Nachdem wir die Skalierung auf über 3.000 CE-Sites ausgedehnt und den Betrieb viele Tage lang durchgeführt hatten, wurde uns schließlich klar, dass dies nicht skalierbar war und wir unsere Überwachungsinfrastruktur überdenken mussten. Wir haben uns entschieden, Prometheus auf oberster Ebene (unter globaler Kontrolle) fallen zu lassen und Prometheus in jedem RE in zwei separate Instanzen aufzuteilen. Einer ist für das Scraping lokaler Servicemetriken und der zweite für die Föderierung von CE-Metriken verantwortlich. Beide generieren Warnungen und übertragen Metriken in den zentralen Speicher in Cortex. Cortex wird als Analyse- und Visualisierungsquelle verwendet und ist nicht Teil des Warnflusses der Kernüberwachung. Wir haben mehrere zentralisierte Messlösungen getestet, nämlich Thanos und M3db, und kamen zu dem Schluss, dass Cortex unseren Anforderungen am besten entspricht.

verwalten06
Abbildung 6 – Architektur der Metrikerfassung

Der folgende Screenshot (Abbildung 7) zeigt den Speicherverbrauch beim Scraping von prometheus-cef zum Zeitpunkt von 3000 Endpunkten. Interessant ist der verbrauchte RAM von 29,7 GB, was angesichts der Größe des Systems eigentlich nicht so viel ist. Eine weitere Optimierung ist möglich, indem das Scraping in mehrere Schritte aufgeteilt wird oder der Remote-Schreibzugriff auf Cortex direkt an den Edge selbst verschoben wird.

verwalten07
Abbildung 7 – Ressourcennutzung am Standort RE

Der nächste Screenshot (Abbildung 8) zeigt, wie viele Speicher- und CPU-Ressourcen wir für Cortex-Ingestoren (max. 19 GB RAM) und Distributoren in dieser Größenordnung benötigten. Der größte Vorteil von Cortex ist die horizontale Skalierung, die es uns ermöglicht, mehr Replikate hinzuzufügen als bei Prometheus, wo die Skalierung vertikal erfolgen muss.

verwalten08
Abbildung 8 – Ressourcennutzung bei Global Control

Für die Protokollierungsinfrastruktur in CEs und REs verwenden wir Fluentbit-Dienste pro Knoten, die die Dienst- und Systemprotokollereignisse sammeln und an Fluentd im verbundenen RE weiterleiten. Fluentd leitet die Daten an das im RE vorhandene ElasticSearch weiter. Die Daten von ElasticSearch werden von Elastalert ausgewertet und es werden Regeln zum Erstellen von Alertmanager-Warnungen festgelegt. Wir verwenden unsere benutzerdefinierte Integration von Elastalert in Alertmanager, um Warnungen mit denselben Bezeichnungen zu erstellen, die auch Prometheus erstellt.

Die wichtigsten Punkte unserer Überwachungsreise:

  • Verwenden neuer Prometheus-Föderationsfilter zum Löschen nicht verwendeter Metriken und Labels

    - Anfangs hatten wir rund 50.000 Zeitreihen pro CE mit durchschnittlich 15 Labels

    - Wir haben es auf durchschnittlich 2000 pro CE optimiert

    Einfache While-Listen für Metriknamen und Blacklists für Labelnamen

  • Wechsel von der globalen Prometheus-Föderation zum Cortex-Cluster

    - Das zentralisierte Prometheus hat das Prometheus aller REs und CEs abgeschafft

    - Im Jahr 1000 n. Chr. wurde es unhaltbar, die Menge an Metriken zu verwalten

    - Derzeit haben wir Prometheus bei jedem RE (Föderation zu den Promethei der verbundenen CEs) mit RW zu Cortex

  • Elasticsearch-Cluster und -Protokolle

    - Dezentrale Protokollierungsarchitektur

    - Fluentbit als Collector auf jedem Knoten leitet Protokolle an Fluentd (Aggregator) in RE weiter

    - ElasticSearch wird in jedem RE eingesetzt und verwendet die Remote-Clustersuche, um Protokolle von einer einzelnen Kibana-Instanz abzufragen.

Zusammenfassung

Ich hoffe, dass dieser Blog Ihnen einen Einblick in die Dinge gibt, die bei der Verwaltung von Tausenden von Edge-Sites und Clustern auf der ganzen Welt berücksichtigt werden müssen. Auch wenn wir die meisten unserer anfänglichen Designanforderungen erfüllen und validieren konnten, liegen noch viele Verbesserungen vor uns …