P

Praktikum III

Zurück zur Veranstaltung

Motivation

Dieses Praktikum dient der Einarbeitung in den Umgang mit CI/CD-Pipelines (hier: GitLab-CI/CD). Dies ist wichtig, um die zu entwickelnde Anwendung stetig zu bauen und möglichst schnell Ergebnisse und Fehler zu erkennen. Da der Deployment-Prozess auch heute noch erfahrungsgemäß eine große Fehlerquelle des Softwareentwicklungsprozesses birgt, sollte dieser möglichst früh angegangen und durchgeführt werden, auch wenn natürlicherweise noch Fehler entstehen. Das Prinzip ist hier: Fail fast. Learn fast.

Vorbereitung

Für die Vorbereitung des Praktikumsversuchs wird mit einem Selbststudienaufwand von 12 Zeitstunden kalkuliert.

  1. Lesen und verstehen Sie was git ist und warum Sie es benutzen sollten:
  2. Arbeiten Sie sich in das Konzept des Git-Flow ein und recherchieren Sie die Unterschiede und Besonderheiten zu den Konzepten des GitHub-Flow und des GitLab-Flow, die für kleinere Entwicklerteams besser geeignet sind:
  3. In diesem Praktikum sollen Sie eine GitLab-Pipeline entwickeln. Dafür sollen Sie sich in die folgenden Dokumentation von GitLab einarbeiten:

Ausgangspunkt

Sie erhalten einen Laborrechner mit einem frisch installierten Ubuntu-Betriebssystem. Installieren Sie die erforderlichen Werkzeuge, die Sie aus dem letzten Praktikum kennen, bei Bedarf nach.

Durchführung

Im Folgenden werden die Arbeitsschritte beschrieben, die Sie durchführen müssen, um das Praktikum erfolgreich zu absolvieren. Hinweise sind anhand der kursiven Schrift zu erkennen.

Erstellen Sie im Wiki des zuvor erstellten GitLab-Projekts ein Laborprotokoll. Notieren Sie hier strukturiert Ihre Arbeitschritte mit kopier- und ausführbaren Kommandozeilenbefehlen in dieser Form:

docker run hello-world

Das Laborprotokoll soll dem Laborpersonal am Ende gemeinsam mit der kurzen Vorführung der Ergebnisse gezeigt werden.

Mittlerweile sollten Sie sicher im Umgang mit dem Terminal und Docker sein.

Schritt 1

Ziel

Erstellung eines GitLab-Projekts und Installation eines GitLab-Runners auf dem Laborrechner, der mit dem erstellten Projekt verknüpft wird. Im Rahmen einer Pipeline müssen verschiedene Programme ausgeführt werden. Diese Programme sollen nicht auf dem GitLab-Server laufen, um Lastprobleme zu vermeiden. Statt dessen wird das GitLab-Projekt mit einem GitLab-Runner verbunden. Der GitLab-Runner wird auf einem anderen Computer (im einfachsten und unseren Fall der Entwicklungsrechner) installiert und steuert von dort die Ausführung der Programme und Skripte der GitLab-Pipeline:

╭────────────────────────────────────────╮     ╭─────────────────────────────────────────────────────────────────╮
│ GitLab-Server                          │     │ Entwicklungsrechner                                             |
├────────────────────────────────────────┤     |╭──────────────────────────────────────╮                         |
| * startet Pipeline-Jobs auf dem Runner |─────>| Gitlab-Runner                        |                         |
| * erhält Ergebnisse vom Runner         |<─────| * wird im GitLab-Projekt registriert |     ╭──────────────────╮|
| * verwaltet Code, Issues und Branches  |     || * führt Pipeline-Skripte aus         |<───>| Pipeline-Skripte ||
╰────────────────────────────────────────╯     || * bricht Ausführung bei Fehlern ab   |     ╰──────────────────╯|
                                               |╰──────────────────────────────────────╯                         |
                                               ╰─────────────────────────────────────────────────────────────────╯

Aufgabe

Erstellen Sie sich im GitLab ein neues Projekt, installieren Sie den GitLab-Runner auf dem Laborrechner und konfigurieren Sie ihn so, dass er Ihrem spezifischen Projekt zugeordnet ist. Notwendige Informationen hierfür erhalten Sie im Bereich Settings > CI/CD Ihres GitLab-Projektes. Wählen Sie den shell-Executor für den Runner aus.

