4. CI/CD mit GitLab CI

4.1. Einführung

In diesem Kapitel beschäftigen wir uns mit CI/CD Pipelines. Um diese zu demonstrieren verwenden wir die Pipelines in GitLab. CI/CD steht für Continuous Integration, Continuous Delivery und ist ein essentieller Bestandteil von moderner Softwareentwicklung. Die Pipelines automatisieren den Build-, Test- und Deploymentprozess und erlauben essomit einem Team die Software schneller und Zuverlässiger auszuliefern.

CI/CD-Pipelines bestehen aus einer Reihe von Arbeitsschritten, die nacheinander ausgeführt werden, um frühzeitig Probleme im Entwicklungszyklus zu erkennen und zu beheben, die Softwarequalität sicherzustellen und die Software effizient bereitzustellen. Die Jobs können automatisch aufgrund von Codeänderungen wie Commits oder Merges oder zeitgesteuert ausgeführt werden.

GitLab ist eine webbasierte DevOps-Plattform, die robuste CI/CD-Funktionen anbietet. Die wichtigsten Funktionen sind:

  • GitLab Runner: GitLab Runner sind Prozesse, die Pipelinejobs ausführen können. Da GitLab nicht wie GitHub diese out of the box anbietet, müssen diese selbst, entweder auf dem eigenen Rechner oder auf einem Server, installiert werden. Sie sind für alle Hauptplattformen verfügbar.

  • GitLab YAML-Konfiguration: CI/CD-Pipelines in GitLab werden mithilfe einer deklarativen Konfigurationsdatei namens „.gitlab-ci.yml“ definiert. Diese Datei beschreibt die Stufen, Jobs und Schritte der Pipeline und kann gemeinsam mit dem Code in Git verwaltet werden.

  • Jobs und Stages: Eine Pipeline besteht aus mehreren Stufen, von denen jede einen oder mehrere Jobs enthält. Jobs definieren die auszuführenden Aufgaben, wie z. B. den Build der Anwendung, das Ausführen von Tests oder die Bereitstellung in einer bestimmten Umgebung.

  • Trigger und Abhängigkeiten: Jobs können durch verschiedene Ereignisse ausgelöst werden, wie z. B. Code-Commits, Merge-Anfragen oder zeitgesteuerte Intervalle. Abhängigkeiten zwischen Jobs können definiert werden, um komplexe Arbeitsabläufe zu erstellen.

  • Artefakte: CI/CD-Pipelines können während der Ausführung der Pipeline Artefakte generieren. Diese Dateien wie Binärdateien, Testberichte oder Dokumentationen können gespeichert und für weitere Verwendung oder Überprüfung verwendet werden.

Die Verwendung von Pipelines hat viele Vorteile. Zum einen kann durch sie die Codequalität stark verbessert werden, da Linter, die den Code auf Code conventions überprüfen, eine einheitliche Struktur in der kompletten Codebase vorschreiben.
Zum anderen kann dadurch eine schnellere Time-to-Market erzielt werden, da sie zeitaufwändige Aufgaben vereinfachen. Sie konnen im Laufe des Projekts erweitert und an die speziellen Anforderungen angepasst werden.

4.2. Vorbereitungen

1. GitLab Runner URL und Registrierungstoken

Die GitLab Runner URL und den Registrierungstoken finden wir in der GitLab-Benutzeroberfläche in unserem Repository unter Settings > CI/CI > Runners.

_images/gitlabrunner1.png

2. GitLab Runner installieren

https://docs.gitlab.com/runner/install/

Wir haben den Runner als Docker Container auf einem von der Hochschule für ein anderes Projekt bereitgestellten Ubuntu Server gestartet. Den Container haben wir mittels einer Docker Compose Konfiguration definiert.

docker-compose.yml

version: "3.6"
services:
    gitlab-runner:
        image: gitlab/gitlab-runner
        container_name: gitlab-runner
        restart: always
        volumes:
        - /var/run/docker.sock:/var/run/docker.sock
        - gitlab-runner-config:/etc/gitlab-runner
volumes:
    gitlab-runner-config:

Docker Container starten:

docker-compose up -d

