Kapitel 1. Einführung in Jenkins 2
Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com
Willkommen bei Jenkins 2: Up and Running. Egal, ob du Build-Administrator, Entwickler, Tester oder eine andere Rolle bist, du bist hier genau richtig, um mehr über diese Weiterentwicklung von Jenkins zu erfahren. Mit diesem Buch bist du auf dem besten Weg, die Funktionen von Jenkins 2 zu nutzen, um deine Pipelines mit einem Maß an Flexibilität, Kontrolle und Wartungsfreundlichkeit zu entwerfen, zu implementieren und auszuführen, das mit Jenkins bisher nicht möglich war. Und egal, welche Rolle du spielst, du wirst die Vorteile schnell erkennen.
Wenn du ein Entwickler bist, wird sich das Schreiben deiner Pipeline als Code bequemer und natürlicher anfühlen. Wenn du ein DevOps-Profi bist, wird die Wartung deiner Pipeline einfacher, weil du sie wie jeden anderen Code behandeln kannst, der wichtige Prozesse steuert. Als Tester/in kannst du die verbesserte Unterstützung für Funktionen wie Parallelität nutzen, um deine Arbeit noch effektiver zu gestalten. Wenn du ein Manager bist, kannst du die Qualität deiner Pipeline genauso sicherstellen wie die deines Quellcodes. Wenn du ein Jenkins-Benutzer bist, wirst du deine Fähigkeiten erheblich erweitern und für diese neue Entwicklung von "Pipelines-as-code" bereit sein.
Um diese Ziele zu erreichen, musst du den Übergang von deinen bestehenden Implementierungen verstehen und planen. Jenkins 2 stellt eine bedeutende Veränderung gegenüber den älteren, traditionelleren, formularbasierten Versionen von Jenkins dar. Und bei einer solchen Umstellung gibt es eine Menge zu lernen. Aber das ist alles überschaubar. In einem ersten Schritt müssen wir eine solide Grundlage für die Grundlagen von Jenkins 2 schaffen (Was ist es? Was sind die wichtigsten Punkte?), einschließlich der neuen Funktionen, der Änderungen in der Arbeitsumgebung und des Verständnisses der neuen Konzepte, auf denen es basiert. Darum geht es in diesem und im nächsten Kapitel. Einiges davon ist dir vielleicht schon bekannt. Und wenn ja, ist das großartig. Aber ich empfehle dir, zumindest die Abschnitte zu lesen, die dir bekannt vorkommen. Vielleicht gibt es dort etwas, das neu ist oder sich so sehr verändert hat, dass es sich lohnt, es zu beachten.
In diesem Kapitel werden wir auf einer hohen Ebene untersuchen, was Jenkins 2 anders macht und wie es zu dem passt, was du gewöhnt bist. Wir werden uns drei Schlüsselbereiche ansehen:
Was ist Jenkins 2 im Hinblick auf die wichtigsten neuen Funktionen und Merkmale?
Was sind die Gründe (Motivationen und Antriebskräfte) für die Verlagerung von Jenkins?
Wie kompatibel ist Jenkins 2 mit früheren Versionen? Was ist bei der Kompatibilität zu beachten?
Werfen wir zunächst einen Blick darauf, was Jenkins 2 von den herkömmlichen Jenkins-Versionen unterscheidet.
Was ist Jenkins 2?
In diesem Buch wird der Begriff "Jenkins 2" etwas unbestimmt verwendet. In unserem speziellen Kontext bezieht er sich auf die neueren Versionen von Jenkins, die Pipelines-as-Code und andere neue Funktionen wie Jenkinsfiles unterstützen, über die wir im Laufe des Buches sprechen werden.
Einige dieser Funktionen sind für Jenkins 1.x-Versionen bereits seit einiger Zeit über Plugins verfügbar. (Ein Großteil der neuen Funktionen von Jenkins 2 stammt aus größeren Aktualisierungen bestehender Plugins sowie aus völlig neuen Plugins). Aber Jenkins 2 ist noch mehr. Es steht für eine Verlagerung des Schwerpunkts auf diese Funktionen als bevorzugte, zentrale Art der Interaktion mit Jenkins. Anstatt Webformulare auszufüllen, um Aufträge für Jenkins zu definieren, können die Nutzer jetzt mit der Jenkins DSL und Groovy Programme schreiben, um ihre Pipelines zu definieren und andere Aufgaben zu erledigen.
DSL bezieht sich hier auf Domain-Specific Language, die "Programmiersprache" für Jenkins. Die DSL basiert auf Groovy und enthält Begriffe und Konstrukte, die Jenkins-spezifische Funktionen kapseln. Ein Beispiel ist das Schlüsselwort node
, das Jenkins mitteilt, dass du einen Knoten (früher "Master" oder "Slave") programmatisch auswählst, auf dem du diesen Teil deines Programms ausführen möchtest.
Die DSL ist ein Kernstück von Jenkins 2. Sie dient als Baustein, der andere wichtige Funktionen für die Benutzer ermöglicht. Schauen wir uns ein paar dieser Funktionen an, um zu sehen, wie sie Jenkins 2 von "altem" Jenkins unterscheiden. Wir werden uns einen Überblick über die neue Möglichkeit verschaffen, deinen Code in einer Jenkins-Datei von Jenkins zu trennen, einen strukturierteren Ansatz für die Erstellung von Workflows mit deklarativen Pipelines und eine aufregende neue visuelle Oberfläche namens Blue Ocean.
Das Jenkinsfile
In Jenkins 2 kann deine Pipeline-Definition jetzt getrennt von Jenkins selbst gespeichert werden. In früheren Versionen von Jenkins wurden deine Auftragsdefinitionen in Konfigurationsdateien im Jenkins-Stammverzeichnis gespeichert. Das bedeutete, dass Jenkins selbst in der Lage sein musste, die Definitionen zu sehen, zu verstehen und zu ändern (es sei denn, du wolltest direkt mit der XML-Datei arbeiten, was eine Herausforderung war). In Jenkins 2 kannst du deine Pipeline-Definition als DSL-Skript in einem Textbereich in der Weboberfläche schreiben. Du kannst den DSL-Code aber auch extern als Textdatei mit deinem Quellcode speichern. So kannst du deine Jenkins-Aufträge mit einer Datei verwalten, die den Code wie jeden anderen Quellcode enthält, einschließlich der Verfolgung des Verlaufs, der Anzeige von Unterschieden usw.
Der Dateiname, unter dem Jenkins 2 deine Auftragsdefinitionen/Pipelines erwartet, ist Jenkinsfile. Du kannst mehrere Jenkinsfiles haben, die sich durch das Projekt und den Zweig, in dem sie gespeichert sind, voneinander unterscheiden. Du kannst deinen gesamten Code in der Jenkinsfile speichern oder über gemeinsam genutzte Bibliotheken anderen externen Code aufrufen/einbeziehen. Außerdem gibt es DSL-Anweisungen, mit denen du externen Code in dein Skript laden kannst (mehr dazu in Kapitel 6).
Die Jenkinsdatei kann auch als Markierungsdatei dienen, d.h. wenn Jenkins eine Jenkinsdatei als Teil des Quellcodes deines Projekts sieht, versteht es, dass es sich um ein Projekt/einen Zweig handelt, den Jenkins ausführen kann. Jenkins weiß auch, mit welchem Projekt und welchem Zweig der Versionsverwaltung (SCM) es arbeiten muss. Dann kann es den Code in der Jenkins-Datei laden und ausführen. Wenn du mit dem Build-Tool Gradle vertraut bist, ähnelt dies der Idee der build.gradle-Datei, die von dieser Anwendung verwendet wird. Ich werde im Laufe des Buches noch mehr über Jenkinsfiles erzählen.
Abbildung 1-1 zeigt ein Beispiel für eine Jenkins-Datei in der Versionskontrolle.
Deklarative Pipelines
In war der Code in den früheren Versionen von Pipelines-as-Code in Jenkins hauptsächlich ein Groovy-Skript mit eingefügten Jenkins-spezifischen DSL-Schritten. Es gab kaum eine vorgegebene Struktur, und der Programmfluss wurde durch Groovy-Konstrukte gesteuert. Die Fehlerberichterstattung und -prüfung basierte auf der Ausführung des Groovy-Programms und nicht auf dem, was du mit Jenkins zu tun versuchst.
Dieses Modell ist das, was wir heute als Scripted Pipelines bezeichnen. Die DSL für die Pipeline hat sich jedoch weiterentwickelt.
In Scripted Pipelines unterstützte die DSL eine große Anzahl verschiedener Schritte, um Aufgaben auszuführen, aber es fehlten einige der wichtigsten Metaeigenschaften von Jenkins-orientierten Aufgaben, wie z. B. die Verarbeitung nach dem Build, die Fehlerprüfung für Pipelinestrukturen und die Möglichkeit, auf einfache Weise Benachrichtigungen basierend auf verschiedenen Zuständen zu senden. Vieles davon ließe sich durch Groovy-Programmiermechanismen wie die try-catch-finally
Blöcke nachbilden. Das erforderte jedoch zusätzlich zur Jenkins-orientierten Programmierung weitere Groovy-Programmierkenntnisse. Die in Abbildung 1-1 gezeigte Jenkins-Datei ist ein Beispiel für eine Scripted Pipeline mit try-catch
Benachrichtigungsfunktion.
In 2016 und 2017 hat CloudBees, das Unternehmen, das die meisten Beiträge zum Jenkins-Projekt leistet, eine verbesserte Programmiersyntax für Pipelines-as-code eingeführt, die Declarative Pipelines. Diese Syntax fügt den Pipelines eine klare, erwartete Struktur sowie erweiterte DSL-Elemente und -Konstrukte hinzu. Das Ergebnis ähnelt mehr dem Arbeitsablauf beim Erstellen einer Pipeline in der Weboberfläche (mit Freestyle-Projekten).
Ein Beispiel dafür ist die Post-Build-Verarbeitung mit Benachrichtigungen auf der Grundlage des Build-Status, die jetzt einfach über einen eingebauten DSL-Mechanismus definiert werden kann. Dadurch ist es nicht mehr nötig, eine Pipeline-Definition mit Groovy-Code zu ergänzen, um traditionelle Funktionen von Jenkins zu emulieren.
Die formalere Struktur von Declarative Pipelines ermöglicht eine sauberere Fehlerprüfung. Anstatt Groovy-Tracebacks zu durchsuchen, wenn ein Fehler auftritt, erhält der Benutzer eine kurze, gezielte Fehlermeldung, die in den meisten Fällen direkt auf das Problem verweist. Abbildung 1-2 zeigt einen Ausschnitt aus der Ausgabe der folgenden deklarativen Pipeline mit der verbesserten Fehlerprüfung:
pipeline
{
agent
any
stages
{
stae
(
'Source'
)
{
git
branch:
'test'
,
url:
'git@diyvb:repos/gradle-greetings'
stash
name:
'test-sources'
,
includes:
'build.gradle,/src/test'
}
stage
(
'Build'
)
{
}
}
}
Blue Ocean Interface
Die Struktur von, die mit deklarativen Pipelines einhergeht, dient auch als Grundlage für eine weitere Neuerung in Jenkins 2 - Blue Ocean, die neue visuelle Oberfläche von Jenkins. Blue Ocean fügt eine grafische Darstellung für jede Phase einer Pipeline hinzu, die Indikatoren für Erfolg/Misserfolg und Fortschritt anzeigt und einen Point-and-Click-Zugang zu den Protokollen für jeden einzelnen Teil ermöglicht. Blue Ocean bietet auch einen einfachen visuellen Editor. Abbildung 1-3 zeigt ein Beispiel für einen erfolgreichen Pipeline-Lauf mit den in Blue Ocean angezeigten Protokollen. Kapitel 9 ist ganz der neuen Schnittstelle gewidmet.
Neue Auftragstypen in Jenkins 2
Jenkins 2 enthält eine Reihe neuer Auftragstypen, die vor allem darauf ausgelegt sind, wichtige Funktionen wie Pipelines-as-Code und Jenkinsfiles zu nutzen. Diese Typen machen es einfacher denn je, die Erstellung von Aufträgen und Pipelines zu automatisieren und deine Projekte zu organisieren. Die Erstellung eines neuen Auftrags/Postens/Projekts beginnt auf die gleiche Weise.
Neue Auftragstypen und Plugins
Damit diese neuen Auftragsarten verfügbar sind, müssen die erforderlichen Plugins installiert sein. Wenn du die empfohlenen Plugins während des Installationsprozesses akzeptierst, erhältst du die hier beschriebenen Aufträge.
Sobald Jenkins 2 installiert ist und du dich eingeloggt hast, kannst du wie bisher neue Aufträge erstellen. Wie in Abbildung 1-4 zu sehen ist, schlägt der Text unter dem Banner "Willkommen bei Jenkins!" vor, "neue Aufträge zu erstellen", aber der Menüpunkt dafür heißt eigentlich "Neues Element". Die meisten dieser Elemente sind letztendlich auch eine Art Projekt. Für verwende ich die Begriffe "Auftrag", "Artikel" und "Projekt" im gesamten Buch.
Wenn du wählst, um einen neuen Auftrag in Jenkins 2 zu erstellen, wird dir ein Bildschirm angezeigt, auf dem du die Art des neuen Auftrags auswählen kannst(Abbildung 1-5). Du wirst einige bekannte Typen sehen, wie z. B. das Freestyle-Projekt, aber auch einige, die du vielleicht noch nicht gesehen hast. Ich fasse die neuen Auftragstypen hier kurz zusammen und erkläre sie dann in Kapitel 8 ausführlicher.
Pipeline
Wie der Name schon andeutet, ist der Projekttyp Pipeline für die Erstellung von Pipelines gedacht. Dazu wird der Code in der Jenkins-DSL geschrieben. Dies ist der Hauptprojekttyp, über den wir in diesem Buch sprechen werden.
Wie bereits erwähnt, können Pipelines entweder in einem "geskripteten" Syntaxstil oder in einem "deklarativen" Syntaxstil geschrieben werden. Pipelines, die in dieser Art von Projekt erstellt werden, können auch leicht in Jenkinsdateien umgewandelt werden.
Mappe
Unter kannst du Projekte gruppieren und nicht nur eine Art von Projekt. Beachte, dass dies nicht wie die traditionellen "Ansicht"-Reiter auf dem Jenkins-Dashboard ist, mit denen du die Liste der Projekte filtern kannst. Vielmehr ist es wie ein Verzeichnisordner in einem Betriebssystem. Der Ordnername wird Teil des Projektpfads.
Organisation
Bestimmte Versionsverwaltungsplattformen bieten einen Mechanismus zur Gruppierung von Repositories in "Organisationen". Jenkins-Integrationen ermöglichen es dir, Jenkins-Pipeline-Skripte als Jenkinsdateien in den Repositories innerhalb einer Organisation zu speichern und auf Basis dieser Dateien auszuführen. Derzeit werden GitHub- und Bitbucket-Organisationen unterstützt, weitere sind für die Zukunft geplant. Der Einfachheit halber werden wir in diesem Buch hauptsächlich über GitHub-Organisationsprojekte als Beispiel sprechen.
Unter der Voraussetzung, dass ausreichend Zugriff hat, kann Jenkins automatisch einen Organisations-Webhook (eine Benachrichtigung von der Website) auf der Hosting-Seite einrichten, der deine Jenkins-Instanz benachrichtigt, wenn Änderungen im Repository vorgenommen werden. Wenn Jenkins benachrichtigt wird, erkennt es die Jenkinsdatei als Markierung im Repository und führt die Befehle in der Jenkinsdatei aus, um die Pipeline zu starten.
Multibranchen-Pipeline
In verwendet Jenkins bei dieser Art von Projekt wieder die Jenkinsdatei als Markierung. Wenn in dem Projekt mit einer Jenkinsdatei ein neuer Zweig angelegt wird, erstellt Jenkins automatisch ein neues Projekt in Jenkins nur für diesen Zweig. Dieses Projekt kann auf jedes Git- oder Subversion-Repository angewendet werden.
Wir werden uns jeden dieser neuen Projekttypen in Kapitel 8 des Buches genauer ansehen. Es ist aber auch erwähnenswert, dass Jenkins nach wie vor das traditionelle Arbeitspferd der Aufträge - Freestyle-Projekte - unterstützt. Du kannst dort immer noch Aufträge über webbasierte Formulare erstellen und sie wie bisher ausführen. Aber der Schwerpunkt von Jenkins 2 liegt natürlich auf Pipeline-Aufträgen.
Es ist leicht zu erkennen, dass Jenkins 2 eine große Veränderung gegenüber dem traditionellen Jenkins-Modell darstellt. Deshalb lohnt es sich, ein paar Minuten darauf zu verwenden, die Gründe für die Veränderung zu diskutieren.
Gründe für die Verschiebung
Jenkins ist seit vielen Jahren das wohl produktivste Tool zur Verwaltung von Workflows und Pipelines. Was hat also den Ausschlag gegeben, Jenkins 2 zu ändern? Schauen wir uns einige mögliche Gründe an, sowohl externe als auch interne von Jenkins.
DevOps-Bewegung
Die Ideen von, die hinter Continuous Integration, Continuous Delivery und Continuous Deployment stehen, gibt es schon seit einigen Jahren. Aber anfangs waren sie eher ein Endziel als ein Ausgangspunkt. Da DevOps in den letzten Jahren immer mehr in den Mittelpunkt gerückt ist, erwarten die Nutzer und Unternehmen, dass die Werkzeuge sie bei der Umsetzung von DevOps und kontinuierlichen Praktiken unterstützen (oder sie zumindest nicht erschweren).
Angesichts der Stellung von Jenkins im Bereich der Workflow-Automatisierung war es zu erwarten (und vielleicht auch erforderlich), dass sich die Fähigkeiten von Jenkins weiterentwickeln würden, um diese Branchenfaktoren zu unterstützen.
Montage von Pipelines
Das Erstellen von einzelnen Aufträgen in der Jenkins Freestyle-Oberfläche war nicht unbedingt problematisch. Der Versuch, mehrere Aufträge zu einer kontinuierlichen Softwarebereitstellungspipeline zusammenzufügen, die den Code von der Übergabe bis zur Bereitstellung begleitet, war jedoch oft eine Herausforderung. Die Kernfunktionalität von Jenkins ermöglichte es, einen bestimmten Auftrag zu starten, nachdem ein anderer beendet war, aber die gemeinsame Nutzung von Daten zwischen Aufträgen, wie z. B. Arbeitsbereichen, Parametern usw., war oft problematisch oder erforderte spezielle Plugins oder Tricks, um dies zu erreichen.
Wiederaufnehmbarkeit
Ein wichtiger Teil der Funktionalität von Jenkins 2 hängt von der Dauerhaftigkeit der Pipelines ab. Das bedeutet, dass Aufträge auf Agenten weiterlaufen oder dort fortgesetzt werden, wo sie aufgehört haben, wenn der Master-Knoten neu startet. Eine der Voraussetzungen für die Kompatibilität eines Plugins mit Jenkins 2 ist die Fähigkeit, Zustände zu serialisieren, damit diese im Falle eines Neustarts des Master-Knotens wiederhergestellt werden können. Bei früheren Versionen von Jenkins war das nicht der Fall. Benutzer und Prozesse mussten sich oft durch die Protokolle wühlen, um herauszufinden, wo alles geblieben war, oder den Prozess von vorne beginnen.
Konfigurierbarkeit
Da die Benutzer von größtenteils auf die webbasierte Oberfläche beschränkt waren, mussten sie bei der Arbeit mit Jenkins in der Regel die richtige Stelle auf dem Bildschirm finden, sich mit den Schaltflächen und Feldern vertraut machen und versuchen, bei der Eingabe von Daten keine Tippfehler zu machen. Workflow-Änderungen (wie das Umordnen von Schritten in einem Auftrag oder das Ändern der Reihenfolge, in der Aufträge ausgeführt werden) konnten mehrere Interaktionen durch Klicken, Ziehen und Tippen erfordern, im Gegensatz zu den einfacheren Aktualisierungen, die in einer Texteditor-Oberfläche möglich sind. In einigen Fällen, in denen GUI-Elemente für die Schnittstelle zu den Werkzeugen bereitgestellt wurden, gab es keine Möglichkeit, bestimmte Befehle über die Jenkins-Oberfläche an die Werkzeuge zu senden. Die webbasierten Formulare, die in Jenkins vorherrschen, eignen sich gut für einfache, strukturierte Entscheidungen, aber nicht so gut für iterative oder entscheidungsbasierte Ablaufsteuerung.
Arbeitsbereiche teilen
Traditionell hatte in Jenkins jeder Auftrag seinen eigenen Arbeitsbereich, in dem er den Quellcode abrufen, Builds durchführen oder andere Aufgaben erledigen konnte. Für einzelne Aufträge funktionierte das gut, denn so wurden die Umgebungen isoliert und das Überschreiben von Daten verhindert. Wenn jedoch Aufträge miteinander verknüpft wurden, konnte dies zu einem ineffektiven Prozess führen, der nur schwer zu überwinden war. Wenn zum Beispiel mehrere Aufträge in einer Pipeline erstellte Artefakte verarbeiten mussten, war es äußerst ineffizient, die Artefakte jedes Mal neu zu erstellen. Das Speichern und Abrufen der Artefakte in einem Repository zwischen der Ausführung der Aufträge erforderte mehrere Schritte und eine zusätzliche Konfiguration für jeden Auftrag. Eine effizientere Strategie wäre es, den Arbeitsbereich zwischen den Aufträgen zu teilen - aber das war in Jenkins nicht ohne Weiteres möglich. Stattdessen musste der Benutzer benutzerdefinierte Arbeitsbereiche definieren und Parameter verwenden, die auf den Arbeitsbereich verwiesen, oder ein spezielles Plugin einsetzen, damit es funktionierte.
Spezialisiertes Wissen
Wie in der vorangegangenen Diskussion über gemeinsam genutzte Arbeitsbereiche zeigt, mussten die Benutzer oft die "richtigen Tricks" kennen, um etwas im alten Jenkins-System zu implementieren, was sie in einem normalen Programm oder Skript leicht tun konnten (Datenübertragung, Flusskontrolle, externe Aufrufe usw.).
Zugang zur Logik
Das alte Jenkins verließ sich in der Regel auf Webformulare, um Daten einzugeben, und speicherte sie in XML-Konfigurationsdateien in seinem Home-Verzeichnis. Bei dieser Implementierung gab es keine einfache Möglichkeit, die Logik bei der Ausführung mehrerer Aufträge auf einen Blick zu sehen. Für Benutzer/innen, die damit nicht vertraut waren, konnte das Verständnis der Jenkins-Einrichtung und der Auftragsdefinitionen ein längeres Scrollen durch Bildschirme, das Betrachten von Werten in Formularen, das Hin- und Herblättern zwischen globalen Konfigurationen usw. erfordern. Das machte eine breitere Unterstützung, die Zusammenarbeit zwischen mehreren Nutzern und das Verständnis von Multijob-Pipelines zu einer Herausforderung, vor allem, wenn umfangreiche Änderungen, Überprüfungen oder Fehlerbehebungen vorgenommen werden mussten.
Pipeline Quellenmanagement
Wie im vorherigen Abschnitt gezeigt hat, war die "Quelle" für einen alten Jenkins-Auftrag eine XML-Datei. Diese war nicht nur schwer zu lesen, sondern auch schwer zu ändern und zu korrigieren, ohne das Webinterface zu benutzen. Die Konfiguration war nicht dafür gedacht, am gleichen Ort wie der Quellcode zu existieren. Konfiguration und Quellcode waren zwei getrennte Einheiten, die auf zwei verschiedene Arten verwaltet wurden.
Eine Folge davon war die mangelnde Nachvollziehbarkeit. Es gab zwar Plugins, die dabei halfen, Änderungen im Laufe der Zeit nachzuverfolgen, aber das war nicht so bequem wie die Nachverfolgung einfacher Änderungen an den Quelldateien und erforderte immer noch, dass die Jenkins-Anwendung selbst in der Lage war, Änderungen an Aufträgen nachzuverfolgen.
Wettbewerb
Ein zusätzlicher Faktor, der hier zweifellos eine Rolle gespielt hat, ist, dass andere Anwendungen entstanden sind, die Pipelines als Code einrichten. Es gibt verschiedene Beispiele wie Concourse von Pivotal, das die Containerisierung von Aufträgen nutzt und die Beschreibung von Pipelines in YAML-Dateien ermöglicht.
Die Herausforderungen meistern
Wie kann Jenkins 2 diese Herausforderungen meistern? Ich habe bereits einige Möglichkeiten angedeutet, aber es gibt noch ein paar Punkte, die es wert sind, an dieser Stelle hervorgehoben zu werden:
-
Pipelines werden als Bürger erster Klasse behandelt. Das bedeutet, dass es ein Design und Unterstützung für die Arbeit mit Pipelines als Entität in der Anwendung gibt, anstatt dass Pipelines etwas sind, das durch das Verbinden von Aufträgen in Jenkins entsteht.
-
Pipelines können durch Kodierung programmiert werden, anstatt nur durch eine Konfigurationsschnittstelle ausgedrückt zu werden. Dies ermöglicht die Verwendung zusätzlicher Logik und Workflows sowie Programmierkonstrukte, die im alten Jenkins nicht verfügbar waren oder nicht auftauchten.
-
Es gibt eine strukturierte DSL speziell für die Programmierung von Pipelines.
-
Eine Pipeline kann direkt als Skript in einem Auftrag erstellt werden, ohne dass eine umfangreiche Webformular-Interaktion erforderlich ist. Außerdem können sie völlig separat in Jenkinsfiles erstellt werden.
-
Pipelines, die als Jenkinsdateien gespeichert werden, können jetzt mit dem Quellcode getrennt von Jenkins gespeichert werden.
-
Die DSL enthält Funktionen zum einfachen Austausch von Dateien zwischen Arbeitsbereichen.
-
Es gibt eine erweiterte, integrierte Unterstützung für die Arbeit mit Docker-Containern.
All dies führt zu einer leichteren Wartbarkeit und zu Tests sowie zu mehr Widerstandsfähigkeit. Wir können Ausnahmefälle mit typischen Konstrukten behandeln und Ereignisse wie Neustarts besser überstehen.
Bevor wir uns näher mit den Funktionen von Jenkins 2 befassen, lohnt es sich, einen Moment über die Kompatibilität zwischen dem alten und dem neuen System zu sprechen.
Kompatibilität
Für die meisten Artikel gibt es entsprechende Möglichkeiten, um über Pipelines die gleiche Funktionalität zu erhalten wie über die traditionelle Weboberfläche und Freestyle-Aufträge. Es gibt sogar mehrere Möglichkeiten, einige davon sind eingebaut, andere sind ausgeklügelt. Dies lässt sich am besten mit einer kurzen Diskussion über die zwei verschiedenen Syntaxarten beschreiben, die Jenkins für die Erstellung von Pipelines unterstützt.
Pipeline-Kompatibilität
Wie bereits erwähnt, unterstützt Jenkins 2 jetzt zwei Arten von Pipelines - skriptgesteuerte und deklarative Pipelines - mit jeweils eigener Syntax und Struktur. In den nächsten Kapiteln werden wir mehr über beide Arten erfahren, aber jetzt wollen wir uns erst einmal ein konkretes Beispiel ansehen: die Post-Build-Benachrichtigung in einer traditionellen Freestyle-Struktur und die entsprechenden Funktionen in Scripted und Declarative Pipelines.
Abbildung 1-6 zeigt die Post-Build-Konfiguration eines herkömmlichen Freestyle-Projekts für einen typischen Vorgang: das Versenden von E-Mail-Benachrichtigungen. In einem Freestyle-Projekt gibt es dafür ein spezielles Webseiten-Element mit Feldern, die für die Konfiguration ausgefüllt werden müssen.
In der Syntax für eine Scripted Pipeline gibt es keine eingebaute Möglichkeit, solche Post-Build-Aktionen durchzuführen. Wir beschränken uns auf die DSL-Schritte und das, was mit Groovy-Codierung gemacht werden kann. Um also nach einem Build immer eine E-Mail zu senden, müssen wir wie hier gezeigt kodieren:
node
{
try
{
// do some work
}
catch
(
e
)
{
currentBuild
.
result
=
"FAILED"
throw
e
}
finally
{
to:
"buildAdmin@mycompany.com"
,
subject:
"STATUS FOR PROJECT: ${currentBuild.fullDisplayName}"
,
body:
"RESULT: ${currentBuild.result}"
}
}
Angenommen, wir haben unser E-Mail-Setup bereits global in Jenkins konfiguriert, können wir die Anweisung DSL mail
verwenden, um eine E-Mail zu versenden. Da wir in der Skriptsyntax keine Pipeline-Anweisung/Funktion haben, um immer etwas als Post-Build-Operation zu tun, greifen wir auf die Groovy try-catch-finally
Syntax zurück.
Dies macht auf Kompatibilitätsausnahmen bei einigen Jenkins-Funktionen aufmerksam, z. B. bei der Post-Build-Verarbeitung. In solchen Fällen können DSL-Konstrukte fehlen. In solchen Fällen musst du eventuell auf Groovy-Konstrukte zurückgreifen, die die Verarbeitung durch Jenkins nachahmen können. (Dieser Ansatz wird in Kapitel 3 ausführlicher behandelt.)
Wenn du dich für die Declarative Pipeline-Struktur entscheidest, stehen die Chancen gut, dass dir Konstrukte zur Verfügung stehen, mit denen du die meisten der gängigen Jenkins-Funktionen ausführen kannst. In der Declarative Pipeline-Syntax gibt es zum Beispiel einen Abschnitt post
, der definiert werden kann, um Nachbearbeitungsschritte ähnlich wie die traditionelle Post-Build-Bearbeitung und Benachrichtigungen zu handhaben (wir behandeln dies in Kapitel 7):
pipeline
{
agent
any
stages
{
stage
(
"dowork"
)
{
steps
{
// do some work
}
}
}
post
{
always
{
to:
"buildAdmin@mycompany.com"
,
subject:
"STATUS FOR PROJECT: ${currentBuild.fullDisplayName}"
,
body:
"RESULT: ${currentBuild.result}"
}
}
}
Die Kompatibilität spielt nicht nur bei der eigentlichen Programmierung eine Rolle. Ein weiterer erwähnenswerter Bereich ist die Plugin-Kompatibilität.
Plugin-Kompatibilität
Wie bei der Vorgängerversion von Jenkins wird der Großteil der Funktionen von Jenkins 2 durch die Integration von Plugins bereitgestellt. Mit der Einführung von Jenkins 2 wurden neue Anforderungen an die Kompatibilität der Plug-ins gestellt. Wir können die Anforderungen grob in zwei Kategorien einteilen: Sie müssen Neustarts überstehen und erweiterte APIs bereitstellen, die in Pipeline-Skripten verwendet werden können.
Neustarts überleben
Eine der Eigenschaften/Anforderungen von Jenkins 2-Pipelines ist, dass sie Neustarts eines Knotens überstehen müssen. Um dies zu unterstützen, ist das Hauptkriterium, dass zustandsbehaftete Objekte in Plugins serialisierbarsein müssen , d.h.ihr Zustand muss aufgezeichnet werden können. Das ist bei vielen Konstrukten in Java und Groovy nicht selbstverständlich, sodass Plugins unter Umständen erheblich geändert werden müssen, um diese Anforderung zu erfüllen.
Pipeline-Skripte, die wieder gestartet werden können
Wenn ein bestimmter Teil des Codes nicht serialisierbar ist, gibt es in manchen Fällen Möglichkeiten, seine Verwendung zu umgehen. In Kapitel 16 findest du einige Vorschläge, wie du diese Art von Problemen umgehen kannst.
Skriptfähige APIs bereitstellen
Um mit dem Schreiben von Pipeline-Skripten kompatibel zu sein, müssen die Schritte, die früher durch das Ausfüllen der Jenkins-Webformulare erledigt wurden, jetzt als Pipeline-Schritte mit kompatibler Groovy-Syntax ausgedrückt werden können. In vielen Fällen sind die Begriffe und Konzepte sehr ähnlich zu denen, die in den Formularen verwendet wurden. Wo Foo
in der formularbasierten Version des Plugins ein Label für ein Texteingabefeld war, kann es jetzt einen DSL-Aufruf mit Foo
als benanntem Parameter geben, dem ein Wert übergeben wird.
Als Beispiel werden wir die Konfiguration und die Vorgänge für Artifactory, einen binären Artefaktmanager, verwenden. Abbildung 1-7 zeigt, wie wir die Build-Umgebung für einen Freestyle-Jenkins-Job so konfigurieren können, dass er auf Artifactory-Repositories zugreifen kann.
Und hier ist, wie wir die ähnliche Konfiguration in einem Pipeline-Skript vornehmen können:
// Define new Artifactory server based on our configuration
def
server
=
Artifactory
.
server
"LocalArtifactory"
// Create a new Artifactory for Gradle object
def
artifactoryGradle
=
Artifactory
.
newGradleBuild
()
artifactoryGradle
.
tool
=
"gradle4"
// Tool name from Jenkins configuration
artifactoryGradle
.
deployer
repo:
'libs-snapshot-local'
,
server:
server
artifactoryGradle
.
resolver
repo:
'remote-repos'
,
server:
server
Neben der Konfiguration gibt es noch die eigentlichen Vorgänge, die ausgeführt werden müssen. In den Freestyle-Aufträgen gibt es wieder Kontrollkästchen und Webformulare, die Jenkins sagen, was zu tun ist. (Siehe Abbildung 1-8.)
Und wenn das Plugin pipeline-kompatibel ist, werden wir im Kontext eines Pipeline-Skripts wahrscheinlich ähnliche DSL-Anweisungen haben, um die API-Aufrufe für dieselbe Funktionalität zu machen. Das folgende Beispiel zeigt ein entsprechendes Pipeline-Skript für das vorangegangene Artifactory Freestyle-Beispiel:
// buildinfo configuration
def
buildInfo
=
Artifactory
.
newBuildInfo
()
buildInfo
.
env
.
capture
=
true
// Deploy Maven descriptors to Artifactory
artifactoryGradle
.
deployer
.
deployMavenDescriptors
=
true
// extra gradle configurations
artifactoryGradle
.
deployer
.
artifactDeploymentPatterns
.
addExclude
(
"*.jar"
)
artifactoryGradle
.
usesPlugin
=
false
// run the Gradle piece to deploy
artifactoryGradle
.
run
buildFile:
'build.gradle'
tasks:
'cleanartifactoryPublish'
buildInfo:
buildInfo
// publish build info
server
.
publishBuildInfo
buildInfo
In einigen Fällen können Pipeline-Skripte auch Elemente nutzen, die bereits in der traditionellen Jenkins-Oberfläche konfiguriert sind, wie z. B. globale Werkzeuge. Ein Beispiel für die Verwendung von Gradle wird im Folgenden gezeigt.
In der ersten Abbildung(Abbildung 1-9) sehen wir das globale Tool-Setup für unsere Gradle-Instanz. Dann sehen wir, wie es in einem Freestyle-Projekt verwendet wird(Abbildung 1-10), und schließlich sehen wir, wie es in einem Pipeline-Projekt über einen speziellen DSL-Schritt namens tool
verwendet wird, der es uns ermöglicht, auf die globale Konfiguration zurückzugreifen, basierend auf dem übergebenen name
Argument.
stage
(
'Compile'
)
{
// Compile and do unit testing
// Run gradle to execute compile
sh
"${tool 'gradle3.2'}/bin/gradle clean build"
}
Deklarative Pipelines haben auch eine tool
Direktive, die die gleiche Funktionalität in dieser Art von Pipeline ermöglicht.(In Kapitel 7 werden deklarative Pipelines im Detail besprochen.)
Wie wir gesehen haben, ist die Bereitstellung von APIs (und damit die Kompatibilität von Plugins mit Pipelines) von zentraler Bedeutung, um traditionelle Funktionen in Pipelines ausführen zu können. Irgendwann werden alle Plugins Pipeline-kompatibel sein müssen, aber zum jetzigen Zeitpunkt gibt es immer noch Plugins, die nicht oder nicht vollständig kompatibel sind. Es gibt jedoch einige Stellen, an denen du die Kompatibilität überprüfen kannst.
Überprüfung der Kompatibilität
Unter findest du Informationen darüber, ob vorhandene Plugins mit der Verwendung von Pipelines in Jenkins 2 kompatibel sind oder nicht. Beachte, dass die Informationen hier nicht garantiert auf dem neuesten Stand sind, aber diese Seiten bieten wahrscheinlich die beste Zusammenfassung der verfügbaren Informationen.
Eine Seite ist auf GitHub, wie gezeigt. Ein Beispiel für eine solche Seite ist in Abbildung 1-11 zu sehen.
Die andere ist die Pipeline Steps Reference auf der Jenkins.io Seite, die die Pipeline-kompatiblen Plug-ins auflistet.
Einige dieser speziellen Plugins und ihre Schritte werden in späteren Kapiteln dieses Buches behandelt.
Zusammenfassung
Dieses Kapitel von gibt einen kurzen Überblick darüber, was Jenkins 2 von Jenkins unterscheidet. Es gibt eine Kernunterstützung für Pipelines sowohl als Aufträge selbst als auch separat von Jenkins als Jenkinsfiles. Wenn du deinen Code für eine Pipeline schreibst, kannst du zwischen der traditionellen, flexibleren Scripted Pipeline oder der strukturierteren Declarative Pipeline Syntax wählen.
Jenkins 2 bietet außerdem mehrere neue Projekttypen. Mit dem Ordner-Typ lassen sich Projekte in einem gemeinsamen Namensraum und einer gemeinsamen Umgebung zusammenfassen. Der Typ Multibranch Pipeline ermöglicht die einfache automatisierte Erstellung von Aufträgen pro Zweig und die kontinuierliche Integration, die durch Jenkins-Dateien in den Zweigen ausgelöst werden. Und der Projekttyp Organisation erweitert die Multibranch-Funktionalität auf alle Projekte in einer Organisationsstruktur auf GitHub oder Bitbucket.
Wir haben uns auch einige der Treiber für die Entwicklung vom traditionellen Jenkins-Modell zum Pipeline-zentrierten Modell angesehen. Dazu gehörten das Wachstum der Pipelines als Ganzes sowie die Herausforderungen, mehrere Aufträge in Jenkins zusammenarbeiten zu lassen. Ein weiterer Faktor war die traditionell enge Kopplung der Pipeline-Konfiguration an die Jenkins-Anwendung.
Abschließend haben wir einige Kompatibilitätsfaktoren besprochen, die beim Wechsel von Jenkins 2 zu Jenkins 2 zu beachten sind. Wir werden im Laufe des Buches auf die Besonderheiten verschiedener Anwendungen eingehen, aber wenn du mit den hier dargelegten allgemeinen Ideen vertraut bist, hast du eine gute Grundlage, um diese zu verstehen und dir Gedanken darüber zu machen, was du für die Umstellung deiner bestehenden Pipelines brauchst.
Apropos Grundlagen: In Kapitel 2 behandeln wir die grundlegenden Aspekte der Arbeit mit Pipelines in Jenkins 2. Das wird dir helfen, das Grundwissen zu vervollständigen, das du brauchst, um Pipelines nutzen zu können.
Get Jenkins 2: Auf und davon now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.