Unsere Erkenntnisse nach einem Jahr Migration von GitLab.com auf Kubernetes

Anmerkung des Übersetzers.: Die Anpassung von Kubernetes in GitLab wird als einer der beiden Hauptfaktoren angesehen, die das Wachstum des Unternehmens fördern. Bis vor Kurzem beruhte jedoch die Infrastruktur des Online-Dienstes GitLab.com auf virtuellen Maschinen, und erst vor etwa einem Jahr begann die Migration zu K8s, die bis heute noch nicht abgeschlossen ist. Wir freuen uns, die Übersetzung eines kürzlich veröffentlichten Artikels eines SRE-Ingenieurs von GitLab vorzustellen, der beschreibt, wie dies geschieht und welche Schlüsse die am Projekt Beteiligten ziehen.

Unsere Erkenntnisse nach einem Jahr Migration von GitLab.com auf Kubernetes

Seit etwa einem Jahr beschäftigt sich unser Infrastrukturteam mit der Migration aller Dienste, die auf GitLab.com laufen, zu Kubernetes. In dieser Zeit sind wir auf Probleme gestoßen, die nicht nur mit der Verschiebung der Dienste zu Kubernetes, sondern auch mit dem Management des hybriden Deployments während des Übergangs zusammenhängen. In diesem Artikel werden die wertvollen Lektionen vorgestellt, die wir gelernt haben.

Von Anfang an arbeiteten die Server von GitLab.com in der Cloud auf virtuellen Maschinen. Diese virtuellen Maschinen werden von Chef verwaltet, und ihre Installation erfolgt über unser offizielles Linux-Paket. Die Deploymentsstrategie für den Fall eines App-Updates besteht darin, die Serverlandschaft koordiniert und sequentiell mithilfe eines CI-Pipelines zu aktualisieren. Diese Methode — auch wenn sie langsam und ein wenig langweilig ist — garantiert, dass GitLab.com dieselben Installations- und Konfigurationsmethoden anwendet wie die Nutzer von (self-managed) Installationen von GitLab, die dafür unsere Linux-Pakete verwenden.

Wir verwenden diese Methode, weil es von größter Bedeutung ist, die Freuden und Sorgen, die die Mitglieder der Community bei der Installation und Konfiguration ihrer GitLab-Kopien erleben, selbst zu spüren. Dieser Ansatz hat einige Zeit gut funktioniert, aber als die Anzahl der Projekte auf GitLab über 10 Millionen stieg, stellten wir fest, dass er unseren Anforderungen an Skalierung und Deployment nicht mehr gerecht wurde.

Die ersten Schritte zu Kubernetes und einem cloud-nativen GitLab

Im Jahr 2017 wurde das Projekt GitLab Charts Um GitLab für die Bereitstellung in der Cloud vorzubereiten und den Benutzern zu ermöglichen, GitLab in Kubernetes-Clustern zu installieren. Zu diesem Zeitpunkt waren wir uns bewusst, dass der Umzug von GitLab nach Kubernetes die Skalierbarkeit der SaaS-Plattform erhöhen, die Bereitstellung vereinfachen und die Effizienz der Ressourcennutzung steigern würde. Gleichzeitig hingen viele Funktionen unserer Anwendung von gemounteten NFS-Partitionen ab, was den Übergang von virtuellen Maschinen verlangsamte.

Der Drang nach Cloud-Native und Kubernetes ermöglichte es unseren Ingenieuren, einen schrittweisen Übergang zu planen, bei dem wir einige Abhängigkeiten der Anwendung von Netzspeichern aufgegeben haben, während wir gleichzeitig neue Funktionen weiterentwickelten. Seit wir im Sommer 2019 mit der Planung der Migration begonnen haben, wurden viele dieser Einschränkungen beseitigt, und der Prozess der Übertragung von GitLab.com nach Kubernetes läuft jetzt auf Hochtouren!

Funktionsweise von GitLab.com in Kubernetes

Für GitLab.com nutzen wir einen einheitlichen regionalen GKE-Cluster, der gesamten Verkehr der Anwendung verarbeitet. Um die Komplexität (bereits eh schon schwierig) der Migration zu minimieren, konzentrieren wir uns auf Services, die nicht von lokalem Speicher oder NFS abhängen. GitLab.com verwendet hauptsächlich eine monolithische Codebasis auf Rails, und wir lenken den Verkehr abhängig von den Arbeitslastmerkmalen zu verschiedenen Endpunkten, die in ihren eigenen Node-Pools isoliert sind.

