Blog

Wie man echte Pipelines mit Jenkins und Maven erstellt

Marcus Martina

Aktualisiert Oktober 22, 2025
8 Minuten
Das Wesentliche bei der Erstellung einer Pipeline ist die Aufteilung eines einzelnen Build-Prozesses in kleinere Schritte, die jeweils ihre eigene Verantwortung haben. Auf diese Weise kann schnelleres und spezifischeres Feedback gegeben werden. Definieren wir eine echte Pipeline als eine Pipeline, die streng mit einer einzigen Revision in einem Versionskontrollsystem verbunden ist. Das ist sinnvoll, da wir idealerweise wollen, dass der Build-Server ein vollständiges und genaues Feedback für jede einzelne Revision zurückgibt. Da neue Revisionen jederzeit übertragen werden können, ist es natürlich, dass mehrere Pipelines nebeneinander ausgeführt werden. Bei Bedarf ist es sogar möglich, die gleichzeitige Ausführung desselben Build-Schritts für verschiedene Pipelines zuzulassen. Es müssen jedoch einige Maßnahmen ergriffen werden, um zu gewährleisten, dass alle Schritte, die innerhalb einer Pipeline ausgeführt werden, tatsächlich auf derselben Revision basieren.Innerhalb einer Jenkins Build Server-Instanz ist es möglich, eine echte Pipeline für ein Maven-basiertes Projekt recht einfach und effizient zu erstellen. Um eine solche Pipeline zu erstellen, müssen jedoch einige zusätzliche Jenkins-Plugins bereitgestellt und richtig konfiguriert werden, wie wir weiter unten sehen werden. Nehmen wir an, wir haben einen kontinuierlichen Build für ein Maven-Projekt mit mehreren Modulen auf oberster Ebene, den wir in die folgenden Schritte aufteilen möchten, wobei jeder Schritt von einem separaten Jenkins-Job ausgeführt wird.
  1. Erstellen - Auschecken der Hauptversion, Kompilieren und Unit-Testen des Codes, Erstellen und Archivieren der Artefakte
  2. Integrationstest - führen Sie Integrationstests für diese Artefakte durch
  3. Live-Bereitstellung - Artefakte auf einem Live-Server bereitstellen
  4. smoke test - führen Sie smoke tests für diese bereitgestellten Artefakte durch
