Continuous Delivery mit Jenkins und GitLab CI

Bei Continuous Delivery (CD) handelt es sich um einen Auslieferungsprozess von Software. CD hilft dabei, qualitativ hochwertige Software zu erstellen

In diesem Prozess existieren verschiedene Phasen zu unterschiedlichen Zeitpunkten in der Entwicklung, welche zur Steigerung der Qualität beitragen. Im Folgenden wird auf die Umsetzung von CD auf der Grundlage eines Jenkins Build Servers und eines GitLab Systems eingegangen.

Continuous Delivery mit Jenkins und GitLab CI

Das Prinzip von CD

Hierbei müssen Software-Teile, welche entwickelt werden, verschiedenste Validierungen bestehen, um letzten Endes veröffentlicht zu werden. In diesem Fall spricht man von einer Pipeline: Diese definiert, unter welcher Bedingung welche Validierung geprüft wird, um entsprechende Software-Teile zu veröffentlichen. Dabei spielen die Code-Versionierung und damit verbundene Techniken wie Branching eine wichtige Rolle bei CD.

Generelles Setup und Branching-Modell

Im Folgenden wird ein rudimentäres Setup entwickelt, das sowohl mit der Technologie Jenkins als auch GitLab umgesetzt wird. Dieses Setup kann als Grundlage dienen und ist beliebig auf die Anforderungen eines konkreten Projektes anpassbar sowie erweiterbar. Der Code liegt unter https://github.com/diva-e/continuous-delivery.

Für die Entwicklung einer Software wird als Versionierungssystem GIT eingesetzt. Zudem verfolgt man den Branching-Ansatz. Dabei unterscheiden wir zwischen drei unterschiedlichen Branch-Typen:

  1. Master Branch

  2. Develop Branch

  3. Feature Brach

Kurz gefasst bedeutet dies, dass der Master Branch all jene Code-Teile der Software beinhaltet, die für die Erstellung der Software für ihren Einsatzzweck beim Endnutzer verwendet werden. Der Master Branch wird aus den Code-Teilen des Develop Branches zu einem bestimmten Zeitpunkt aktualisiert.

Der Develop Branch beinhaltet Code-Teile, die für den internen Einsatzzweck zur Entwicklungszeit dienen. Der Develop Branch wird aus den Code-Teilen bzw. Features des Feature Branches aktualisiert.

Der Feature Branch beinhaltet Code-Teile, die für ein konkretes Feature stehen, das gerade entwickelt wird.

Die Abbildung zeigt die erwähnten Branches im Kontext des Jenkins Pipeline-Plugins.

Betrachten wir die unterschiedlichen Branch-Typen, so scheint, es sei ausreichend, die Validierung auf dem Master Branch und somit der finalen Software durchzuführen, die auch für den Endnutzer gedacht ist. Diese Aussage ist zunächst korrekt und der Schritt sollte auch unbedingt durchgeführt werden. Allerdings passiert diese Validierung recht spät und kurz vor der Freigabe der Software. Sollte an dieser Stelle ein Fehler erkannt werden, ist das Beheben des Fehler relativ aufwendig, da beispielsweise erst das Feature identifiziert werden muss und dann ein Bugfix angewandt wird. Im schlimmsten Fall ist die Behebung des Fehlers erst in einer späteren Version der Software möglich.

Angenommen, wir schaffen es, die Validierung in einer früheren Phase der Software durchzuführen. Dadurch könnten wir den Fehler beheben, noch bevor dieser auf dem Master Branch ankommt.

An dieser Stelle profitiert man von einem CD Setup bei der Entwicklung von Software: Hier haben wir die Möglichkeit zu definieren, dass in der Phase der Entwicklung eines Features auf einem Feature Branches Tests und somit die Validierung der Code-Teile durchgeführt werden, was dem Entwickler die Möglichkeit bietet, den Fehler direkt bei der Entwicklung des Features zu beheben.

Dieser Ansatz lässt sich im Bezug auf die Validierung genau so auf den Develop Branch oder Master Branch übertragen.

Zudem haben wir die Möglichkeit, in einer Phase des CD auch anderweitige Aktionen durchzuführen, auf die aber in diesem Teil des Beitrags nicht näher eingegangen wird. Im Folgenden betrachten wir die Umsetzung für den Jenkins Build Server und die GitLab Versionskontrolle.

Das Jenkins Setup

Für das CD Setup ist eine vorhandene Jenkins-Installation mit installiertem Pipeline-Plugin erforderlich.

Für die Konfiguration des Plugins ist abgesehen von der Source Konfiguration vor allem die Build Configuration wichtig. Hier definiert man, dass in den Sources ein Jenkinsfile vorhanden ist, das für die Konfiguration des Jenkins- und des Pipeline-Plugins verwendet wird.

In den Sources liegt ein funktionsfähiges Jenkinsfile in der Wurzel des Projekts mit folgendem Inhalt, das die Konfiguration der Pipeline mit ihren Phasen definiert:

pipeline {
   agent any
   stages {
       stage('Build') {
           steps {
               echo 'Building ...'
               sh 'mvn clean compile'
           }
       }
       stage('Test') {
           steps {
               echo 'Testing ...'
               sh 'mvn verify'
           }
           post {
               success {
                   echo 'Test success :)'
               }
               failure {
                   echo 'Test failure :('
               }
           }
       }
       stage('Deploy') {
           when {
               anyOf {
                   branch 'master'
                   branch 'develop'
               }
           }
           steps {
               echo 'Deploying ...'
               sh 'mvn deploy -Dmaven.test.skip=true'
           }
       }
   }
   options {
       buildDiscarder(logRotator(numToKeepStr: '3'))
   }
}


In der gegebenen Konfiguration sind drei Stages zu finden: „Build“, „Test“ und „Deploy“. Die Aktionen der einzelnen Stages sind in ihren Schritten einfach gehalten, erfüllen im Beispiel aber ihren Zweck.

So wird in der Stage „Build” das Projekt mittels eines Shell- und Maven-Befehls gebaut. Ist diese Stage erfolgreich, wird die nächste Stage angestoßen.

In der Stage „Test” werden die Tests des Projekt ausgeführt. Hier lässt sich auf das Ergebnis der Tests reagieren. Im Fehlerfall könnte eine E-Mail-Benachrichtigung an den Entwickler gesendet werden, damit dieser schnellstmöglich seinen Fehler korrigiert.

Die im Beispiel letzte Stage „Deploy” wird ausschließlich ausgeführt, wenn sich die Code-Änderung auf dem Develop Branch oder Master Branch identifizieren lässt. Das bedeutet, dass auf Feature Branches ausschließlich das Projekt gebaut und getestet wird.

Zudem existiert im Jenkinsfile die Möglichkeit, unter „options” das Jenkins Pipeline Plugin zu konfigurieren. In diesem kurzen Beispiel wurde konfiguriert, dass maximal drei Builds auf dem Jenkins in der Historie zur Verfügung stehen.

Das Jenkins Pipeline-Plugin bietet natürlich noch mehr Möglichkeiten als die in diesem Beispiel beschriebenen. Hierzu lohnt sich ein Blick in die Dokumentation, die unter https://jenkins.io/doc/book/pipeline/syntax/ zu finden ist.

Das GitLab Setup

Das für den Jenkins beschriebene Setup für CD wird im Folgenden für GitLab beschrieben. Analog zum Jenkinsfile gibt es die Datei .gitlab-ci.yml, welche auch in der Wurzel des Projekts parallel zum Jenkinsfile zu hinterlegen ist:

stages:
- build
- test
- deploy

Build:
 stage: build
 tags:
   - docker
 script:
   - mvn clean compile

Test:
 stage: test
 tags:
   - docker
 script:
   - mvn test

Deploy:
 stage: deploy
 tags:
   - docker
 only:
   - develop
   - master
 script:
   - mvn deploy -Dmaven.test.skip=true


Auch hier verwenden wir wieder die drei bekannten Stages mit den identischen Aktionen. Die weiterführenden Möglichkeiten der Konfiguration können der GitLab CI Dokumentation https://docs.gitlab.com/ee/ci/yaml/ entnommen werden.

Zudem versehen wir jede Stage mit einem Tag, über das zur Ausführung der Runner referenziert wird. Wie ein Runner konfiguriert und integriert wird, ist nicht Teil dieser Beschreibung und kann der Dokumentation https://docs.gitlab.com/ee/ci/docker/using_docker_build.html entnommen werden.

Die Abbildung zeigt beispielhaft die Verarbeitung und Ausführung der Pipelines auf den jeweiligen Branches.

Bewertung

Betrachtet man die Möglichkeiten, welche die CD-Umsetzung mit Jenkins und GitLab bietet, sollte heutzutage in Projekten auf eine der beiden Lösungen gesetzt werden. Die Konfiguration ist einfach und schnell durchgeführt, außerdem hat man die Konfiguration des Build Setups unter Versionskontrolle. Beide Technologien bieten hierbei ähnliche Möglichkeiten zur Konfiguration und sind ebenbürtig. Betrachtet man den Aspekt der Wartbarkeit, so ist GitLab im Vorteil: Hier entfällt ein zusätzliches System (der Build Server Jenkins), um das man sich kümmern muss, da der Build Server direkt mitgeliefert wird. Ein Stück weit muss man diese Aussage allerdings relativieren, denn beim GitLab Ansatz sind zusätzlich Runner für die Ausführung notwendig, die ggf. auch gewartet werden müssen. Allerdings bieten diese Runner auch Vorteile, was die Skalierbarkeit angeht.

Durch die Einführung eines solchen oder ähnlichen Setups für CD erhält man frühzeitig Feedback über die Änderungen und somit die Qualität des Codes. Ein Branching-Konzept und die damit verknüpfte CD Automatisierung sorgen dafür, dass Code-Änderungen einen definierten Prozess durchlaufen und ihre Ergebnisse entsprechend auf den Systemen zur Verfügung stehen. Dadurch hat man im Projekt die Möglichkeit, Features zu testen und in den entsprechenden Phasen der Entwicklung abzunehmen und zu bewerten. Dies wiederum trägt zu einer qualitativ hochwertigeren und schnelleren Entwicklung von Features und Software bei.