Verwaltung von Hunderten von Code-Zweigen mit Jenkins
Bei Magnolia ist eine der größten Herausforderungen bei unserer KI die Gesamtzahl der Aufträge, mit denen wir arbeiten. Wir pflegen rund hundert Module, für die wir mehrere parallele aktive Releases haben. In diesem Blog werden wir das schlanke Setup besprechen, das es uns ermöglicht, diese Hunderte von Zweigen zu pflegen und zu bauen.
Zum Glück für uns folgen die meisten unserer Module dem gleichen Muster: ein Maven-Build auf Steroiden. Der springende Punkt ist die Erstellung, das Testen und die Bereitstellung von Artefakten für Nexus, wobei wir in der Lage sind, benutzerdefinierte Schritte hinzuzufügen - und das alles mit Jenkins. Die Suche nach einer effektiven und flexiblen Lösung hat uns einige Zeit gekostet. Lassen Sie mich nun erklären, wie wir es mit Bitbucket, Pipeline-Vorlagen und dem Pipeline Maven Integration Plug-in geschafft haben.
Bitbucket
Wir verwenden Bitbucket, um alle unsere Projekte zu verwalten. Unsere Maven-Module und -Reaktoren befinden sich in einem Projektordner unter https://git.magnolia-cms.com/projects. Jedes unserer Module kann mehrere aktiv gepflegte Zweige haben. Einige haben auch offene Pull Requests.
Während unsere Bitbucket-Instanz über alle Entwickleraktivitäten informiert ist, muss unsere Jenkins-Instanz nicht über alles informiert sein, was gepusht wird. Inaktive Zweige sind für die Jenkins-Instanz uninteressant, und sie muss auch nicht wissen, wenn ein Entwickler Arbeit in einen Testzweig verschiebt, um sie mit einem Kollegen zu teilen. Würde man allen Git-Hashes die gleiche Bedeutung beimessen, würde dies die Verarbeitungskosten erhöhen und unsere Entwickler ausbremsen, da irrelevante Builds die Warteschlange verstopfen und die relevanten Builds verzögern würden.
Unsere Jenkins-Instanz sucht nur nach Zweigen mit den Namen master oder release/*, die ein Jenkinsfile enthalten. Dies ist unsere Bitbucket-Job-Konfiguration:
Wenn Sie vorhaben, dieses Setup zu implementieren, möchten Sie vielleicht Force-Pushing zu diesen Zweigen verhindern oder das Zusammenführen ausschließlich durch Pull-Requests im Bitbucket-Berechtigungsschema erzwingen, das für Ihre Repositories gilt.
Pipeline-Vorlagen
Wenn Jenkins die Jenkinsfile aufnimmt, ist es wichtig, dass es die Build-Schritte nicht neu definiert. Es wäre ein Alptraum, wenn jeder Zweig Eigenschaften wie die Maven- oder Docker-Version oder die Flags für die verschiedenen Phasen, in denen wir Maven verwenden, ändern würde. Wenn wir jemals einen dieser Parameter aktualisieren müssten, würde es einen halben Tag an wiederholter Arbeit für einen Entwickler erfordern, jeden einzelnen Zweig zu ändern.
Stattdessen nutzen wir die gemeinsam genutzten Bibliotheken von Jenkins, um Snippets, Einstellungen und Vorlagen in unseren Builds mit nur einer Codezeile gemeinsam zu nutzen:
magnoliaDefaultPipeline()
Diese Funktion ersetzt eine Pipeline wie diese:
pipeline { agent { node { label 'aws' } } stages { stage('Build and deploy') { when { anyOf { branch 'master'; branch 'main'; branch 'release/*' } } steps { script { withMaven() { sh 'mvn deploy' } } } } } }
magnoliaDefaultPipeline() zieht die Job-Definition vars/magnoliaDefaultPipeline.groovy aus unseren Pipeline-Templates und löst damit automatisch die folgenden Jobs im Build des Zweigs aus:
Klonen Sie unsere Build-Skripte
Führen Sie den Maven-Build aus
Binäre Kompatibilität testen
Warnungen zur Abhängigkeitsanalyse prüfen
JIRA-Zustandsprüfung durchführen
Magnolia in a Can: Containerization with Magnolia
Learn how to deploy Magnolia as a Docker container based on best practices from our professional services team
Pipeline Maven-Integration
Ein weiteres wichtiges Teil des Puzzles ist das Pipeline Maven Integration Plug-in.
Der Prozess, den ich bisher beschrieben habe, ermöglicht es uns, viele unabhängige Module mit einem einfachen Aufbau zu erstellen.
Magnolia besteht jedoch aus vielen Modulen in einer bestimmten Reihenfolge: Main, UI, Community-Module, Community-Webapps, Enterprise-Module und Enterprise-Webapps. Zum Beispiel:
Dies ist möglich, indem wir das Plug-in fast überall dort aufrufen, wo wir Maven in einer Pipeline verwenden:
withMaven(mavenParameters.get()) { sh "mvn deploy" }
Das Plug-in ist dafür verantwortlich, zu prüfen, von welchen Modulen ein Zweig abhängt. Es weiß auch, welche Module bereits auf der Jenkins-Instanz gebaut wurden. Daher kann es jeden relevanten nachgelagerten Job auslösen, wenn ein Build abgeschlossen ist. Auf diese Weise pflegen wir unsere Triggerkette dynamisch und ohne Beteiligung der Entwickler.
AWS-Build-Skripte
Bash-Skripte sind der einzige Dateityp, den wir nicht mit gemeinsamen Bibliotheken zentralisieren konnten. Wir haben eine Lösung gefunden, indem wir sie in einem ersten Schritt von unseren Pipelines klonen lassen. Weitere Einzelheiten zu diesem Ansatz finden Sie in unserem Artikel über das Testen von Bash-Skripten mit Jenkins.
Schlussfolgerung
Die Verwaltung von Hunderten von Zweigen in Jenkins kann eine Herausforderung sein. Wir haben darüber nachgedacht, das Problem durch die Gruppierung von Modulen zu vereinfachen, aber dieser Ansatz hätte dem Produkt im Vergleich zu Fehlerbehebungen und neuen Funktionen nur wenig Wert hinzugefügt. Wir haben alternative CI-Lösungen ausprobiert, aber auf dem Markt keine gefunden, die für einen modularen Aufbau wie den unseren geeignet war.
Dank veröffentlichter Forschung, PoCs und Bibliotheken sind wir schließlich auf den in diesem Blog beschriebenen Ansatz gekommen, der uns hilft, unsere CI so zu verwalten, dass unsere Entwickler zufrieden sind. Wir haben sehr wenige Probleme mit diesem Setup und ich hoffe, dass dieser Blog es Ihnen ermöglicht, unsere Vorgehensweise zu reproduzieren.
Vor kurzem haben wir auch die Modular Pipeline Library entdeckt, die den Ansatz noch weiter verfolgt und mit der wir in Zukunft experimentieren wollen.