Im Falle des Frontends werden diese Arten unterteilt in Anfragen an Web, API, Git SSH/HTTPS und Registry. Im Backend unterteilen wir Jobs in Warteschlangen nach verschiedenen Merkmalen basierend auf vordefinierten Ressourcenlimits, die es uns ermöglichen, Zielvorgaben für die Dienstleistungsstufen (Service-Level Objectives, SLOs) für verschiedene Lasten festzulegen.

Alle diese Dienste von GitLab.com sind mit dem unveränderten Helm-Chart von GitLab konfiguriert. Die Konfiguration erfolgt in Subcharts, die nach Bedarf aktiviert werden können, während wir schrittweise Dienste in den Cluster übertragen. Selbst wenn beschlossen wurde, einige unserer stateful Dienste wie Redis, Postgres, GitLab Pages und Gitaly nicht in die Migration einzubeziehen, ermöglicht Kubernetes eine drastische Reduzierung der Anzahl der VMs, die derzeit von Chef verwaltet werden.

Transparenz und Konfigurationsmanagement von Kubernetes

Alle Einstellungen werden von GitLab selbst verwaltet. Dafür werden drei Konfigurationsprojekte auf Basis von Terraform und Helm verwendet. Wir versuchen überall, wo es möglich ist, GitLab selbst zum Starten von GitLab zu verwenden, aber für betriebliche Aufgaben haben wir eine separate Installation von GitLab. Diese ist notwendig, um bei der Durchführung von Bereitstellungen und Aktualisierungen nicht von der Verfügbarkeit von GitLab.com abhängig zu sein.

Obwohl unsere Pipelines für den Kubernetes-Cluster auf einer separaten Installation von GitLab laufen, gibt es für die Code-Repositories öffentliche Spiegel unter den folgenden Adressen:

  • k8s-workloads/gitlab-com — Konfigurations-Hülle für GitLab.com für das Helm-Chart von GitLab;
  • k8s-workloads/gitlab-helmfiles — enthält Konfigurationen für Dienste, die nicht direkt mit der Anwendung GitLab verbunden sind. Dazu gehören Konfigurationen für das Logging und Monitoring des Clusters sowie für integrierte Tools wie PlantUML;
  • Gitlab-com-infrastructure — Terraform-Konfiguration für Kubernetes und alte (Legacy) VM-Infrastruktur. Hier werden alle Ressourcen konfiguriert, die für den Betrieb des Clusters erforderlich sind, einschließlich des Clusters selbst, Knotenpools, Dienstkonten und IP-Reservierungen.

Unsere Erkenntnisse nach einem Jahr Migration von GitLab.com auf Kubernetes
Bei Änderungen wird eine öffentliche kurze Zusammenfassung angezeigt, die auf einen detaillierten Diff verweist, den die SRE vor der Durchführung von Änderungen im Cluster analysiert.

Für die SRE führt der Link zu einem detaillierten Diff in der GitLab-Installation, die für den Betrieb verwendet wird und auf die der Zugang eingeschränkt ist. Dadurch können Mitarbeiter und das Community ohne Zugang zum Betriebprojekt (das nur für die SRE geöffnet ist) vorgeschlagene Änderungen in der Konfiguration einsehen. Indem wir eine öffentliche Instanz von GitLab für den Code mit einer geschlossen Instanz für CI-Pipelines kombinieren, bewahren wir einen einheitlichen Workflow und gewährleisten gleichzeitig die Unabhängigkeit von GitLab.com bei Konfigurationsupdates.

Was wir während der Migration herausgefunden haben

Im Verlauf des Umzugs wurden Erfahrungen gesammelt, die wir auf neue Migrationen und Deployments in Kubernetes anwenden.

1. Steigende Kosten aufgrund des Datenverkehrs zwischen den Verfügbarkeitszonen

Unsere Erkenntnisse nach einem Jahr Migration von GitLab.com auf Kubernetes
Tägliche Egress-Statistik (Byte pro Tag) für den Git-Repo-Park auf GitLab.com

Google unterteilt sein Netzwerk in Regionen. Diese wiederum werden in Verfügbarkeitszonen (AZ) unterteilt. Git-Hosting ist mit großen Datenmengen verbunden, daher ist es wichtig, den Netzwerktraffic zu überwachen. Bei internem Datenverkehr ist der egress nur dann kostenlos, wenn er innerhalb einer einzigen Verfügbarkeitszone bleibt. Zum Zeitpunkt des Verfassens dieses Artikels geben wir an einem normalen Arbeitstag etwa 100 TB Daten aus (und das nur für Git-Repositorys). Dienste, die in unserer alten VM-basierten Topologie auf denselben virtuellen Maschinen liefen, arbeiten jetzt in unterschiedlichen Kubernetes-Pods. Das bedeutet, dass ein Teil des Verkehrs, der zuvor lokal für die VM war, potenziell über die Grenzen der Verfügbarkeitszonen hinausgeht.