3. GitLab Runner registrieren

  1. Auf Konsole des Gitlab Runner verbinden:

    docker exec -it gitlab-runner bash
    
  2. Runner registrierung starten:

    gitlab-runner register
    
  3. Url der GitLab-Instanz eingeben:

  4. Registrierungs Token eingeben:

    GR1348941r2vXXXXXXXXYJtddaBJ9

  5. Beschreibung für den Runner eingeben. Kann später in der GitLab-Benutzeroberfläche geändert werden:

    bifa-runner

  6. Tags des Runners getrennt duch Kommas eingeben. Können später in der GitLab-Benutzeroberfläche geändert werden:

    docker

  7. Optionalen Wartungshinweis eingeben:

    leer

  8. Ausführungsprogramm des Runners eintragen. Für die meisten Anwendungsfälle Docker:

    docker

  9. Wenn Docker als Ausführungsprogramm gewählt wurde, muss ein Standard Docker Image angegeben werden:

    ubuntu:jammy

Der erfolgreich erstellte Runner erscheint unter Settings > CI/CI > Runners:

_images/gitlabrunner2.png

4. GitLab CI/CD Variablen konfigurieren

Da wir zur Bereitstellung unseres Projekts eine FTP Verbindung benötigen, haben wir aus Sicherheitsgründen die FTP Zugangsdaten als CI/CD Variablen eingerichtet, um diese sensiblen Daten nicht als Klartext im Code zu haben. Diese können wir in der GitLab-Benutzeroberfläche in unserem Repository unter Settings > CI/CI > Variables einrichten.

_images/gitlabrunner3.png

4.3. Kernkonzepte & Komponenten

1. Continuous Integration:

Continuous Integration bezieht sich auf den Prozess, in dem Entwickler ihre Codeänderungen regelmäßig in ein gemeinsames Repository integrieren, um sicherzustellen, dass der Code immer funktioniert und dass Probleme frühzeitig erkannt werden. Dieser Prozess beinhaltet die Verwendung von automatisierten Tests und Build-Tools.

_images/ci.png

2. Continuous Delivery:

Continuous Delivery geht einen Schritt weiter als Continuous Integration und bezieht sich darauf, dass der Code in einem automatisierten Prozess von der Entwicklungsumgebung bis zur Produktion ausgerollt wird. Dadurch wird gewährleistet, dass der Code ständig auf seine Funktionalität und Qualität getestet wird und dass Probleme schnell behoben werden können.

_images/cd.png

3. Automatisierung:

Durch die Automatisierung von Build-, Test- und Bereitstellungsprozessen wird die Entwicklungszeit verkürzt und die Fehlerwahrscheinlichkeit minimiert. Dadurch können Unternehmen schneller auf Marktbedingungen reagieren und Innovationen schneller einführen.

4. Zusammenarbeit:

CI/CD fördert die Zusammenarbeit zwischen Entwicklern, Testern und Betriebsteams. Durch den Einsatz von gemeinsamen Tools und Prozessen können alle Beteiligten an einem Projekt effektiver zusammenarbeiten und die Qualität und Geschwindigkeit der Softwareentwicklung erhöhen.

5. Kontinuierliches Feedback:

Ein weiteres wichtiges Konzept von CI/CD ist das kontinuierliche Feedback. Durch die Integration von Feedback-Mechanismen in den Entwicklungsprozess können Entwickler und Tester schnell auf Probleme reagieren und den Code verbessern. Dadurch wird die Qualität und Zuverlässigkeit der Software erhöht.

4.4. Versuchsdurchführung

Für den Aufbau der CI/CD Pipeline wurde die Datei .gitlab-ci.yml im Root des Git-Repositories erstellt. Diese hat den folgenden Inhalt, der in diesem Kapitel genauer beschrieben wird:

 1stages:
 2  - build
 3  - deploy
 4
 5default:
 6  tags:
 7    - docker
 8
 9build:
10  image: python:3.9.16-bullseye 
11  stage: build
12  script:
13    - echo "Building the html page.."
14    - cd docs
15    - pip3 install -r requirements.txt
16    - make html
17    - echo "Successfully build documentation."
18  artifacts:
19    expire_in: "1 day"
20    paths:
21      - docs/build/html
22
23deploy:
24  image: alpine:latest
25  stage: deploy
26  only:
27    - main
28  variables:
29    GIT_STRATEGY: none
30  dependencies:
31    - build
32  script:
33    - echo "Deploy docs to server.."
34    - apk add lftp
35    - lftp -c "set ftp:ssl-force true; set ssl:verify-certificate false; open -u $FTP_USERNAME,$FTP_PASSWORD $FTP_HOSTNAME; mirror -Renv ./docs/build/html/ ./"
36    - echo "Successfully deployed docs."

