Anmerkung der Redaktion: Von Zeit zu Zeit laden wir Mitglieder unserer Kunden-Community ein, einen Beitrag für den GitLab-Blog zu verfassen. Danke an Carl Myers, CI-Plattform-Manager bei Indeed, dass du uns von deinen Erfahrungen mit GitLab berichtest.
Hier bei Indeed ist es unsere Mission, Menschen dabei zu helfen, einen Job zu finden. Indeed ist die weltweit führende Job-Website mit mehr als 350 Millionen Einzelbesucher(innen) pro Monat.
Für die Engineering-Plattformteams von Indeed gilt ein etwas anderes Motto: „Wir helfen den Menschen dabei, Menschen zu helfen, einen Job zu finden.“ Als Teil einer datengesteuerten Engineering-Kultur, die gute zwei Jahrzehnte immer die Jobsuchenden in den Vordergrund gestellt hat, sind wir dafür verantwortlich, die Tools zu entwickeln, mit denen dies nicht nur möglich ist, sondern die die Entwickler(innen) auch darin unterstützen, tagtäglich gute Ergebnisse für die Jobsuchenden zu liefern.
Mit der kontinuierlichen Integration von GitLab konnte das nur 11 Personen umfassende CI-Plattformteam von Indeed effektiv Tausende von Benutzer(inne)n im gesamten Unternehmen unterstützen. Weitere Vorteile, die Indeed durch den Umstieg auf GitLab CI erreichen konnte:
- 79 % Anstieg der täglichen Pipelines
- 10–20 % niedrigere CI-Hardware-Kosten
- Gesunkener Supportaufwand
Weiterentwicklung unserer CI-Plattform: von Jenkins zu einer skalierbaren Lösung
Wie viele große Technologieunternehmen haben wir unsere CI-Plattform mit dem Wachstum des Unternehmens organisch aufgebaut und nutzten dabei die damals verfügbaren Open-Source- sowie branchenüblichen Lösungen. 2007, als Indeed weniger als 20 Entwickler(innen) hatte, verwendeten wir Hudson, den direkten Vorgänger von Jenkins.
Heute, nach fast zwei Jahrzehnten des Wachstums, haben wir Tausende von Entwickler(inne)n. Als neue Technologien verfügbar wurden, nahmen wir schrittweise Veränderungen vor und wechselten um 2011 herum zu Jenkins. Dank einer weiteren Verbesserung konnten wir die meisten unserer Workloads mithilfe von AWS EC2 auf dynamischen Worker Nodes in der Cloud umstellen. Mit dem Eintritt in das Kubernetes-Zeitalter stieß die Systemarchitektur jedoch an ihre Grenzen.
Die Architektur von Jenkins wurde nicht mit Blick auf die Cloud entwickelt. Jenkins funktioniert mit einem „Controller“-Knoten, einem Single Point of Failure, der wichtige Teile einer Pipeline ausführt und bestimmte Schritte an Worker Nodes (die bis zu einem gewissen Grad horizontal skaliert werden können) auslagert. Controller sind auch eine manuelle Skalierungsachse.
Wenn man zu viele Jobs für einen Controller hat, muss man sie manuell auf mehrere Controller verteilen. CloudBees bietet Möglichkeiten, dies zu mindern, etwa durch das CloudBees Jenkins Operations Center, in dem man seine Controllerkonstellation zentral verwalten kann. Die Ausführung von Controllern in einer Kubernetes-Umgebung bleibt jedoch eine Herausforderung, da jeder Controller ein anfälliger Single Point of Failure ist. Aktivitäten wie Node-Rollouts oder Hardwareausfälle verursachen Ausfallzeiten.
Neben den technischen Einschränkungen, die Jenkins mit sich bringt, hatte unsere CI-Plattform auch mehrere Probleme, die wir selbst verursacht hatten. Zum Beispiel haben wir die Jenkins-DSL Groovy verwendet, um in jedem Repository Jobs aus Code zu erstellen. Dies führte dazu, dass jedes Projekt seine eigene, kopierte und eingefügte Job-Pipeline hatte, was zu Hunderten von Versionen führte, die schwer zu warten und aktualisieren waren. Obwohle die Engineering-Kultur von Indeed auf Flexibilität Wert legt und es den Teams erlaubt, in separaten Repositories zu arbeiten, wurde diese Flexibilität zu einer Belastung, als Teams zu viel Zeit damit verbrachten, sich um regelmäßige Wartungsanfragen zu kümmern.
Als wir unser Technical Debt erkannten, setzten wir auf das Golden-Path-Muster, das Flexibilität bietet und gleichzeitig eine Standardroute vorgibt, um Updates zu vereinfachen und konsistente Praktiken in den Projekten zu fördern.
Das CI-Plattformteam bei Indeed ist nicht sehr groß. Unser Team aus rund 11 Entwickler(inne)n unterstützt Tausende von Benutzer(inne)n, bearbeitet Supportanfragen, führt Updates und Wartungen durch und ermöglicht einen ständig verfügbaren Support für unser globales Unternehmen.
Da unser Team nicht nur unsere GitLab-Instanz unterstützt, sondern die gesamte CI-Plattform einschließlich des Artefakt-Servers, unseres gemeinsamen Build-Codes und zahlreicher anderer, individueller Komponenten unserer Plattform, hatten wir alle Hände voll zu tun. Wir brauchten einen Plan, der uns half, unsere Herausforderungen zu meistern und gleichzeitig unsere vorhandenen Ressourcen so effizient wie möglich zu nutzen.
Umstieg auf GitLab CI
Nach einem sorgfältigen Design-Review mit den wichtigsten Stakeholdern entschieden wir, das gesamte Unternehmen von Jenkins zu GitLab CI zu migrieren. Die Hauptgründe für die Entscheidung für GitLab CI waren:
- Wir haben GitLab bereits für die Quellcodeverwaltung verwendet.
- GitLab ist eine Komplettlösung, die alles bietet, was wir für CI benötigen.
- GitLab CI wurde für Skalierbarkeit und die Cloud entwickelt.
- GitLab CI ermöglicht es uns, Vorlagen zu schreiben, die andere Vorlagen erweitern, was mit unserer Golden-Path-Strategie kompatibel ist.
- GitLab ist Open-Source-Software und das GitLab-Team hat uns bei der Bereitstellung von Fehlerkorrekturen immer unterstützt, was uns zusätzliche Flexibilität und Sicherheit gibt.
Als wir offiziell ankündigten, dass die GitLab-CI-Plattform für Benutzer(innen) allgemein verfügbar sein würde, erfolgten bereits 23 % aller Builds in GitLab CI mit einer Kombination von „Grassroots“-Bemühungen und Early Adopters.
Die Herausforderung der Migration lag jedoch in der großen Streuung. Aufgrund der großen Anzahl an benutzerdefinierten Builds in Jenkins hätte ein automatisiertes Migrationstools für die meisten Teams nicht funktioniert. Die meisten Vorteile des neuen Systems kamen erst zum Tragen, als das alte System auf dem Nullstand war. Nur dann konnten wir die Hardware ausschalten und die CloudBees-Lizenzgebühr sparen.
Funktionsgleichheit und die Vorteile eines Neustarts
Obwohl wir bei Indeed viele verschiedene Technologien unterstützen, sind die drei am häufigsten verwendeten Sprachen Java, Python und JavaScript. Mit diesen Programmiersprachen werden Bibliotheken, Bereitstellungen (Webservices oder Anwendungen) und Cron-Jobs (ein Prozess, der in regelmäßigen Abständen abläuft, z. B. um einen Datensatz in unserem Data Lake aufzubauen) erstellt. Jedes davon bildete eine Matrix an Projekttypen (Java Library, Python Cronjob, JavaScript Webapp usw.), für die wir ein Grundgerüst in Jenkins hatten. Daher mussten wir für jeden dieser Projekttypen eine Golden-Path-Vorlage in GitLab CI erstellen.
Die meisten Benutzer(innen) können diese empfohlenen Pfade ohne Änderungen nutzen, aber für jene, die eine Anpassung brauchen, ist der Golden Path trotzdem ein wichtiger Ausgangspunkt, der ihnen ermöglicht, nur das Nötige zu ändern und trotzdem in Zukunft von zentralisierten Vorlagenaktualisierungen zu profitieren.
Wir haben schnell gemerkt, dass die meisten Benutzer(innen), auch jene mit Anpassungen, gern den Golden Path nehmen bzw. ihn zumindest ausprobieren. Wenn sie ihre Anpassungen vermissen, können sie sie immer noch später hinzufügen. Das war ein überraschendes Ergebnis! Wir dachten, dass die Teams, die in signifikante Anpassungen investiert hatten, diese nur widerstrebend aufgeben würden, doch in der Mehrheit der Fälle waren sie den Teams nach der Umstellung egal. Dadurch konnten wir viele Projekte sehr schnell migrieren. Wir konnten einfach den Golden Path (eine kleine, etwa 6 Zeilen lange Datei mit Includes) in ihre Projekte einfügen und sie konnten sie von dort aus nutzen.
InnerSource als Retter in der Not
Das CI-Plattformteam hat auch eine Richtlinie eingeführt, die besagt, dass externe Beiträge Vorrang haben. So werden alle im Unternehmen zur Teilnahme ermutigt. Dies wird manchmal als InnerSource bezeichnet. Wir haben Tests und Dokumentationen geschrieben, um externe Beiträge – Beiträge von außerhalb unseres unmittelbaren Teams – zu ermöglichen, damit Teams, die Anpassungen schreiben wollten, sie stattdessen in den Golden Path hinter einer Feature-Flag einfügen können. So konnten sie ihre Arbeit mit anderen teilen und sicherstellen, dass wir sie im weiteren Verlauf des Projekts nicht beschädigen (denn sie wurde Teil unserer Codebase, nicht ihrer eigenen).
Dies hatte auch den Vorteil, dass manche Teams, die auf eine benötigte Funktion warten mussten, selbst an dieser Funktion arbeiten konnten. Wir konnten sagen: „Wir planen, die Funktion in ein paar Wochen zu implementieren. Wenn ihr sie eher braucht, dürft ihr gerne daran mitarbeitet.“ Am Ende wurden viele Kernfunktionen, die für die Gleichschaltung nötig waren, auf diese Weise schneller und besser entwickelt, als es für unser Team alleine möglich gewesen wäre. Ohne dieses Modell wäre die Migration nicht erfolgreich gewesen.
Vor dem Zeitplan und unter dem Budget
Unsere CloudBees-Lizenz lief am 1. April 2024 aus. Dies gab uns ein ambitioniertes Ziel für die vollständige Migration vor. Dies war besonders ehrgeizig, wenn man bedenkt, dass zu dieser Zeit 80 % aller Builds (60 % aller Projekte) noch Jenkins für ihre CI verwendeten. Dies bedeutete, dass über 2.000 Jenkins-Dateien noch umgeschrieben oder durch unsere Golden-Path-Vorlagen ersetzt werden mussten.
Um dieses Ziel zu erreichen, stellten wir Dokumentationen und Beispiele zur Verfügung, implementierten Funktionen, wo dies möglich war, und halfen unseren Benutzer(inne)n, Funktionen beizutragen, wo sie konnten.
Wir haben regelmäßige Bürozeiten eingeführt, zu denen jeder kommen und Fragen stellen oder unsere Hilfe bei der Migration in Anspruch nehmen konnte. Außerdem haben wir Supportfragen zur Migration vor fast allem anderen priorisiert. Unsere Teammitglieder wurden zu GitLab-CI-Profis und teilten dieses Wissen innerhalb des Teams und im gesamten Unternehmen.
Eine automatische Migration war bei den meisten Projekten nicht möglich, aber wir fanden heraus, dass sie für eine kleine Untergruppe an Projekten funktionierte, in denen es wenig Anpassungen gab. Wir erstellten eine Sourcegraph-Stapeländerungskampagne, um Merge Requests für die Migration von hunderten Projekten einzureichen und forderten unsere Benutzer(innen) auf, diese MRs anzunehmen.
Wir zogen Erfolgsgeschichten unserer Benutzer(innen) heran und weit verbreitet. Als die Benutzer(innen) neue Funktionen zu unseren Golden Paths beisteuerten, warben wir damit, dass diese Funktionen bei der Migration auf GitLab CI „kostenlos enthalten“ sind. Einige Beispiele sind integrierte Sicherheits -und Compliance-Scans, Slack-Benachrichtigungen für CI-Builds und Integrationen in andere interne Systeme.
Wir haben auch eine Kampagne aggressiver „Scream Tests“ durchgeführt. Wir haben Jenkins-Jobs, die schon eine Weile nicht mehr ausgeführt wurden oder schon länger nicht mehr erfolgreich waren, automatisch deaktiviert und teilten den Benutzer(inne)n mit, dass sie diese Jobs wieder aktivieren konnten, wenn sie sie nochmals brauchen würden. So konnten wir auf einfache Weise feststellen, welche Jobs wirklich gebraucht wurden. Wir hatten Tausende von Jobs, die seit unserer letzten CI-Migration (von Jenkins zu Jenkins) nicht ein einziges Mal ausgeführt worden waren. Dies zeigte uns, dass wir fast alle davon sicher ignorieren konnten.
Im Januar 2024 gaben wir unsere Benutzer(inne)n einen Anstoß, indem wir ankündigten, dass alle Jenkins-Controller schreibgeschützt werden (keine Builds), es sei denn, es wird ausdrücklich eine Ausnahme angefordert. Wir hatten viel bessere Informationen zum Eigentum von Controllern und sie entsprachen im Allgemeinen unserer Unternehmensstruktur, also war es sinnvoll, sich auf Controller und nicht auf Jobs zu konzentrieren. Die Liste der Controller war auch viel überschaubarer als die Liste der Jobs.
Um eine Ausnahme zu erhalten, baten wir unsere Benutzer(innen), ihre Controller in einer Tabelle zu suchen und ihre Kontaktinformationen daneben zu schreiben. Dadurch erhielten wir eine sichere, aktuelle Liste der Stakeholder, die wir auf dem Endspurt nachverfolgen konnten. Außerdem konnten uns die Benutzer(innen) dadurch deutlich mitteilen, welche Jobs sie unbedingt brauchten. Zu Spitzenzeiten hatten wir etwa 400 Controller; im Januar hatten wir 220, aber nur 54 Controller benötigten Ausnahmen (einige von ihnen gehörten uns, um unsere Tests und Canary Tests durchzuführen).
Wir hatten eine überschaubare Liste von etwa 50 Teams, die wir unter unseren Teammitgliedern aufteilten, und begannen, Kontakt aufzunehmen, um herauszufinden, wie jedes Team bei der Migration vorankam. Im Januar und Februar stellten wir fest, dass einige Teams planten, ihre Migration ohne unsere Hilfe vor dem 28. Februar abzuschließen. Andere planten wiederum, ihre Projekte vorher einzustellen, und eine sehr kleine Anzahl war sehr besorgt, dass sie es nicht schaffen würden.
Wir konnten mit dieser kleineren Gruppe von Teams zusammenarbeiten und ihnen einen maßgeschneiderten Service bieten. Wir erklärten ihnen, dass wir zwar nicht über das nötige Fachwissen verfügten, um die Migration für sie durchzuführen, dass wir aber mit Fachleuten aus ihrem Team zusammenarbeiten konnten. Für einige Projekte schrieben wir und sie überprüften; für andere schrieben sie und wir überprüften. Am Ende hat sich unsere ganze Arbeit ausgezahlt und wir haben Jenkins genau an dem Tag ausgeschaltet, den wir 8 Monate zuvor angekündigt hatten.
Die Ergebnisse: verbesserte CI-Effizienz und Benutzerzufriedenheit
Auf dem Höhepunkt führte unsere Jenkins CI-Plattform über 14.000 Pipelines pro Tag aus und bediente Tausende Projekte. Heute führt unsere GitLab-CI-Plattform schon einmal über 40.000 Pipelines an einem einzigen Tag aus und regelmäßig über 25.000 pro Tag. Die inkrementellen Kosten für jeden Job jeder Pipeline sind ähnlich wie bei Jenkins, aber ohne den Aufwand für die Hardware zum Ausführen der Controller. Darüber hinaus dienten diese Controller als Single Points of Failure und Skalierungsbegrenzer, die uns zwangen, unsere Plattform künstlich in Segmente zu unterteilen. Ein direkter Vergleich ist immer schwierig, aber wir haben festgestellt, dass die Kosten für unsere CI-Hardware ohne diesem Overhead um 10–20 % niedriger sind. Außerdem ist der Supportaufwand für GitLab CI niedriger, da sich die Anwendung automatisch in der Cloud skaliert, über Verfügbarkeitszonen ausfallsicher ist und für die Vorlagensprache eine hervorragende Dokumentation öffentlich verfügbar ist.
Ein ebenso wichtiger Vorteil ist, dass wir jetzt über 70 % Annahmerate unserer Golden Paths erreicht haben. Das bedeutet, dass wir eine Verbesserung umsetzen konnten, von der über 5.000 Projekte bei Indeed sofort ohne weitere Maßnahmen profitieren können. So konnten wir einige Jobs zu kostengünstigeren ARM64-Instanzen verschieben, die Build-Images der Benutzer(innen) einfacher auf dem neuesten Stand halten und unsere Möglichkeiten zur Kosteneinsparung besser verwalten. Am wichtigsten ist aber, dass unsere Benutzer(innen) mit der neuen Plattform zufriedener sind.
Über den Autor: Carl Myers lebt in Sacramento, Kalifornien, und ist Manager des CI-Plattformteams bei Indeed. Carl hat seine fast zwei Jahrzehnte lange Berufslaufbahn damit verbracht, interne Tools und Entwicklerplattformen zu entwickeln, die Entwickler(innen) in großen und kleinen Unternehmen begeistern und befähigen.
Danksagungen: Diese Migration wäre ohne die unermüdlichen Bemühungen von Tron Nedelea, Eddie Huang, Vivek Nynaru, Carlos Gonzalez, Lane Van Elderen und dem Rest des CI-Plattformteams nicht möglich gewesen. Unser Teams ist besonders dankbar für die Führung von Deepak Bitragunta. Unser Dank geht auch an Irina Tyree für ihre Unterstützung bei diesem langen Projekt, für die Bereitstellung von Ressourcen und die unternehmensweite Abstimmung. Abschließend möchten wir uns bei allen bei Indeed bedanken, die Code, Feedback und Fehlerberichte beigetragen sowie bei der Migration von Projekten geholfen haben.
Dies ist eine überarbeitete Version des Artikels Wie Indeed seine CI-Plattform durch Gitlab CI ersetzt hat, der ursprünglich auf dem Indeed-Engineering-Blog veröffentlicht wurde.