Regionale GKE-Cluster ermöglichen es, mehrere Verfügbarkeitszonen zur Sicherstellung der Verfügbarkeit abzudecken. Wir prüfen die Möglichkeit, den regionalen GKE-Cluster in ein zonales Cluster aufzuteilen für Dienste, die große Datenmengen generieren. Dies wird die egress-Kosten senken, während die Clusterverfügbarkeit erhalten bleibt.

2. Limits, Ressourcenanforderungen und Skalierung

Unsere Erkenntnisse nach einem Jahr Migration von GitLab.com auf Kubernetes
Anzahl der Replikate, die den Produktionsverkehr auf registry.gitlab.com verarbeiten. Der Verkehr erreicht seinen Höhepunkt um etwa 15:00 UTC.

Unsere Geschichte mit der Migration begann im August 2019, als wir den ersten Dienst – das GitLab Container Registry – nach Kubernetes migrierten. Dieser kritisch wichtige Dienst mit hohem Verkehrsaufkommen war für die erste Migration gut geeignet, da es sich um ein zustandsloses Dienstprogramm mit wenigen externen Abhängigkeiten handelt. Das erste Problem, mit dem wir konfrontiert waren, war die hohe Anzahl an verdrängten Pods aufgrund von Speichermangel auf den Knoten. Daher mussten wir die Anforderungen und Limits anpassen.

Es stellte sich heraus, dass bei Anwendungen, deren Speicherverbrauch im Laufe der Zeit zunimmt, niedrige Werte für die Anforderungen (die Speicher für jeden Pod reservieren) zusammen mit einem "großzügigen" festen Limit zur Nutzung zu einer Sättigung (Saturation) der Knoten und zu einer hohen Verdrängungsrate führten. Um dieses Problem zu beheben, wurde beschlossen, die Anforderungen zu erhöhen und die Limits zu senken.. Dies hat den Druck von den Knoten genommen und einen Lebenszyklus für die Pods geschaffen, der nicht zu viel Druck auf den Knoten ausübte. Jetzt beginnen wir mit Migrationen mit großzügigen (und fast identischen) Werten für Requests und Limits und passen diese bei Bedarf an.

3. Metriken und Protokolle

Unsere Erkenntnisse nach einem Jahr Migration von GitLab.com auf Kubernetes
Die Infrastrukturabteilung konzentriert sich auf Latenzen, Fehlerraten und die Sättigung mit festgelegten Zielen für den Service-Level (SLO), die an die Gesamtverfügbarkeit unseres Systems.

gebunden sind. Im vergangenen Jahr war eines der Schlüsselergebnisse in der Infrastrukturabteilung die Verbesserungen im Monitoring und im Umgang mit SLO. SLO haben es uns ermöglicht, Ziele für einzelne Dienste festzulegen, die wir während der Migration genau verfolgt haben. Aber selbst mit dieser verbesserten Sichtbarkeit ist es nicht immer möglich, Probleme sofort zu erkennen, indem wir Metriken und Alarme verwenden. Zum Beispiel haben wir uns auf Latenzen und Fehlerraten konzentriert, aber wir decken nicht alle Nutzungsszenarien des Dienstes ab, der migriert wird.

Dieses Problem wurde fast sofort nach dem Transfer eines Teils der Workloads in den Cluster festgestellt. Besonders deutlich wurde es, als wir Funktionen überprüften, für die die Anzahl der Anfragen gering war, aber sehr spezifische Konfigurationsabhängigkeiten hatten. Eine der wichtigsten Lektionen aus der Migration war die Notwendigkeit, bei der Überwachung nicht nur Metriken, sondern auch Protokolle und den "langen Schwanz" (hier ist das die Verteilung auf dem Diagramm – Anm. d. Ü.) von Fehlern. Jetzt fügen wir für jede Migration eine detaillierte Liste von Abfragen zu den Protokollen (log queries) hinzu und planen klare Rollbackverfahren, die im Fall von Problemen von einem Schichtwechsel zum anderen übergeben werden können. Das parallele Bedienen derselben Anfragen auf der alten VM-Infrastruktur und der neuen, die auf Kubernetes basiert, war eine einzigartige Herausforderung. Im Gegensatz zur Lift-and-Shift-Migration

