Raspberry Pi als Jenkins Server – Teil 3
In diesem Praxis-Tutorial zeige ich wie man aus einem unter GitHub gehosteten Projekt eine einfache Build Chain baut die das Projekt lädt, compiliert und einen Test durchführt. Mit diesem Setup kann die Software laufend über Nacht gebaut und getestet werden.
Raspberry Pi als Jenkins Server – Teil 3
Nichts ist langweiliger als das nächste Hello World Beispiel, deshalb zeige ich wie man ein komplexes praxisnahes Jenkings Projekt anlegt. Sollten noch Fragen offen bleiben empfehle ich andere simplere Tutorials oder die Jenkins Dokumentation. Ich werde mir nun ein neues Jenkins Projekt erstellen, welches ein unter GitHub gehostetes Softwareprojekt automatisch auscheckt, danach neu baut und Softwaretests durchführt. Das ist vermutlich die einfachste Form einer DevOps Build Chain. Der Output sollte ein regelmäßig gebautes Programm sein oder im Fehlerfall eine Benachrichtigung an den Jenkins Administrator.
Projekt anlegen
Jenkins bettelt im Dashboard gerade darum endlich mit der Arbeit beginnen zu können, weshalb ich ein neues Projekt anlege. Als erstes Testprojekt habe ich mir mein aktuellstes Projekt von meinem GitHub geschnappt. Ich lege ein Projekt mit dem GitHub Namen als Freestyle Projekt an:
Im nächsten Dialog überspringen wir alle nicht relevanten Felder und geben gleich die clone URL vom Git Repository an. Das sieht in meinem Fall so aus:
Mit einem Klick auf Speichern wird das Projekt angelegt. Bevor weitere Tasks konfiguriert werden will ich das auschecken vom Git Repository testen.
Wichtig zu erwähnen ist, dass die Git relevanten Felder von einem Jenkins Plugin stammen. Das Jenkins Git Plugin ist bei mir offensichtlich installiert. Das bedeutet aber noch nicht, dass ein git clone auch funktioniert, es muss zusätzlich auch Git installiert sein. Ich habe das auf meinem Raspberry Pi kurz getestet:
git --version
Falls du git noch nicht installiert haben solltest, das bekommst du mit:
sudo apt-get install git
Erster Test
Ich führe das soeben angelegte Projekt über den neu hinzugekommenen Menüpunkt „Jetzt bauen“ aus. Das geht überraschend schnell (gemessen an den bisherigen Steps am Raspberry Pi), eine Ausgabe bestätigt, dass der erste Task erfolgreich durchlaufen wurde. Über das Kontextmenü Konsolenausgabe kann man sich näher ansehen was alles gemacht wurde.
Im Detail können wir aus der Konsolenausgabe mehrere Dinge feststellen:
- Jenkins konnte den Task erfolgreich beenden (letzte Zeile: Finished: SUCCESS)
- das Projektverzeichnis für den Task findet man unter /var/lib/jenkins/workspace
- gestartet wurde der Task durch einen Benutzer, genauer gesagt von mir
Unter dem Menüpunkt „Git Build Data“ erhält man weitere Informationen vom Git Plugin zum ausgecheckten Git Repository.
Periodischer Checkout
Aktuell kennt Jenkins den von mir angelegten Task, ich als Benutzer kann diesen manuell ausführen. Das ist noch keine Automatisierung, weshalb ich nun im nächsten Step den Checkout derart automatisiere, dass dieser zumindest einmal täglich ausgeführt wird. Dazu muss die Konfiguration des ersten Projekts geändert werden, auf der Übersichtsseite findet man dazu den Menüpunkt „Konfigurieren“.
Das folgende Formular kennt man schon vom Anlegen des Projekts. Nun kann man sich um die bisher nicht beachteten Punkte kümmern.
Unter Source Code Management System abfragen definiert man eine Ausführungszeit der Abfrage die nahezu identisch dem Crontab von Linux ist. Neu ist das große „H“ welches ich aufgrund eines Warnhinweis von Jenkins hinzugefügt habe. Der kryptisch wirkende Code H(0.10) 4 * * * bedeutet nichts anderes als: führe den Task:
- irgendwann in der Zeitspanne der 0ten bis 10ten Minute
- um 4 Uhr
- jeden Tag, jedes Monat und jeden Wochentag (*) aus
Damit sollte ein täglich aktuelles Programm bereitgestellt werden können und in der Früh weiß ich bereits ob mich eventuell Fehler erwarten die zu einem Abbruch führten.
Achtung: es ist wichtig zu wissen, dass mit dieser Einstellung nicht jeden Tag neu ausgecheckt wird! Das passiert nur, wenn es auch Änderungen gibt. Es wird lediglich täglich um die eingestellte Uhrzeit das lokale Git Repository mit dem remote Git Repository abgeglichen. Konkret wird der Hash Wert des letzten Commits verglichen.
Zum Test habe ich dazu den Cron auf * * * * * gestellt, das heißt das Projekt soll ständig geprüft werden. Parallel dazu habe ich eine kleine Änderung im Git Projekt gemacht und diese auf GitHub gepushed. Wenige Sekunden später wurde der Task unter Jenkins ausgeführt. Das Ergebnis:
Im Gegensatz zum ersten Lauf, den ich manuell durchgeführt hatte, ist nun der Urheber eine SCM-Änderung.
Getriggerter Checkout
So ein Daily-Build ist schon was feines, aber ich möchte nach jeder Änderung am Source Code wissen, ob dieser auch fehlerfrei durchläuft. Ein Cron der ständig durch ein Polling-Verfahren eine externe Quelle abfragt ist aus Ressourcensicht nicht empfehlenswert. In diesem Fall legt man ein so genanntes Webhook am Source Control System an. Dieses Setup würde das Tutorial in der Komplexität sprengen, unter GitHub findet man in den Settings einen Punkt dafür. Wer mehr darüber wissen will findet im Internet Dokumentationen.
Da mein Raspberry Pi aus dem Internet nicht erreichbar ist müsste ich erst ein DynDNS einrichten oder meinen Jenkins Server in die Cloud oder auf meinen Webserver bringen. In jedem fall sieht man schon welche Vorteile man mit der Vernetzung unterschiedlicher Services in der Cloud haben kann, aber auch wie komplex die Abhängigkeiten gleich mal werden, wenn man unterschiedliche Dienste verwendet.
Fazit
In diesem Tutorial habe ich gezeigt wie man den Source Code für ein Projekt automatisch am Jenkins Server auscheckt. In den weiteren Teilen der Tutorialserie werde ich nun automatische Builds und Tests hinzufügen. GitHub und Jenkins stehen nur exemplarisch für die Software die man für Continuous Integration verwenden kann um eine Build Chain zu bauen. Alternativen wie GitLab (das lokal gehostet werden kann) oder Azure DevOps in der Cloud sind nur einige weitere Beispiele die einem Entwickler helfen die Qualität der Software zu steigern.
Teil 1 | Teil 2 | Teil 3 | Teil 4