Aus Gründen der Effizienz wird empfohlen, zu vermeiden, dass Arbeiten innerhalb derselben Pipeline mehrfach ausgeführt werden, wie z.B. ein vollständiges Auschecken, Kompilieren von Code, Testen von Code, Erstellen von Artefakten und Archivieren von Artefakten. Die verschiedenen Schritte in einer Pipeline können typischerweise durch die Aktivierung verschiedener Maven-Profile ausgeführt werden, die Artefakte, die in einem vorgelagerten Build erstellt und archiviert wurden, innerhalb derselben Pipeline wiederverwenden. Die integrierte automatische Archivierung von Artefakten ist in Jenkins standardmäßig aktiviert. Diese Funktion kann für nachgelagerte Aufträge oft deaktiviert werden, da diese Aufträge in der Regel keine Artefakte erzeugen, die wiederverwendet werden müssen.Das Maven 2 Projekt-Plugin setzt das lokale Maven-Repository standardmäßig auf ~/.m2/repository. Insbesondere bei der Implementierung von Pipelines ist es notwendig, diese Einstellung auf lokal für den Executor zu ändern, um Interferenzen zwischen gleichzeitigen Pipeline-Builds zu vermeiden. Obwohl dieses Verhalten in jeder auftragsspezifischen Konfiguration außer Kraft gesetzt werden kann, wird empfohlen, die generische Einstellung für das lokale Maven-Repository zu ändern, wenn Jenkins-Knoten mit mehreren Executors betrieben werden, da die lokalen Maven-Repositories für den gleichzeitigen Zugriff durch verschiedene Executors nicht sicher sind. Da die Executors jeweils über ein eigenes lokales Maven-Repository verfügen, ist es nicht mehr erforderlich, dass ein Maven-Build die generierten Artefakte tatsächlich in das lokale Repository installiert, da es keine Garantien dafür gibt, dass die aufeinanderfolgenden Schritte derselben Pipeline von demselben Executor ausgeführt werden. Außerdem werden, wie wir weiter unten sehen werden, die Artefakte, die in nachgelagerten Builds benötigt werden, ohnehin in das lokale Repository des zugewiesenen Executors heruntergeladen.Da jede Pipeline eindeutige Artefaktversionen erzeugt, kann die Größe der lokalen Maven-Repositories der Executors sehr schnell wachsen. Da jeder Pipeline-Build nur eine bestimmte Version der erzeugten Artefakte benötigt, macht es keinen Sinn, die älteren Versionen aufzubewahren.Daher ist es eine gute Idee, die lokalen Maven-Repositories auf allen Knoten regelmäßig zu bereinigen, zumindest für die Artefakte, die von den Pipelines erzeugt werden. Dies kann durch die Erstellung eines Aufräumjobs für jeden Knoten erfolgen, der ein einfaches Shell-Skript ausführt. Für den Master-Knoten bereinigt das folgende Beispielskript die lokalen Repositorys für alle Executors:
rm -rv ${JENKINS_HOME}/maven-repositories/*
Für die Slaves muss die Variable JENKINS_HOME in diesem Ausdruck durch das entsprechende Jenkins-Home-Verzeichnis ersetzt werden. Der NodeLabel Parameter Plugin kann verwendet werden, um die Aufräumarbeiten bestimmten Knoten zuzuordnen und das Heavy Job Plugin kann verwendet werden, um alle verfügbaren Executors auf diesem Knoten zuzuweisen, um den exklusiven Zugriff auf alle lokalen Repositories sicherzustellen. Lassen Sie uns nun die eigentliche Pipeline erstellen, indem wir das Plugin für parametrisierte Auslöser das es uns ermöglicht, vordefinierte Parameter an nachgelagerte Aufträge zu übergeben. Auf diese Weise können wir eine einzige Pipeline-Revisionsnummer vom ersten Job über die gesamte Pipeline hinweg weitergeben. Nehmen wir an, wir verwenden Subversion als Versionskontrollsystem. In diesem Fall können wir den Pipeline-Revisionsnummer-Parameter PL_SVN_REVISION als die integrierte Variable SVN_REVISION vordefinieren:
PL_SVN_REVISION = ${SVN_REVISION}
Von allen nachgelagerten Aufträgen wird der Pipeline-Parameter können einfach durch Aktivieren der Funktion für aktuelle Build-Parameter weitergegeben werden. Der PL_SVN_REVISION-Parameter kann in nachgelagerten Aufträgen verwendet werden, um revisionsspezifischen Code auszuchecken, indem @${PL_SVN_REVISION} zur Repository-URL hinzugefügt wird. Dies könnte Code sein, der für das Bootstrapping eines Integrationstests oder Smoke-Tests oder für eine Live-Bereitstellung benötigt wird. Dieser Code ist vorzugsweise nur eine einzelne POM-Datei oder ein kleines Modul. Er muss nicht einmal tatsächliche Testskripte oder Fixtures enthalten. Diese können einfach als Artefakt in den ersten Job gepackt werden und genau wie andere Artefakte in nachgelagerten Jobs wiederverwendet werden. Der Jenkins Maven Repository Server Plugin ist ein großartiges Tool, da es einen einzelnen Job-Build als Maven-Repository mit allen Artefakten, die als Teil dieses Builds archiviert werden, offenlegt. Dies macht es sehr einfach und effizient, diese spezifischen Artefakte in nachgelagerten Jobs über den üblichen Maven-Abhängigkeitsmechanismus wiederzuverwenden. Es ist nicht mehr notwendig, dass Maven Artefakte in einem separaten Maven-Repository-Manager wie Nexus bereitstellt, da Jenkins nun völlig autark ist. Außerdem ist nur Jenkins selbst in der Lage, die spezifischen Artefakte bereitzustellen, die zu einer bestimmten Pipeline gehören. Mit dem Jenkins Maven Repository Server Plugin können wir einen Upstream-Job-Build als Maven-Repository definieren. Obwohl standardmäßig nur der letzte erfolgreiche Build unterstützt wird, ist es mit einem kleinen Trick möglich, einen anderen vorgelagerten Job-Build auszuwählen, genauer gesagt den Build, der die Artefakte erstellt hat, die in der Pipeline wiederverwendet werden sollen. Zu diesem Zweck definieren wir einen weiteren Pipeline-Parameter PL_CREATE_BUILD als Kombination aus der eingebauten Variable JOB_NAME und der eingebauten Variable BUILD_NUMBER vor :
PL_CREATE_BUILD = ${JOB_NAME}/Build/${BUILD_NUMBER}
Dieser Pipeline-Parameter kann vom ersten Job aus zusammen mit dem PL_SVN_REVISION-Parameter durch die gesamte Pipeline propagiert werden. Der spezifische Pfad ${PL_CREATE_BUILD} /repository bezeichnet nun tatsächlich das richtige Upstream-Maven-Repository. Dieser Ausdruck kann bei der Definition eines vorgelagerten Maven-Repositorys als angegebener Pfad im Repository gewählt werden. Da es sich jedoch um einen Ausdruck handelt, schlägt die Jenkins-Parse-POMs-Phase fehl. Die Lösung ist die Verwendung des Environment Injector Pluginzu verwenden, das es ermöglicht, jede Umgebungsvariable in den Build-Prozess zu injizieren. Das Jenkins Maven Repository Server Plugin definiert eine Umgebungsvariable Jenkins.Repository unter der Haube, wenn ein Upstream Maven Repository definiert wird. Lassen Sie uns stattdessen diese Umgebungsvariable explizit als Eigenschaftsinhalt mit dem Environment Injector Plugin injizieren:
Jenkins.Repository = ${JENKINS_URL}plugin/repository/project/${PL_CREATE_BUILD}/repository
Wie im Jenkins Maven Repository Server Plugin dokumentiert, kann diese Umgebungsvariable verwendet werden, um ein Maven Repository ${env.Jenkins.Repository} in einem jenkins-Profil in der Datei Maven settings.xml anzugeben. Um sicherzustellen, dass das ausführerspezifische lokale Maven Repository mit den Snapshot-Versionen der im ersten Job der Pipeline erstellten Artefakte aktualisiert wird, ist es notwendig, die Snapshots updatePolicy auf always zu setzen. Schließlich sind die verschiedenen Schritte einer Pipeline nicht an einen bestimmten Knoten oder Executor gebunden, was der Hauptgrund dafür ist, das Maven Repository Server Plugin überhaupt zu verwenden. Bitte beachten Sie, dass es vorkommen kann, dass ein von einem Executor ausgeführter Build tatsächlich auf einer älteren Pipeline basiert als der vorhergehende Build, der auf demselben Executor ausgeführt wurde. In diesem Fall müssen die Snapshot-Artefakte im lokalen Maven-Repository tatsächlich durch ältere Versionen, d.h. Artefakte mit älteren Zeitstempeln, ersetzt werden. Glücklicherweise scheint dies das Standardverhalten von Maven zu sein. Es ist also kein Pre-Build-Schritt erforderlich, der das lokale Repository bereinigt, um eine echte Pipeline zu gewährleisten.Nun können manchmal Build-Schritte aus verschiedenen Pipelines nicht gleichzeitig ausgeführt werden, weil ein exklusiver Zugriff auf dieselben Ressourcen erforderlich ist. Wenn es sich nur um einen einzigen Auftrag handelt, genügt es, dafür zu sorgen, dass die in Jenkins integrierte Funktion Gleichzeitige Builds ausführen, wenn nötig für diesen Auftrag deaktiviert ist, was ohnehin das Standardverhalten ist. In Fällen, in denen mehrere Aufträge betroffen sind, müssen diese explizit gedrosselt werden. So können beispielsweise die Bereitstellung von Artefakten auf einem Live-Server und die Durchführung eines Smoke-Tests für Artefakte, die bereits auf demselben Server bereitgestellt wurden, natürlich nicht gleichzeitig ausgeführt werden. Das Throttle Concurrent Builds Plugin kann verwendet werden, um Drosselkategorien zu definieren und die gleichzeitige Ausführung von Aufträgen einzuschränken, indem sie derselben Drosselkategorie zugewiesen werden. Außerdem können manchmal Build-Schritte verschiedener Pipelines nicht in einer zufälligen Reihenfolge ausgeführt werden. So kann beispielsweise die Bereitstellung von Artefakten einer Pipeline auf einem Live-Server nicht durch die Bereitstellung von Artefakten einer anderen Pipeline erfolgen, bevor ein Smoke-Test für die bereits bereitgestellten Artefakte ausgeführt wurde. Dies kann gewährleistet werden, indem Sie dem Smoke-Test-Job eine höhere Priorität zuweisen, indem Sie das Prioritäts-Sortier-Plugin.Manchmal kann ein Schritt in der Pipeline aufgrund eines technischen Fehlers fehlschlagen, der nicht mit der zugehörigen Revision zusammenhängt. Um einen Neuaufbau des fehlgeschlagenen nachgelagerten Auftrags auszulösen, müssen die Pipeline-Parameter PL_SVN_REVISION und PL_CREATE_BUILD manuell angegeben werden, was ein wenig umständlich ist. Hier das Rebuilder-Plugin nützlich, das den Wiederaufbau eines Auftrags mit denselben Parametern wie der fehlgeschlagene Build erleichtert. Alternativ kann das Build-Pipeline-Plugindas eine schöne Visualisierung der letzten Pipelines bietet, verwendet werden, um einen fehlgeschlagenen Build manuell erneut auszulösen. Leider werden in der aktuellen Version die Revisionsnummern der Pipelines nicht angezeigt. Um die tatsächlichen Revisionsnummern in Jenkins zu visualisieren, kann das Build Name Setter Plugin verwendet werden. Dies erleichtert die Identifizierung von Builds anhand der Revisionsnummer anstelle der Build-Nummer. Für den ersten Job können Sie den Build-Namen wie folgt festlegen
#${BUILD_NUMBER} - rev ${ENV,var="SVN_REVISION"}
Und für nachgelagerte Aufträge muss die Variable SVN_REVISION in diesem Ausdruck durch den Pipeline-Parameter PL_SVN_REVISION ersetzt werden, da diese unterschiedliche Werte haben können.

Verfasst von

Marcus Martina

Contact

Let’s discuss how we can support your journey.