(schnelle Übertragung von Anwendungen „wie sie sind“ in die neue Infrastruktur; weitere Informationen finden Sie zum Beispiel auf (schnelle Übertragung von Anwendungen „wie sie sind“ in die neue Infrastruktur; weitere Informationen finden Sie beispielsweise unter hier — Anm. d. Übersetzer), die parallele Arbeit auf "alten" VMs und Kubernetes erfordert, dass die Überwachungstools mit beiden Umgebungen kompatibel sind und in der Lage sind, Metriken in einer einheitlichen Ansicht zu konsolidieren. Es ist wichtig, dass wir dieselben Dashboards und Abfragen für Logs verwenden, um eine konsistente Beobachtbarkeit während der Übergangsphase zu erreichen.

4. Umleitung des Datenverkehrs auf den neuen Cluster

Für GitLab.com sind einige Server reserviert für die Canary-Phase. Der Canary-Park bedient unsere internen Projekte und kann auch von Benutzern aktiviert werden. Primär dient er jedoch zur Überprüfung von Änderungen an der Infrastruktur und der Anwendung. Der erste migrierte Dienst begann mit der Annahme eines begrenzten Volumens internen Verkehrs, und wir setzen diese Methode fort, um sicherzustellen, dass die SLO eingehalten werden, bevor der gesamte Verkehr auf den Cluster geleitet wird.

Im Falle der Migration bedeutet dies, dass zuerst die Anfragen zu internen Projekten in Kubernetes geleitet werden, und anschließend schalten wir schrittweise den restlichen Verkehr auf den Cluster um, indem wir das Gewicht für das Backend über HAProxy ändern. Während des Übergangs von VMs zu Kubernetes wurde deutlich, dass es sehr vorteilhaft ist, eine einfache Möglichkeit zur Umleitung des Verkehrs zwischen der alten und der neuen Infrastruktur in der Hinterhand zu haben und die alte Infrastruktur während der ersten Tage nach der Migration für einen Rollback bereit zu halten.

5. Reserven der Pods und deren Nutzung

Bereits zu Beginn wurde das folgende Problem identifiziert: Die Pods für den Registry-Dienst starteten schnell, während das Starten der Pods für Sidekiq bis zu zwei Minutendauerte. Der lange Start der Pods für Sidekiq wurde zum Problem, als wir mit der Migration der Arbeitslasten für Worker nach Kubernetes begannen, die Jobs schnell verarbeiten und schnell skalieren mussten.

In diesem Fall war die Lektion, dass, obwohl der Horizontal Pod Autoscaler (HPA) in Kubernetes gut mit wachsendem Verkehr umgeht, es wichtig ist, die Eigenschaften der Arbeitslasten zu berücksichtigen und Reservekapazitäten der Pods bereitzustellen (insbesondere unter Bedingungen ungleichmäßiger Nachfrageverteilung). In unserem Fall erlebten wir einen plötzlichen Anstieg der Jobs, was ein schnelles Skalieren erforderlich machte, was zu einer Überlastung der CPU-Ressourcen führte, bevor wir den Node-Pool skalieren konnten.

Es gibt immer die Versuchung, aus dem Cluster so viel wie möglich herauszuholen, jedoch beginnen wir, nachdem wir zunächst auf Leistungsprobleme gestoßen sind, jetzt mit einem großzügigen Pod-Budget und reduzieren es später unter genauer Beobachtung des SLO. Der Start von Pods für den Sidekiq-Dienst hat sich erheblich beschleunigt und dauert nun im Durchschnitt etwa 40 Sekunden. Von der Verkürzung der Startzeit der Pods profitierte sowohl GitLab.com als auch unsere Benutzer der Self-Managed-Installationen, die mit dem offiziellen Helm-Chart von GitLab arbeiten.

Fazit

Nachdem wir jeden Dienst migriert hatten, freuten wir uns über die Vorteile der Nutzung von Kubernetes in der Produktion: schnellere und sicherere Anwendungs-Deployments, Skalierung und eine effizientere Ressourcennutzung. Die Vorteile der Migration gehen über den Dienst GitLab.com hinaus. Auch die Benutzer des offiziellen Helm-Charts profitieren von jeder Verbesserung.

Ich hoffe, Ihnen hat die Geschichte über unsere Abenteuer mit der Migration zu Kubernetes gefallen. Wir setzen die Migration weiterer Dienste in den Cluster fort. Weitere Informationen finden Sie in den folgenden Veröffentlichungen:

P.S. vom Übersetzer

Lesen Sie auch in unserem Blog:

Quelle: habr.com

60GB SSD 8Gb DDR4