Sofern nur ein Runner verwendet wird, muss kein Tag angegeben werden. Sobald im späteren Verlauf mehrere Runner gebraucht werden, können die Tags der einzelnen Runner noch im GitLab bearbeitet werden.

Sollten Sie eine Fehlermeldung der folgenden Form erhalten:

ERROR: Job failed: prepare environment: Process exited with status 1.

Befolgen Sie beim nächsten mal die in der Aufgabe verlinkten Anleitung und versuchen Sie für diesen Runner diesen Fix.

Schritt 2

Ziel

Neues Issue und Merge-Request im Projekt. Erstellung einer "Hello World!"-Pipeline unter Zuhilfenahme einer zu erstellenden .gitlab-ci.yml im Projekt. Im GitLab-Flow können wir ein Issue, einen Merge-Request und einen Branch so verknüpfen, dass

  • aus dem Issue heraus ein zugehöriger Merge-Request und Branch erstellt werden können und
  • beim Mergen des Merge-Requests das Issue geschlossen und der Branch gelöscht werden.

Dies bildet das Vorgehen bei der Softwareentwicklung so ab, dass es

  • zu jedem Feature ein Issue gibt,
  • Features auf eigenen Branches, sogenannten Feature-Branches, entwickelt werden,
  • Branches nach Fertigstellung und Test in den main-Branch gemerged werden und
  • das Issue nach Fertigstellung der Implementierung geschlossen wird.

Außerdem können wir Pipelines so definieren, dass nach jedem Commit und jedem Merge automatisch Pipeline-Skripte ausgeführt werden, welche

  • aus dem Quellcode die fertige Software erstellen (bauen)
  • die fertige Software testen und
  • die fertige Software auf einen Staging- oder Produktionsserver ausliefern (deployen)

Aufgabe

Legen Sie den folgenden Entwurf als neues Issue in Ihrem GitLab-Projekt an und übernehmen Sie den folgenden Text, der wichtige Entscheidungen und Arbeitsschritte des Issues enthält, in die Kommentaren des aus dem Issue heraus erstellten Merge-Requests:

Erstellen Sie eine erste Pipeline in der GitLab-UI

Erstellen Sie einen ersten Job, der erst Hello, world! in eine Datei schreibt und dann den Inhalt dieser Beispieldatei auf der Kommandozeile ausgibt.
Sehen Sie sich die Ausgaben der Pipeline in GitLab an und notieren Sie sich Besonderheiten in der Ausgabe, insbesondere die, die Rückschlüsse auf das Hostsystem des Runners zulassen.
Überprüfen Sie Ihren Laborrechner anschließend auf die Existenz der Beispieldatei. Hierfür empfiehlt sich ein auffälliger Dateiname, sodass Sie anschließend auf dem System mit Suchwerkzeugen arbeiten können.

Arbeiten Sie das erstellte Issue nach dem Schema des GitLab-Flows ab. Aus Ihrer Vorbereitung für dieses Praktikum sollten Sie wissen, was dies bedeutet. Bearbeiten Sie die weiteren Schritte nach demselben Schema: Issue erstellen, aus dem Issue Merge-Request und Branch erzeugen, auf den Branch wechseln und dort die Aufgabe bearbeiten, nach Abschluss Merge-Request mergen.

Schritt 3

Ziel

Erstellung einer Pipeline mit mehreren Stages und Nutzung von vordefinierten Variablen. Die einfache HelloWorld-Pipeline soll so erweitert werden, dass Sie zwei Stages enthält: Bauen der Software und Deployment. Vorerst entstehen dabei nur Dateien im Filesystem des Entwicklungsrechners (dort, wo der GitLab-Runner läuft). Wir simulieren das Verhalten also erstmal nur anstatt wirklich Quellcode zu übersetzen und auf Server auszuliefern.

Aufgabe

Teilen Sie die Pipeline in eine Build-Stage (Dateiinhalt schreiben) und eine Deploy-Stage (Dateiinhalt ausgeben) ein.