Im ersten Absatz werden die einzelnen Stages der Pipeline beschrieben. In unserem Fall gibt es einen Build-Step und einen Deploy-Step. Wenn zusätzlich noch Tests durchgeführt werden sollen, kann beispielsweise noch eine Test-Stage hinzugefügt werden.

1stages:
2  - build
3  - deploy

Im nächsten Abschnitt werden Standardwerte angegeben, die für jeden Job angewendet werden. In diese Fall wurde der Tag docker gesetzt, damit der konfigurierte Runner alle Jobs verarbeitet.

1default:
2  tags:
3    - docker

Der erste Job ist der Build-Job, der die HTML-Dateien aus der Sphinx-Dokumentation generieren soll. Dafür wurde das Image python:3.9.16-bullseye gewählt, das schon einen Python-Interpreter installiert hat. Der Job wird dann noch der Stage build hinzugefügt. In Zeile 5-9 werden dann Schritt-für-Schritt die Befehle angegeben, die vom Runner ausgeführt werden sollen. Nach erfolgreichem Abschluss sollen dann die HTML-Dateien als Artifakt abgelegt werden. Diese können dann von der nächsten Stage weiterverarbeitet werden.

 1build:
 2  image: python:3.9.16-bullseye 
 3  stage: build
 4  script:
 5    - echo "Building the html page.."
 6    - cd docs
 7    - pip3 install -r requirements.txt
 8    - make html
 9    - echo "Successfully build documentation."
10  artifacts:
11    expire_in: "1 day"
12    paths:
13      - docs/build/html

Der nächste Job soll die vorher generierten HTML-Dateien nehmen und sie per FTP auf einem Server ablegen. Hierzu wird ein anderes Image verwendet, das alpine:latest, das im Grunde ein sehr kleines Linux beinhaltet und dadurch sehr schnell gestartet werden kann. Dieser Step soll nur auf dem main-Branch ausgeführt werden (Zeile 4-5) und ist vom vorher definierten build-Job abhängig (Zeile 8-9). Außerdem wird in diesem Schritt der Source-Code nicht benötigt und muss daher nicht geclonet werden, wodurch man sich wiederum Zeit sparen kann (Zeile 6-7). In den letzten 4 Zeilen wird wiederum die genaue Ausführung der Befehle definiert, um das Programm lftp zu installieren und die HTML-Dateien auf den FTP-Server zu kopieren.

 1deploy:
 2  image: alpine:latest
 3  stage: deploy
 4  only:
 5    - main
 6  variables:
 7    GIT_STRATEGY: none
 8  dependencies:
 9    - build
10  script:
11    - echo "Deploy docs to server.."
12    - apk add lftp
13    - lftp -c "set ftp:ssl-force true; set ssl:verify-certificate false; open -u $FTP_USERNAME,$FTP_PASSWORD $FTP_HOSTNAME; mirror -Renv ./docs/build/html/ ./"
14    - echo "Successfully deployed docs."

4.5. Fazit

Abschließend kann man sagen, dass CI/CD Pipelines eine entscheidene Rolle in modernen Softwareprojekten spielen und aus diesen nicht mehr wegzudenken sind. Sie automatisieren den Build-, Test- und Deploymentprozess und nehmen so zeitaufwändige, sich stetig wiederholende Aufgaben ab. Mit den verschiedenen Stages, in der Tools zur Codeüberwachung eingesetzt werden können, wird die Codequalität stets hoch gehalten und die Software verbessert. Durch die Verwendung von Pipelines wird eine zentrale Plattform für die Zusammenarbeit von Entwicklern, Testern und anderen Stakeholdern bereitgestellt. Dadurch wird Transparenz und Struktur geschaffen, da der Status der Pipeline eingesehen, Änderungen nachverfolgt und Probleme diskutiert werden können. Insgesamt vereinfacht es die Erstellung von hochwertigen Softwareprojekten und sollte immer zum Einsatz kommen.

4.6. Literaturangaben

Informationen:

https://docs.gitlab.com/ee/ci/

https://www.redhat.com/de/topics/devops/what-is-ci-cd

Bilder: