Jenkins ist eine weitverbreitete Open-Source-Automatisierungsplattform, die in der Softwareentwicklung häufig in Verbindung mit Git für Continuous Integration (CI) eingesetzt wird. Durch automatisierte Builds und Tests unterstützt Jenkins die frühzeitige Identifizierung potenzieller Probleme und trägt zur Verbesserung der Entwicklungsqualität bei.
Das häufig genutzte Jenkins-Plugin Multijob ermöglicht die Bündelung mehrerer Jobs zu einer Gruppe und erleichtert so die Verwaltung komplexer Builds. Da dieses Plugin jedoch als veraltet gilt, erfolgt nun die Umstellung auf die Jenkins-Pipeline.
Jenkins-Multijob
In unserem bisherigen Setup wurden mehrere Tests als Jenkins-Multijob implementiert. Die folgende Jenkins-Meldung:
gab Anlass zur Umstellung eines Multijobs auf die Jenkins-Pipeline. An dieser Stelle soll als Beispiel ein Multijob für eine gekoppelte Simulation mit OpenFOAM und einem externen Strahlungs- und Wärmeleitungslöser dienen. Er besteht aus folgenden Schritten:
-
Init-Phase
- Erstellen eines gemeinsamen Workspaces für die beiden Simulationsprogramme
- Erstellung des Meshes für die OpenFOAM-Geometrie
-
Gekoppelte Simulation
- Ausführen von OpenFOAM
- Ausführen des externen HeatSolvers
Für jeden dieser Schritte gibt es einen eigenen Jenkins-Job.
Während eines Simulationsschritts arbeiten die Programme parallel und kommunizieren über die OpenFOAM-Schnittstelle “externalCoupled”. Das bedeutet, dass zu bestimmten Zeitpunkten der Strömungslöser Temperaturen vom Heatsolver erhält und der Heatsolver Wärmestromdichten von OpenFOAM empfängt. Die Details zur Durchführung der Simulation und zur Kopplung sind in den Steuerdateien der Programme festgelegt.
Pipeline
Jenkins-Pipeline-Jobs werden über ein Skript definiert, das sogenannte Jenkinsfile. Dieses enthält die Pipeline-Konfiguration und -Schritte für Jenkins.
pipeline { agent { // run on workstation kepler label 'kepler' } stages { stage('WorkSpace') { steps { echo "Build Workspace: $WORKSPACE" build quietPeriod: 0, job: 'Workspace-Box' } } stage('Meshing') { steps { echo "OF-Mesh" build quietPeriod: 0, job: 'OF-Meshing' } } stage('CoupledSimulation') { parallel { stage('Run-HeatSolver') { steps { build quietPeriod: 0, job: 'RunExternalHeatSolver' } } stage('Run-Openfoam') { steps { build quietPeriod: 120, job: 'RunOpenFoam' } } } } } }
In diesem Jenkinsfile wird die Pipeline für die gekoppelte Simulation definiert. Der wichtige Teil ist die parallel
-Umgebung, die die beiden Jenkins-Jobs RunExternalHeatSolver
und RunOpenFoam
gleichzeitig ausführt (OpenFOAM wird mit einer Verzögerung von 2 Minuten gestartet, was in etwa der Rechenzeit der Init-Phase des HeatSolvers entspricht).
Flexiblere Auswahl von Nodes und des Arbeitsverzeichnis
In der optimierten Version der Pipeline können der jeweilige Rechenknoten und das Arbeitsverzeichnis dynamisch über Parameter festgelegt werden. Dies erhöht die Flexibilität und ermöglicht insbesondere eine einfachere Anpassung der Jobs an verschiedene Jenkins-Slaves.
pipeline { agent none // Keine Default-Agent-Zuweisung parameters { string(name: 'WORK_DIR', defaultValue: '/path/to/default/workspace', description: 'Pfad zum Arbeitsverzeichnis') } stages { stage('WorkSpace') { steps { echo "Build Workspace in ${params.WORK_DIR}" build quietPeriod: 0, job: 'Workspace-Box', parameters: [ string(name: 'WORK_DIR', value: "${params.WORK_DIR}") ] } } stage('Meshing') { steps { echo "OF-Mesh in ${params.WORK_DIR}" build quietPeriod: 0, job: 'OF-Meshing', parameters: [ string(name: 'WORK_DIR', value: "${params.WORK_DIR}") ] } } stage('CoupledSimulation') { parallel { stage('Run-HeatSolver') { steps { echo "Running HeatSolver in ${params.WORK_DIR} on Node: Jacobi" build quietPeriod: 0, job: 'RunExternalHeatSolver', parameters: [ string(name: 'WORK_DIR', value: "${params.WORK_DIR}"), string(name: 'NODE', value: "Jacobi") ] } } stage('Run-Openfoam') { steps { echo "Running OpenFoam in ${params.WORK_DIR} on Node: Kepler" build quietPeriod: 120, job: 'RunOpenFoam', parameters: [ string(name: 'WORK_DIR', value: "${params.WORK_DIR}"), string(name: 'NODE', value: "Kepler") ] } } } } } }
Hier werden die beiden Parameter WORK_DIR und NODE an die Jobs RunExternalHeatSolver
und RunOpenFoam
übergeben, sodass:
- Run-HeatSolver: Du führst diesen Job auf dem Node Jacobi aus, und er nutzt das angegebene Arbeitsverzeichnis.
- Run-OpenFoam: Dieser Job läuft auf dem Node Kepler mit einer Verzögerung von 120 Sekunden, während er dasselbe Arbeitsverzeichnis verwendet.
Wichtig: Damit diese Pipeline korrekt funktioniert, müssen die Jenkins-Jobs RunExternalHeatSolver und RunOpenFoam so eingerichtet sein, dass sie die Parameter WORK_DIR und NODE akzeptieren.
Der agent
-Befehl in der Pipeline legt nur den Jenkins-Node für den jeweiligen stage
fest und wird nicht an die aufgerufenen Jobs weitergegeben. Um sicherzustellen, dass die Jobs auf dem richtigen Node ausgeführt werden, müssen die entsprechenden Parameter, wie NODE, explizit übergeben werden.
Beispiel:
stage('Run-HeatSolver') { agent { label 'Jacobi' } // Diese Stage läuft auf Jacobi steps { echo "Running HeatSolver on Jacobi in ${params.WORK_DIR}" build quietPeriod: 0, job: 'RunExternalHeatSolver', parameters: [ string(name: 'WORK_DIR', value: "${params.WORK_DIR}"), string(name: 'NODE', value: "Jacobi") ] } }
In diesem Beispiel legt der agent
-Befehl den Jenkins-Slave Jacobi für den stage
fest. Allerdings wird "Jacobi"
für den aufgerufenen Job RunExternalHeatSolver
zusätzlich als NODE-Parameter übergeben, damit der Job korrekt auf dem Node Jacobi ausgeführt wird. Ansonsten würde er auf dem Default-Node oder als SYSTEM laufen.
Durch die Verwendung dieser Parameter wird sichergestellt, dass die beiden Jobs flexibel auf unterschiedlichen Jenkins-Slaves (Nodes) ausgeführt werden können. Sie teilen sich dabei das gleiche Arbeitsverzeichnis, was die Pipeline anpassungsfähiger macht und die Ressourcenverwaltung in verteilten Jenkins-Umgebungen verbessert. Es wird dabei vorausgesetzt, dass beide Workstations bzw. Jenkins-Nodes Zugriff auf ein gemeinsames Arbeitsverzeichnis haben.
Links
Mehr zur Integration von Jenkins mit Visualisierungstools ist im Beitrag ParaView Headless Rendering zu finden.