Die Ausgabe des Deploy-Jobs soll nun den Zweignamen enthalten. Im Build-Job soll entsprechend Hello from <branch>! in die Datei geschrieben werden. In der Dokumentation der GitLab-CI/CD werden vordefinierte Variablen erläutert, die Sie hierfür verwenden können. Sollten Sie Probleme durch die Aufteilung in zwei Stages erhalten, schauen Sie Sich die Doku zu Artefakten an.

Bei Erfolg schließen Sie die Arbeit an dem Issue ab.

Schritt 4

Ziel

Die simulierte Pipeline soll jetzt so angepasst werden, dass ein realitätsnäheres Szenario entsteht: Wir nehmen an, dass unser Softwareprojekt eine zentrale index.html enthält, die der Einstiegspunkt für die Benutzung der Software durch die Enduser ist. Die index.html des Softwareprojekts soll nach erfolgreichem Ausführen der Pipeline von einem Nginx-Server, der in einem Docker-Container läuft, ausgeliefert werden. Der Docker-Container läuft auf dem Entwicklungsrechner. Das ist ein zum Entwicklungszeitpunkt übliches Vorgehen. In realen Produktionsumgebungen gibt es weitere Pipelines, welche die Software in Docker-Container installieren, die wiederum auf den Produktivservern laufen. Beachten Sie, dass der Docker-Container nur einmal gestartet wird und durch die Pipeline die erforderlichen Dateien dann ersetzt werden. Der Container wird in unserem Beispiel also nicht durch die Pipeline erzeugt und gestartet.

Als index.html nehmen wir die standardmäßig im Nginx enthaltene Datei. Es wird also keine neue index.html im Projekt angelegt, sondern Sie finden heraus, wo die Dateien des Nginx standardmäßig liegen (s. u.).

Aufgabe

Starten Sie auf dem Laborrechner einen Nginx-Server in einem Docker-Container und prüfen Sie die Netzwerkausgabe. Finden Sie heraus aus welcher Datei die Ausgabe stammt und wie Sie diese manipulieren können. Vermutlich müssen Sie entsprechende Parameter in den Docker-Kommandos nutzen.

Erste wenn der Docker Container läuft und Sie die Konfiguration des Nginx verstanden haben: Ändern Sie die Pipeline so, dass Sie die Beispieldatei aus den vorhergehenden Schritten an eine geeignete Stelle im Container kopieren, wodurch sie vom Nginx als Startseite bereitgestellt wird. Es empfiehlt sich vor der Umsetzung komplexer Pipelines das Vorhaben lokal zu testen, sodass dieses nicht in einer Vielzahl von fehlgeschlagenen Pipelines ausufert.

Erstellen Sie für Ihre Arbeitsschritte ein Issue mit entsprechendem Titel und einer passenden Beschreibung. Arbeiten Sie dieses und alle weiteren Implementierungsschritte ebenfalls nach dem Schema des GitLab-Flow ab und dokumentieren Sie diese.

Sollte Ihre Pipeline aufgrund von Zugriffsrechten fehlschlagen: Bringen Sie in Erfahrung, wie der GitLab-Runner in Ihrem Ubuntu realisiert wird und beachten Sie die Anweisungen aus dem Docker Getting Started Guide

Schritt 5

Ziel

Meistens gibt es nicht nur einen Produktivserver, sondern zusätzlich noch einen Staging- und evtl. weitere Server zum Testen. Auf einem Staging-Server kann die Software unter Produktionsbedingungen ausgeführt werden ohne die Produktionsversion zu verändern. Dies dient dazu, Kunden eine Möglichkeit der Überprüfung und endgültigen Freigabe zur Übernahme in Produktion zu ermöglichen. Dabei können beispielsweise Mitarbeiter des Kunden involviert werden, die nicht Mitglied im Projektteam sind (z. B. Geschäftsleitung).

Es sollen jetzt zwei Nginx-Container auf dem Entwicklungsrechner betrieben werden. Einer enthält die aktuelle Entwicklungsversion, der andere die Staging-Version. Das Deployment auf die beiden Server wird über den Branch gesteuert: wenn es sich um den Branch staging handelt, wird auf Staging deployed, sonst auf Development.

Da alle Server nach wie vor auf derselben Maschine (Entwicklungsrechner) laufen, muss der Zugriff auf die beiden Server über einen Reverse Proxy gesteuert werden um Zugriffskonflikte zu vermeiden. Wir verwenden dafür den Reverse Proxy træfik, der ebenfalls als Docker-Container gestartet wird.

