5.2. Projekt¶
Automatisierung des Sphinx Bericht Deployment auf dem RZ-Webserver
5.2.1. Ist-Zustand¶
Bisher lief die Bereitstellung des HTML-Berichts so ab, dass nachdem alle ihre Commits gepusht hatten, ein manuelles Kopieren auf den Webserver notwendig war.
Falls ein Commit vergessen wurde, musste dies erneut vorgenommen werden. Um diesen wiederkehrenden Vorgang zu beschleinigen erstellten wir in der Vergangenheit bereits mit Abgabe 2 ein Skript mit dem Namen deploy-html.bat
.
@echo off
set tmpdir="%temp%\dva-deploy"
set "rootDir=%cd%"
set rzuser=julwie21
echo Cleanup temp dir
mkdir %tmpdir%
rmdir /S /Q %tmpdir%
mkdir %tmpdir%
echo make dir browsable
echo Options +Indexes > %tmpdir%\.htaccess
call make.bat html
if exist "%rootDir%\build\html\index.html" (
xcopy "%rootDir%\build\html\" "%tmpdir%" /E /I /Y
) else (
echo ERROR: index.html not found
exit /b 1
)
)
dir "%tmpdir%"
echo RZ-User: %rzuser%
ssh %rzuser%@login.rz.hs-augsburg.de rm -rf /www/%rzuser%/dva/
scp -r %tmpdir%* %rzuser%@login.rz.hs-augsburg.de:/www/%rzuser%/dva/
REM show result
timeout /t 5
start https://tha.de/~julwie21/dva/
Dieses Skript legt den Build-Output in einem temporären Ordner ab. Initial wird das Verzeichnis neu angelegt. Vor dem Building wird, um das Verzeichnis dva (https://tha.de/~julwie21/dva/) später verfügbar zu machen, eine Konfigurationsdatei .htaccess
anlegt und die entsprechenden Optionen, wie vom RZ angegeben (https://www.tha.de/Rechenzentrum/Eigene-Homepage.html), hinterlegt.
Nun wird das Build Skript von Sphinx ausgeführt. Um zu überprüfen, ob es funktioniert hat, wird überprüft, ob die Datei index.html
existiert.
Ist diese Datei vorhanden, wird das Kopieren in das temporäre Verzeichnis vorgenommen bevor der Upload durchgeführt werden kann.
Beim Upload ist zunächst nur eine Authentifizierung mit Passwort hinterlegt.
Zu guter Letzt wird die Webseite im Browser geöffnet, sodass man nochmals von Hand überprüfen kann, ob alles geklappt hat.
Im weiteren Berichtsverlauf wird noch gezeigt wie die passwortlose Authentifizierung per SSH zum Upload genutzt wird. Auch im Remote-Zielverzeichnis findet vor dem Upload eine Bereinigung des vorhandenen Verzeichnisses statt.
Da immer wieder sinnvolle Ergänzungen oder Korrekturen für den Bericht gefunden wurden, häuften sich allerdings auch die manuellen Ausführungen dieses Skripts.
5.2.2. RZ-Authentifizierung¶
Bei den ersten Überlegungen, die wir anstellten um das Deployment zu automatisieren, galt es zunächst eine passwortlose Authentifizierung einzurichten. Daher erstellten wir einen SSH-Key für den verwendeten RZ-Benutzer und erlaubten mittels Konfigurationsdatei im Home-Verzeichnis an login.rz.hs-augsburg.de einen Verbindungsaufbau mit diesem.
Wir beobachteten allerdings, dass nach einigen Stunden die Gültigkeit des SSH-Keys erloschen ist und keine weitere Anmeldung mehr möglich war. Nach weiteren Versuchen der Fehlerbehebung stellten wir fest, dass nach einer erneuten Passwort-Authentifierung der SSH-Key wieder für einige Stunden gültig war.
Da wir auch nach ausführlicher Recherche das Problem nicht lösen konnten, wandten wir uns an den RZ-Service. Dieser teilte uns freundlich mit, dass für die Anmeldung mittels SSH-Key ein gültiges Kerberos-Ticket vom LDAP Domain Controller benötigt wird. Dieses wird unglücklicherweise nur nach erfolgreicher Passwort-Authentifierung erstellt. Lösen könne man dies jedoch indem man den Public-Key im LDAP des RZ hinterlegt.
5.2.3. Beseitung Sicherheitsproblem (Dienstkonto)¶
Eine Authentifizierung mit Passwort kam aus Sicherheitsgründen auf keinen Fall in Frage, da mit dem RZ-Konto sensible Dienste wie z.B. die Prüfungsanmeldung oder Hochschul E-Mail Adresse verknüpft sind und ein Passwort für die Pipeline in Gitlab gespeichert werden müsste. Auch das Hinterlegen des SSH-Keys eines persönlichen RZ-Benutzers in der Pipeline stellt ein Sicherheitsrisiko für das persönliche RZ-Konto dar, da man mit dem Zugriff auf den Private-Key, der für die Verarbeitung genauso erforderlich ist und den man durch einfache Manipulation der Pipeline erlangen könnte, auch weitere Rechte verwundbar macht.
Durch das minimale Ändern des Codes in der Pipeline .gitlab-ci.yml
wäre es bereits möglich mithilfe des cat
-Befehls diese sensiblen Informationen auszulesen.
Daher mussten wir uns für die Pipeline eine andere Lösung einfallen lassen.
Letztendlich beantragten wir einen Benutzer beim RZ, da wir mit dem Support ohnehin schon in Kontakt standen. Über das Portal des Rechenzentrums (https://idm.hs-augsburg.de/gui/request/) war die Erstellung schnell erledigt und die Freischaltung seitens RZ fand innerhalb eines Tages statt.
Zudem ist es Best Practice ein Dienstkonto für Dienste wie diesen und allem möglichen Erdenklichen zu nutzen. Eine persönliche Kennung sollte niemals zur Ausführung eines Dienstes genutzt werden! Eine Sperrung des Kontos aufgrund mehrfacher falscher Passworteingabe, hätte einen Stillstand der Dienstausführung zur Folge.
Für diesen Benutzer konnten wir nun ohne Sicherheitsbedenken ein SSH-Key Paar für den Benutzer dvagrp07 erstellen. Der Public-Key wurde, wie vom RZ vorgeschlagen dem LDAP bekannt gemacht.
5.2.4. Runner Konfiguration¶
Für die Ausführung der Pipeline wird ein sogenannter Runner benötigt. Hierzu ließen wir uns im Vorfeld vom RZ einen Linux Server mit zwei Cores und vier GB RAM bereitstellen. Für unsere Zwecke ist dies mehr als ausreichend. Als Betriebssystem setzten wir Ubuntu 22.04 ein.
Bgzl. des Runners entschieden wir uns für einen Specific Runner des Executor-Typen Shell. Dieser bietet die maximale Flexibiltät. Die direkte Installation des Runner auf dem Server ohne Docker ist zwar möglich. Allerdings wollten wir auf die Portabilität und Einfachheit eines Docker-Containers sowie auch auf die Möglichkeit einen defekten Runner schnell neu bereitstellen zu können, nicht verzichten. Daher installierten wir zunächst Docker auf unserem Server und den Runner innerhalb eines Containers.
Zwei sehr populäre Distributionen des Runners stammen von Gitlab selbst gitlab/gitlab-runner
und von Bitnami bitnami/gitlab-runner
.
Der Gitlab Runner von Bitnami ist allerdings deutlich schlanker (ca. 300 MB) als der Gitlab Runner direkt von Gitlab (ca. 550 MB) und reicht für unsere Zwecke völlig aus. Daher setzten wir diesen ein.
Zudem mussten wir am Runner selbst einige Anpassungen mittels eines Dockerfile
vornehmen:
FROM bitnami/gitlab-runner:latest
USER root
# make the '/gitlab-runner' folder the current working directory
WORKDIR /gitlab-runner
#####################Install Sphinx##################################################
#Documentation: https://docs.docker.com/engine/install/debian/#install-using-the-repository
RUN apt-get update
RUN apt-get install nano -y
RUN apt-get install python3-sphinx -y
#Prevent problems with fingerprint prompt in ssh
RUN echo " StrictHostKeyChecking no" >> /etc/ssh/ssh_config
#Docker commands to finish image
COPY "gitlab-runner_entrypoint.bash" "gitlab-runner_entrypoint.bash"
RUN chmod +x /gitlab-runner/gitlab-runner_entrypoint.bash
ENTRYPOINT ["/bin/bash","/gitlab-runner/gitlab-runner_entrypoint.bash"]
Alle Kommandos sollen als root ausgeführt werden. Damit der Runner das Building der HTML Dateien erledigen kann, muss im Dockerfile
die Installation von Sphinx durchgeführt werden.
Um zu verhindern, dass eine Abfrage aufkommt, ob wirklich eine Verbindung hergestellt werden soll, die manuell bestätigt werden müsste, haben wir SSH auf dem Runner entsprechend konfiguriert, dass die known_hosts
ignoriert wird. Die Abfrage würde folgendermaßen aussehen:

Damit sich der Runner nach einmaliger Registrierung bei jedem Start automatisch bei Gitlab meldet, mussten wir den Entrypoint mit dem Skript gitlab-runner_entrypoint.bash
anpassen und dieses ausführbar machen.
Die gitlab-runner_entrypoint.bash
sieht wie folgt aus:
#!/bin/bash
if ! [[gitlab-runner status | grep "Token=$RUNNER_TOKEN" ]]; then #register runner if not already registered
gitlab-runner register --non-interactive --url https://gitlab.informatik.hs-augsburg.de --token "$RUNNER_TOKEN" --executor "$RUNNER_EXECUTOR"
fi
gitlab-runner run #Make gitlab-runner service available to receive jobs
Es muss überprüft werden, ob dem Runner bereits ein Runner-Token eingetragen wurde. Ist dies nicht der Fall, wird versucht ihn zu registrieren.
Falls die Registrierung schon durchgeführt wurde, wird lediglich der run
-Befehl ausgeführt und der Runner ist bereit die Pipeline zu verarbeiten.
Zur Bereitstellung des Runners nutzten wir eine docker-compose.yml
Datei:
version: "3"
services:
runner01:
container_name: runner01
image: prak-dva/gitlab-runner
restart: ${GLOBAL_RESTART_POLICY}
stdin_open: true #docker run -i
tty: true #docker run -t
build:
context: .
dockerfile: Dockerfile
environment:
RUNNER_TOKEN: ${RUNNER_TOKEN_1}
RUNNER_EXECUTOR: ${RUNNER_EXECUTOR_1}
volumes:
- type: bind
source: /DVA
target: /DVA
read_only: true
Die Variablen werden über eine .env
Datei mit der RESTART_POLICY: always
und den Runner spezifischen Variablen gesetzt.
Sowohl Public- als auch Private-key wurden in einem vorherigen Abschnitt auf den Ubuntu Host kopiert um eine Authentifizierung an login.rz.hs-augsburg.de zu ermöglichen. Zur Anmeldung am login.rz.hs-augsburg.de ist der SSH-Key allerdings nicht auf dem Host sondern im Runner vonnöten.
Daher bindeten wir das Verzeichnis in dem die SSH-Keys vorliegen mittels binding mount am Runner an. Der Zugriff beschränkt sich allerdings auf readonly, da wir ein versehentliches Löschen verhindern wollen und Schreibrechte ohnehin nicht vonnöten sind.
5.2.5. Runner Registrierung¶
Vor der endgültigen Bereitstellung des Containers auf dem Ubuntu Host muss man den Runner noch über die Gitlab Weboberfläche registrieren, den Runner-Token in die .env
eintragen und dann erst Docker Compose ausführen. Diese Möglichkeit findet man in den CI/CD Settings des Repositories unter Runners:

Wie man in der Abbildung sehen kann, haben wir, wie bereits festgelegt, den Tag Shell
und die Reservierung ausschließlich für unser Projekt eingestellt.
Zur einfachen Wiederverwendbarkeit für weitere Projekte fassten wir die allgemein notwendigen Schritte in einer README.md
zusammen.
5.2.6. Pipeline Konfiguration¶
Unsere produktive .gitlab-ci.yml
sieht folgendermaßen aus:
stages:
- build
- test
- deploy
- cleanup
variables:
BUILD_DIR: .
KEY: "/DVA/id_rsa_tha_dvagrp07"
build:
stage: build
script:
- cd ${BUILD_DIR}
- ls -la ${BUILD_DIR}
- bash -c "sphinx-build -M html ./source ./build -W --keep-going" > sphinx-build.log
- ls -la ./build
- echo Options +Indexes > ./build/html/.htaccess
artifacts:
paths:
- build/
- sphinx-build.log
allow_failure: true #Gitlab will return a warning on error
tags:
- shell
test:
stage: test
script:
- echo Test fails if a warning occurred in log file
- cat sphinx-build.log | grep -v " WARNING"
dependencies:
- build
tags:
- shell
deploy___tha.de/~dvagrp07:
stage: deploy
script:
- ssh dvagrp07@login.rz.hs-augsburg.de -i ${KEY} cd /www/dvagrp07; rm -rf /www/dvagrp07/*
- cd ${BUILD_DIR}
- scp -r -i ${KEY} ./build/html/* dvagrp07@login.rz.hs-augsburg.de:/www/dvagrp07/
- echo "Check result on https://tha.de/~dvagrp07"
dependencies:
- build
only:
- main
tags:
- shell
cleanup:
stage: cleanup
script:
- cd ${BUILD_DIR}
- rm -rf ./build
- rm -rf sphinx-build.log
dependencies:
- build
rules:
- when: always
tags:
- shell
Wir unterteilen in vier Stages build
, test
, deploy
und cleanup
.
Alle Stages sind mit dem Tag shell
gekennzeichnet. Dies muss vom Runner unterstützt werden.
Der Pfad zum SSH-Key sowie das Build Verzeichnis werden in einer global zugänglichen Variable gespeichert.
In Stage build
ist neben dem Build Kommando auch ein Abschnitt artifacts
untergebracht. Dies benennt alle Dateien und Ordner, die über weitere Stages hinweg beibehalten werden sollen.
Der Wert allow_failure
ermöglicht die Pipeline (u. a. für das Cleanup) bei Fehlern nicht abzubrechen.
In der test
Stage wird geprüft, ob Warnungen enthalten sind. Dies kennzeichnet Probleme beim Building. Werden Warnungen gefunden, wird die Pipeline abgebrochen.
Wird der Test erfolgreich durchlaufen, wird in der deploy
Stage deployt.
Hierzu werden die alten Dateien auf dem Webserver gelöscht. Anschließend erfolgt die Übertragung der neuen Dateien aus dem Build.
Abschließend wird in der cleanup
Stage eine Bereinigung durchgeführt: Das Build Verzeichnis und die Logdatei werden gelöscht.
Die Bereinigung des Verzeichnisses behielten wir wie beim Skript aus Ist-Zustand bei, da bei einem fehlerhaften Build ein manuelles Eingreifen erforderlich wäre und die komplette Neuerstellung des Builds im Rahmen dieses Studienfachs maximal wenige Sekunden dauern wird.
Mit fast allen Funktionen könnte man die Pipeline auch in einer Stage darstellen.
In einer älteren Version sah die Konfigurationsdatei folgendermaßen aus:
stages:
- deploy_production
variables:
COMPOSE_DIR: .
KEY: "/DVA/id_rsa_tha_dvagrp07"
deploy___tha.de/~dvagrp07:
stage: deploy_production
script:
- cd ${COMPOSE_DIR}
- ls -la ${COMPOSE_DIR}
- sphinx-build -M html ./source ./build -W --keep-going
- ls -la ./build
- echo Options +Indexes > ./build/html/.htaccess
- ssh dvagrp07@login.rz.hs-augsburg.de -i ${KEY} rm -rf /www/dvagrp07/*
- scp -r -i ${KEY} ./build/html/* dvagrp07@login.rz.hs-augsburg.de:/www/dvagrp07/
- rm -R ./build
- echo "Check result on https://tha.de/~dvagrp07"
only:
- main
tags:
- shell
Zum weiteren Betrieb haben wir uns allerdings für die Implementierung mit mehreren Stages entschieden.
Die Unterteilung in mehrere Stages ist zudem leichter zu verstehen.
5.2.7. Weiterleitung des alten Links¶
Die Bereitstellung neuer Versionen des Berichts ist nun automatisiert. Allerdings ist der alte Link http://www.tha.de/~julwie21/dva jetzt nicht mehr gültig. Daher erstellten wir eine HTML Datei mit einem Redirect auf die neue URL unter diesem Benutzer.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="5;url=https://tha.de/~dvagrp07">
<title>Weiterleitung...</title>
</head>
<body>
<p>Dieser Inhalt wurde verschoben zu <a href="https://tha.de/~dvagrp07">https://tha.de/~dvagrp07</a>. Wenn Sie nicht automatisch weitergeleitet werden, <a href="https://tha.de/~dvagrp07">klicken Sie hier</a>.</p>
</body>
</html>
Hierbei weisen wir nochmal daraufhin, dass der Inhalt verschoben wurde und verlinken zusätzlich auf der Webseite sichtbar. Nach 5 Sekunden wird automatisch auf die neue Webseite weitergeleitet.
Einschränkung: Diese Vorgehensweise leitet Links, die zu Unterordnern führen, beispielsweise https://tha.de/~julwie21/dva/abgabe3/projekt.html#emulation-x86-linux-auf-arm leider nicht weiter. Hier liefert der Webserver zurück, dass die Datei nicht gefunden wurde (Fehler 404). Da der Webserver vom RZ verwaltet wird, ist es uns leider nicht möglich die Routen entsprechend anzupassen.