Außerdem sollen die beiden Server über GitLab-Environments ansprechbar sein.

Aufgabe

Ihnen ist beim Befolgen des GitLab-Flow sicherlich aufgefallen, dass sowohl die Pipelines des Main-Branches als auch der Feature-Branches die eine Beispieldatei aus den vorhergehenden Schritten überschreiben. Ändern Sie Ihre Pipeline so ab, dass verschiedene Nginx-Container genutzt werden, die über verschiedene URLs erreichbar und unter Deployments > Environments im GitLab-Projekt einsehbar sind.

Nutzen Sie dafür das gegebene docker-compose.yml File. Hier wird mittels træfik und nip.io eine Umgebung aus zwei verschiedenen Nginx-Containern geschaffen. Für eine Erfolgreiche Bearbeitung der Aufgabe ist ein tieferes Verständnis dieser beiden Dienste nicht zwingend erforderlich. Wir empfehlen aber, dass Sie sich auch mit diesen Diensten auseinandersetzen und versuchen die Funktionsweise nachzuvollziehen.

# docker-compose.yml
version: "3"
services:
  traefik:
    container_name: traefik
    image: traefik:v2.0
    restart: always
    command:
      --api.insecure
      --entrypoints.http.address=:80
      --providers.docker
      --providers.docker.exposedbydefault=false
    network_mode: host
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
  staging:
    container_name: nginx_staging
    image: nginx
    restart: always
    labels:
      traefik.enable: true
      traefik.http.routers.staging.rule: Host(`staging.XXX.XXX.XXX.XXX.nip.io`)
  dev:
    container_name: nginx_dev
    image: nginx
    restart: always
    labels:
      traefik.enable: true
      traefik.http.routers.dev.rule: Host(`dev.XXX.XXX.XXX.XXX.nip.io`)

Ersetzen Sie im oben stehenden Beispiel XXX.XXX.XXX.XXX durch die IP-Adresse des localhost.

Nutzen Sie in Ihrer erweiterten Pipeline die Keywords rules oder only/except.

Sollten Sie keine Verbindung über die Routen herstellen können, beachten sie den Hinweis auf nip.io:

DNS Rebinding Protection

Some DNS resolvers, forwarders and routers have DNS rebinding protection which may result in failure to resolve local and private IP addresses. This service won't work in those situations.

Informieren Sie sich über mögliche Lösungsansätze, für eine FRITZ!Box kann z.B. dieser Workaround funktionieren.

Schritt 6

Ziel

Üblicherweise wird das fertige Softwareprodukt nach dem Bauen (build-Stage) und vor dem Deployment noch getestet. Dies erfolgt in einer eigenen Test-Stage. Wir wollen dies simulieren, indem die index.html des Projekts während der Build-Stage um den Branch-Namen erweitert und anschließend in der neuen Test-Stage mittels html-validate validiert wird.

Aufgabe

Nun sollen noch zusätzliche Tests in die Pipeline eingebaut werden. Erstellen Sie auch hier ein neues Issue und nutzen Sie Git-Flow. In diesem Schritt soll mit html-validate gearbeitet werden. Führen Sie die folgenden Schritte durch:

<p>
  <button>Click me!</button>
  <div id="show-me">
    Lorem ipsum
  </div>
</p>
  • Erweitern Sie Ihre Pipeline um eine Test-Stage und validieren Sie Ihre index.html.
  • Beheben Sie die angezeigten Fehler und ermöglichen Sie somit eine erfolgreiche Pipeline.
  • Ersetzen Sie in der build-stage mittels sed Lorem ipsum in der index.html durch Hello from <branch>!, bei Problemem mit der Variable beachten sie auch diesen Foreneintrag.
  • Liefern Sie Ihre index.html über die vorhandene Staging-Infrastruktur aus.

Abtestat

Demonstrieren Sie dem Laborpersonal einen kompletten Entwicklungszyklus nach dem Schema des GitLab-Flow. Seien Sie bereit, auf Fragen des Laborpersonals ausführlich antworten zu können.

Zurück zur Veranstaltung

Version

v2023a getestet am 18.04.2023