wrote ci/cd and selfhosted chapters
parent
9fd01f8861
commit
3b3870887c
|
|
@ -18,9 +18,43 @@
|
|||
\usepackage{hyperref}
|
||||
|
||||
\usepackage{amsmath}
|
||||
\usepackage{xcolor}
|
||||
\usepackage{listings}
|
||||
|
||||
\usepackage{tikz}
|
||||
\usetikzlibrary{positioning,arrows.meta,fit,backgrounds}
|
||||
|
||||
\usepackage{biblatex}
|
||||
|
||||
% Lstlisting-Stil für YAML-Beispiele
|
||||
\definecolor{lstbg}{rgb}{0.97,0.97,0.97}
|
||||
\definecolor{lstkw}{rgb}{0.10,0.30,0.65}
|
||||
\definecolor{lstcm}{rgb}{0.40,0.40,0.40}
|
||||
\lstdefinelanguage{yaml}{
|
||||
keywords={true,false,null},
|
||||
keywordstyle=\color{lstkw}\bfseries,
|
||||
sensitive=false,
|
||||
comment=[l]{\#},
|
||||
commentstyle=\color{lstcm}\itshape,
|
||||
morestring=[b]',
|
||||
morestring=[b]",
|
||||
}
|
||||
\lstset{
|
||||
backgroundcolor=\color{lstbg},
|
||||
basicstyle=\ttfamily\footnotesize,
|
||||
breaklines=true,
|
||||
captionpos=b,
|
||||
frame=single,
|
||||
framesep=4pt,
|
||||
rulecolor=\color{black!20},
|
||||
xleftmargin=4pt,
|
||||
xrightmargin=4pt,
|
||||
showstringspaces=false,
|
||||
}
|
||||
|
||||
% Markierung des Verfassers eines Kapitels (Pflicht laut Profvorgabe)
|
||||
\newcommand{\authornote}[1]{\textit{\small Verfasst von: #1}\par\medskip}
|
||||
|
||||
\graphicspath{ {./bilder/} }
|
||||
|
||||
\geometry{
|
||||
|
|
@ -169,22 +203,189 @@
|
|||
Aufgrund der grösseren Nutzerbasis eignet sich GitHub mehr für eine kollaborative Zusammenarbeit an \ac{OSS}. Ein Projekt erreicht mehr Nutzer, die potenziell beitragen können.
|
||||
|
||||
\section{CI/CD}
|
||||
|
||||
%https://docs.gitlab.com/topics/build_your_application/
|
||||
|
||||
\authornote{Christopher Schmitt}
|
||||
|
||||
Die Begriffe \ac{CI}, \ac{CD} und Continuous Deployment werden in der Literatur nicht einheitlich verwendet. Shahin et al.~\cite{shahin_continuous_2017} grenzen sie folgendermassen ab. \ac{CI} bezeichnet das automatische Übersetzen und Testen jeder Codeänderung gegen den gemeinsamen Hauptzweig. \ac{CD} ergänzt diesen Vorgang um die Eigenschaft, dass jeder geprüfte Stand jederzeit in eine produktionsnahe Umgebung ausgeliefert werden kann. Continuous Deployment automatisiert zusätzlich den letzten Schritt in die produktive Umgebung. GitLab deckt alle drei Stufen mit denselben Bausteinen ab: Runner, Pipelines und Jobs. Gesteuert werden diese zentral über eine einzelne Konfigurationsdatei im Repository \cite{cowell_automating_2023}. Die folgenden Abschnitte beschreiben die drei Bausteine im Einzelnen.
|
||||
|
||||
\subsection{GitLab Runner}
|
||||
|
||||
Die GitLab-Instanz selbst führt keine \ac{CI}/\ac{CD}-Arbeit aus. Diese Aufgabe übernimmt ein separater Hilfsprozess, der \textbf{Runner} \cite{gitlab_gitlab_nodate}. Ein Runner registriert sich einmal mit einem Token bei der Instanz und holt sich danach selbständig offene Aufgaben ab. Durch diese Trennung kann die Ausführung horizontal skaliert werden. Plattformabhängige Aufgaben lassen sich gezielt auf der passenden Hardware ausführen \cite{painter_practical_2024}. Runner können auf drei unterschiedlichen Ebenen registriert werden:
|
||||
\begin{itemize}
|
||||
\item \textbf{Instanz} Auf Instanzebene registrierte Runner stehen allen Projekten der GitLab-Instanz zur Verfügung. Sie werden in der Regel von der Administration bereitgestellt.
|
||||
\item \textbf{Gruppe} Auf Gruppenebene registrierte Runner nehmen Aufgaben aus sämtlichen Projekten innerhalb dieser Gruppe und ihrer Subgruppen an. Eingesetzt werden sie meistens dann, wenn eine Gruppe besondere Anforderungen an Hardware oder Software stellt.
|
||||
\item \textbf{Projekt} Auf Projektebene registrierte Runner sind ausschliesslich an ein einzelnes Projekt gebunden. Diese Variante eignet sich für sensitive Projekte, bei denen kein gemeinsam genutzter Runner verwendet werden soll.
|
||||
\end{itemize}
|
||||
Wie ein Runner eine konkrete Aufgabe ausführt, hängt vom konfigurierten \textbf{Executor} ab. Der Executor entscheidet, in welcher Umgebung das vom Anwender hinterlegte Skript läuft. Tabelle~\ref{tab:executors} listet die in der Praxis am häufigsten verwendeten Executors auf.
|
||||
\begin{table}[H]
|
||||
\centering
|
||||
\caption{Häufig verwendete Executors des GitLab Runners \cite{gitlab_gitlab_nodate}}
|
||||
\label{tab:executors}
|
||||
\resizebox{\columnwidth}{!}{%
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\toprule
|
||||
Executor & Ausführungsumgebung & Typischer Einsatz \\ \midrule
|
||||
\texttt{shell} & direkt auf dem Hostsystem & einfache Setups, Eigenbau-Server \\
|
||||
\texttt{docker} & je Aufgabe ein neuer Container & in der Praxis der Standardfall \\
|
||||
\texttt{docker-machine} & ephemere Cloud-VMs & elastische Skalierung \\
|
||||
\texttt{kubernetes} & ein Pod je Aufgabe & grosse Cluster, Autoskalierung \\
|
||||
\texttt{ssh} & entfernter Host über SSH & Legacy-Systeme \\ \bottomrule
|
||||
\end{tabular}%
|
||||
}
|
||||
\end{table}
|
||||
Die Wahl des Executors hat neben der technischen auch eine organisatorische Dimension. Nach Rostami Mazrae et al.~\cite{rostami_usage_2023} startet der \texttt{shell}-Executor zwar mit minimalem Aufwand, wird in produktiven Umgebungen aufgrund fehlender Isolation aber üblicherweise durch \texttt{docker} oder \texttt{kubernetes} ersetzt. Sicherheitsrisiken entstehen vor allem dann, wenn mehrere Projekte denselben \texttt{shell}-Runner verwenden und ein Skript das Hostsystem dauerhaft verändert.
|
||||
|
||||
\subsection{Pipelines}
|
||||
|
||||
Eine \textbf{Pipeline} ist in GitLab die oberste Ebene der Automatisierung. Sie umfasst sämtliche Schritte, die als Reaktion auf ein Ereignis im Repository ablaufen \cite{gitlab_gitlab_nodate}. Ausgelöst wird eine Pipeline durch unterschiedliche Ereignisse. Dazu gehören ein Push, das Öffnen eines \textbf{Merge Requests}, ein hinterlegter Zeitplan, ein manueller Klick in der Weboberfläche oder das Ende einer anderen Pipeline \cite{cowell_automating_2023}.
|
||||
|
||||
Innerhalb einer Pipeline werden die einzelnen Arbeitsschritte zu sogenannten \textbf{Stages} zusammengefasst. Alle Schritte einer Stage laufen parallel und müssen erfolgreich abgeschlossen sein, bevor die nächste Stage beginnt \cite{gitlab_gitlab_nodate}. Eine in der Praxis verbreitete Reihenfolge der Stages ist \texttt{lint}, \texttt{test}, \texttt{build} und \texttt{deploy}. Abbildung~\ref{fig:pipeline-stages} zeigt das Verhältnis von Pipeline, Stages und Jobs.
|
||||
|
||||
\input{diagrams/pipeline_stages}
|
||||
|
||||
Die gesamte Definition einer Pipeline liegt in einer einzigen Datei. Diese trägt den Namen \texttt{.gitlab-ci.yml} und befindet sich im Wurzelverzeichnis des Repositories \cite{gitlab_gitlab_nodate}. Damit folgt GitLab dem von Humble und Farley~\cite{humble_continuous_2010} eingeführten \textbf{Pipeline-as-Code}-Prinzip. Die Beschreibung des Build- und Auslieferungsprozesses wird wie Anwendungscode versioniert und im Review geprüft. Listing~\ref{lst:gitlabciyml} zeigt einen minimalen Aufbau mit drei Stages.
|
||||
|
||||
\begin{lstlisting}[language=yaml,caption={Minimaler Aufbau einer .gitlab-ci.yml},label={lst:gitlabciyml}]
|
||||
stages:
|
||||
- test
|
||||
- build
|
||||
- deploy
|
||||
|
||||
unit-test:
|
||||
stage: test
|
||||
script:
|
||||
- npm ci
|
||||
- npm test
|
||||
|
||||
build-image:
|
||||
stage: build
|
||||
script:
|
||||
- docker build -t app:$CI_COMMIT_SHA .
|
||||
|
||||
deploy-staging:
|
||||
stage: deploy
|
||||
script:
|
||||
- ssh user@host 'docker pull app'
|
||||
only:
|
||||
- main
|
||||
\end{lstlisting}
|
||||
|
||||
Aus der starren Stage-Reihenfolge kann mit dem Schlüsselwort \texttt{needs} ein gerichteter azyklischer Graph (\acs{DAG}) gemacht werden. Ein Schritt darf dann starten, sobald seine konkret benannten Vorgänger fertig sind. Unnötige Wartezeiten entfallen \cite{cowell_automating_2023}. Wiederkehrende Pipeline-Bausteine können über das Schlüsselwort \texttt{include} aus anderen Repositories nachgeladen werden \cite{gitlab_gitlab_nodate}. Mit den in Abschnitt~\ref{subsec:komponenten} beschriebenen CI/CD-Komponenten existiert seit GitLab 16.0 ein weitergehender Mechanismus zur Wiederverwendung von Pipeline-Logik.
|
||||
|
||||
\subsection{Jobs}
|
||||
\subsection{CICD-Komponenten}
|
||||
|
||||
Die eigentliche Arbeitseinheit innerhalb einer Pipeline ist der \textbf{Job}. Ein Job führt ein vom Anwender festgelegtes Skript in einer isolierten Umgebung aus und ist genau einer Stage zugeordnet \cite{gitlab_gitlab_nodate}. Jobs derselben Stage sind voneinander unabhängig und werden parallel auf den verfügbaren Runnern ausgeführt. Ob die Pipeline weiterläuft, hängt vom Ergebnis sämtlicher Jobs einer Stage ab.
|
||||
|
||||
Mit dem Schlüsselwort \texttt{rules} wird pro Job festgelegt, unter welchen Bedingungen dieser ausgeführt wird. Beispiele sind die Beschränkung auf bestimmte Branches, die Ausführung nur bei Änderungen an bestimmten Dateien oder die Abhängigkeit vom Ergebnis vorheriger Jobs \cite{cowell_automating_2023}. Ein als \texttt{manual} markierter Job läuft erst nach einer expliziten Freigabe über die Weboberfläche. Diese Konstruktion wird häufig für Auslieferungen in produktive Umgebungen genutzt.
|
||||
|
||||
Während ein Job läuft, entstehen häufig Dateien, die spätere Jobs weiterverarbeiten. Beispiele sind ein gebautes Bundle, ein Container-Image oder ein Testbericht. GitLab unterscheidet dafür zwei Mechanismen mit unterschiedlicher Lebensdauer \cite{gitlab_gitlab_nodate}:
|
||||
\begin{itemize}
|
||||
\item \textbf{Artefakte} Artefakte sind benannte Ergebnisse eines Jobs. Sie werden nach dem erfolgreichen Abschluss eines Jobs an die GitLab-Instanz hochgeladen, stehen dort zum Download bereit und werden an spätere Jobs der Pipeline weitergegeben.
|
||||
\item \textbf{Caches} Caches dienen ausschliesslich dazu, wiederholte Ausführungen zu beschleunigen. Typisch ist das Zwischenspeichern heruntergeladener Abhängigkeiten zwischen Pipeline-Läufen. Über Jobgrenzen hinweg ist der Cache nicht garantiert verfügbar.
|
||||
\end{itemize}
|
||||
Das Ziel einer Auslieferung wird durch das Konzept der \textbf{Environments} beschrieben \cite{cowell_automating_2023}. Jedes Environment fasst alle Auslieferungen in eine bestimmte Zielumgebung zusammen. In der Weboberfläche wird zusätzlich protokolliert, welche Version dort gerade läuft. Einen Sonderfall bilden \textbf{Review-Apps}. Für jeden offenen Merge Request erzeugt GitLab automatisch eine isolierte, kurzlebige Auslieferung, in der die geänderte Anwendung vor dem Merge begutachtet werden kann \cite{gitlab_gitlab_nodate}. Nach Rostami Mazrae et al.~\cite{rostami_usage_2023} ist diese direkte Kopplung zwischen Review und laufender Vorschau eines der Merkmale, mit denen sich GitLab von alternativen Plattformen abgrenzt.
|
||||
|
||||
Zampetti et al.~\cite{zampetti_empirical_2020} identifizieren in einer empirischen Untersuchung 79 wiederkehrende Anti-Muster in CI-Konfigurationen. Häufige Probleme sind unnötig sequentielle Stages, zu grobgranulare Jobs und das Vermischen von Cache und Artefakten. Lesbarkeit und Wartbarkeit der Pipeline-Definition sind damit ein eigenes Qualitätskriterium.
|
||||
|
||||
\subsection{CICD-Komponenten}\label{subsec:komponenten}
|
||||
|
||||
Mit dem Schlüsselwort \texttt{include} können bereits seit längerem ganze Pipeline-Fragmente aus anderen Repositories oder von einer entfernten \ac{URL} eingebunden werden \cite{gitlab_gitlab_nodate}. In der Praxis stellen sich dabei zwei wiederkehrende Probleme. Eingebundene Fragmente sind in den meisten Fällen weder versioniert noch besitzen sie eine eigene Schnittstelle. Eine Änderung am Fragment kann sämtliche Pipelines mit einbinden \cite{cowell_automating_2023}.
|
||||
|
||||
Seit GitLab 16.0 lösen \textbf{CI/CD-Komponenten} dieses Problem. Eine Komponente ist ein versionierter und parametrisierbarer Pipeline-Baustein, der ähnlich wie eine Software-Bibliothek verwendet wird \cite{gitlab_gitlab_nodate}. Komponenten werden in einem dedizierten Projekt entwickelt und veröffentlicht. Drei Bestandteile sind dabei zwingend vorgesehen:
|
||||
\begin{itemize}
|
||||
\item \textbf{Manifest} In einer Datei \texttt{template.yml} beschreibt die Komponente ihre Eingabeparameter mit Datentyp und Defaultwert sowie die von ihr beigesteuerten Jobs.
|
||||
\item \textbf{Versionsschild} Komponenten werden ausschliesslich über Git-Tags freigegeben. Ein Konsument referenziert eine Komponente immer mit einer konkreten Version. Damit kann sich der eingebundene Stand nicht unter dem Konsumenten verändern.
|
||||
\item \textbf{Katalogeintrag} Ein Projekt, das den Status \textit{Components Project} erhält, erscheint im zentralen \textbf{Component Catalog} der GitLab-Instanz. Die Suche nach geeigneten Komponenten erfolgt dort, ohne dass Repository-Pfade auswendig bekannt sein müssen.
|
||||
\end{itemize}
|
||||
Listing~\ref{lst:component} zeigt die Einbindung einer beispielhaften Lint-Komponente in eine bestehende Pipeline.
|
||||
|
||||
\begin{lstlisting}[language=yaml,caption={Einbindung einer CI/CD-Komponente},label={lst:component}]
|
||||
include:
|
||||
- component: $CI_SERVER_FQDN/team/lint@1.2.0
|
||||
inputs:
|
||||
stage: lint
|
||||
node-version: '20'
|
||||
|
||||
stages:
|
||||
- lint
|
||||
- test
|
||||
\end{lstlisting}
|
||||
|
||||
Im Gegensatz zum klassischen \texttt{include} besitzt die Komponente damit eine echte Aufrufsignatur. Die Eingabewerte werden vom Aufrufer im Block \texttt{inputs} gesetzt und sind unter dem Präfix \texttt{\$[[ inputs.<name> ]]} innerhalb der Komponente verfügbar \cite{gitlab_gitlab_nodate}. Nach Cowell et al.~\cite{cowell_automating_2023} ist diese Trennung zwischen Schnittstelle und Implementierung der wesentliche Schritt, der Pipeline-Logik in grösseren Organisationen wartbar hält. Die Anti-Muster, die Zampetti et al.~\cite{zampetti_empirical_2020} beschreiben, lassen sich auf diese Weise an einer einzigen Stelle korrigieren, ohne dass sämtliche Pipelines angefasst werden müssen.
|
||||
|
||||
\subsection{Anwendungsbeispiel}
|
||||
|
||||
\section{Selbstgehostete Lösung}
|
||||
Zur praktischen Demonstration der vorhergehenden Konzepte wurde eine kleine Webanwendung auf der in Abschnitt~\ref{sec:selfhosted} beschriebenen selbstgehosteten Instanz aufgesetzt. Die Anwendung ist bewusst minimal gehalten. So liegt der Fokus auf der \ac{CI}/\ac{CD}-Konfiguration und nicht auf dem Anwendungscode.
|
||||
|
||||
Die Demoanwendung ist ein \texttt{HTTP}-Dienst, der in \textbf{Node.js} mit dem Web-Framework \textbf{Express} geschrieben ist. Bereitgestellt wird ein einzelner Endpunkt \texttt{GET /}, der eine kurze HTML-Seite mit der Bezeichnung der aktuellen Umgebung und der im Build verbauten Versionskennung ausliefert. Beide Werte werden zur Laufzeit über Umgebungsvariablen aus dem Container gelesen und im jeweiligen Deploy-Job gesetzt. Eine kleine Testsuite mit dem Framework \texttt{vitest} prüft, dass der Endpunkt eine HTML-Antwort mit Statuscode~200 und der erwarteten Versionsangabe liefert.
|
||||
|
||||
Die zugehörige \texttt{.gitlab-ci.yml} definiert drei Stages: \texttt{lint}, \texttt{test} und \texttt{deploy}. Die Stage \texttt{deploy} enthält dabei zwei Jobs, die sich gegenseitig ausschliessen. Tabelle~\ref{tab:demo-pipeline} fasst zusammen, welcher Schritt unter welchen Bedingungen ausgeführt wird und welches Environment er bedient.
|
||||
\begin{table}[H]
|
||||
\centering
|
||||
\caption{Stages der Demo-Pipeline und ihre Auslöser}
|
||||
\label{tab:demo-pipeline}
|
||||
\resizebox{\columnwidth}{!}{%
|
||||
\begin{tabular}{@{}llll@{}}
|
||||
\toprule
|
||||
Stage / Job & Auslöser & Ergebnis & Environment \\ \midrule
|
||||
\texttt{lint} & jeder Push & Stilbericht & -- \\
|
||||
\texttt{unit-test} & jeder Push & Testbericht & -- \\
|
||||
\texttt{deploy:staging} & alle Branches ausser \texttt{main}, manuell & Container in Staging & \texttt{staging} \\
|
||||
\texttt{deploy:prod} & Push auf \texttt{main}, automatisch & Container in Produktion & \texttt{production} \\ \bottomrule
|
||||
\end{tabular}%
|
||||
}
|
||||
\end{table}
|
||||
Die ersten beiden Stages werden bei jedem Push auf jeden Branch ausgeführt. Sie entsprechen den klassischen \ac{CI}-Schritten nach Duvall et al.~\cite{duvall_continuous_2007} und Fowler~\cite{fowler_continuous_2006} und sollen ein schnelles, automatisches Feedback auf jeden Codestand erzeugen. Die Stage \texttt{deploy} deckt den Continuous-Delivery-Anteil ab. Auf einem Feature-Branch steht der Job \texttt{deploy:staging} als manueller Schritt in der Pipeline-Übersicht bereit. Eine Änderung kann so bei Bedarf in einer laufenden Vorschau begutachtet werden, bevor sie in den Hauptzweig wandert. Ein Push auf \texttt{main} liefert automatisch nach \texttt{production} aus. Nach der Begriffsabgrenzung von Shahin et al.~\cite{shahin_continuous_2017} entspricht der Pfad nach \texttt{main} damit Continuous Deployment, der manuelle Pfad nach Staging klassischem Continuous Delivery.
|
||||
|
||||
Im Rahmen der Live-Präsentation wird der Lebenszyklus einer Codeänderung in drei Schritten gezeigt. Im ersten Schritt wird auf einem Feature-Branch eine sichtbare Änderung am Anwendungscode vorgenommen und in das Repository übertragen. Die Stages \texttt{lint} und \texttt{unit-test} laufen automatisch durch. Im zweiten Schritt wird der Job \texttt{deploy:staging} über die Weboberfläche freigegeben. Die Änderung ist unmittelbar unter der Staging-Adresse sichtbar, ohne dass sie bereits im Hauptzweig liegt. Im dritten Schritt wird der Merge Request gegen \texttt{main} akzeptiert. Eine neue Pipeline auf \texttt{main} durchläuft \texttt{lint} und \texttt{unit-test} und löst anschliessend automatisch \texttt{deploy:prod} aus. Die neue Version ist ohne weiteren manuellen Eingriff in der produktiven Umgebung erreichbar. An diesem Ablauf wird der Übergang von \ac{CI} über \ac{CD} bis Continuous Deployment nach Shahin et al.~\cite{shahin_continuous_2017} an einem laufenden System sichtbar.
|
||||
|
||||
\section{Selbstgehostete Lösung}\label{sec:selfhosted}
|
||||
\authornote{Christopher Schmitt}
|
||||
|
||||
GitLab kann nicht nur als \ac{SaaS} bezogen, sondern auch auf eigener Hardware selbst betrieben werden. Diese Variante wird von GitLab als \textbf{Self-Managed} bezeichnet \cite{gitlab_gitlab_nodate}. Sie kommt hauptsächlich in zwei Fällen zum Einsatz. Entweder erlauben Datenschutz- oder Compliance-Vorgaben nicht, dass Quellcode auf fremden Servern liegt. Oder die \ac{SaaS}-Variante wird mit steigender Nutzerzahl zu teuer. Installation, Konfiguration, Aktualisierungen und Sicherungen müssen dafür allerdings selbst übernommen werden \cite{painter_practical_2024}. Im Folgenden wird beschrieben, wie eine solche Instanz im Rahmen dieser Arbeit auf einem privaten Linux-Server aufgesetzt wurde und welcher Aufwand dabei anfiel.
|
||||
|
||||
\subsection{Installation}
|
||||
|
||||
|
||||
Für die selbstgehostete \ac{CE} bietet GitLab das sogenannte \textbf{Omnibus-Paket} an \cite{painter_practical_2024}. Im Paket enthalten sind sämtliche Komponenten, die GitLab im Betrieb benötigt. Dazu zählen der Webserver \texttt{nginx}, der Anwendungsserver \texttt{Puma}, die relationale Datenbank \texttt{PostgreSQL} und der Schlüssel-Wert-Speicher \texttt{Redis}. Weitere Hintergrundprozesse kommen hinzu \cite{gitlab_gitlab_nodate}. Abbildung~\ref{fig:omnibus-arch} zeigt das Zusammenspiel der einzelnen Bausteine.
|
||||
|
||||
\input{diagrams/omnibus_arch}
|
||||
|
||||
Der wesentliche Vorteil des Omnibus-Paketes ist, dass die einzelnen Komponenten nicht selbst installiert und aufeinander abgestimmt werden müssen. Ein einzelner Aufruf des Paketmanagers genügt. Auf debian-basierten Systemen wird das GitLab-Paketrepository einmalig hinzugefügt und anschliessend \texttt{apt install gitlab-ce} ausgeführt \cite{gitlab_gitlab_nodate}.
|
||||
|
||||
Für diese Arbeit wurde GitLab \ac{CE} auf einem privaten Linux-Server installiert. Als Betriebssystem kam eine aktuelle LTS-Variante von Ubuntu zum Einsatz. GitLab empfiehlt für eine produktive Instanz mit bis zu 20 aktiven Nutzern mindestens vier Kerne und 8\,GiB Arbeitsspeicher \cite{gitlab_gitlab_nodate}. Da die verwendete Hardware diesen Richtwert beim Arbeitsspeicher nicht vollständig erreicht, wurde zusätzlich eine Swap-Datei eingerichtet, um Lastspitzen während des ersten \texttt{reconfigure}-Laufs aufzufangen. Die Installation selbst lief unauffällig. Das Paket wurde heruntergeladen und entpackt. Das mitgelieferte Skript \texttt{gitlab-ctl reconfigure} brachte die Instanz innerhalb weniger Minuten in einen lauffähigen Zustand. Eine erste Anmeldung über die Weboberfläche war direkt möglich.
|
||||
|
||||
Eine Besonderheit des hier beschriebenen Aufbaus betrifft die Erreichbarkeit der Instanz. Anstatt die Instanz über eine öffentliche Domain freizugeben, wird die gesamte Kommunikation über ein privates Overlay-Netzwerk auf VPN-Basis abgewickelt. Der Webserver \texttt{nginx} bindet sich dadurch ausschliesslich an die lokale Schnittstelle. Externe Anfragen aus dem Overlay-Netzwerk werden über einen vorgelagerten Proxy entgegengenommen und auf den lokalen Port weitergereicht. Ein zugehöriges \ac{TLS}-Zertifikat wird vom Overlay-Dienst selbst bereitgestellt. Auf eine direkte Exposition der Ports 80 und 443 zum öffentlichen Internet wird auf diese Weise vollständig verzichtet.
|
||||
|
||||
\subsection{Konfiguration}
|
||||
|
||||
|
||||
Eine Self-Managed-Instanz wird zentral über die Datei \texttt{/etc/gitlab/gitlab.rb} konfiguriert \cite{painter_practical_2024}. Sämtliche Komponenten des Omnibus-Pakets lesen ihre Einstellungen aus dieser Datei. Bei jedem Aufruf von \texttt{gitlab-ctl reconfigure} werden die Komponenten mit dem aktuellen Stand neu initialisiert. Tabelle~\ref{tab:gitlabrb} zeigt eine Auswahl der für den vorliegenden Aufbau relevanten Optionen.
|
||||
\begin{table}[H]
|
||||
\centering
|
||||
\caption{Auswahl an Konfigurationsoptionen aus \texttt{gitlab.rb} \cite{gitlab_gitlab_nodate, painter_practical_2024}}
|
||||
\label{tab:gitlabrb}
|
||||
\resizebox{\columnwidth}{!}{%
|
||||
\begin{tabular}{@{}lll@{}}
|
||||
\toprule
|
||||
Option & Wert & Zweck \\ \midrule
|
||||
\texttt{external\_url} & \texttt{https://<host>} & von aussen sichtbare \ac{URL} \\
|
||||
\texttt{nginx['listen\_addresses']} & \texttt{['127.0.0.1']} & nur lokales Binding \\
|
||||
\texttt{letsencrypt['enable']} & \texttt{false} & kein eigenes Zertifikat \\
|
||||
\texttt{registry['enable']} & \texttt{true/false} & Container Registry \\
|
||||
\texttt{gitlab\_rails['smtp\_*']} & Provider & Versand von Systemmails \\
|
||||
\texttt{puma['worker\_processes']} & \texttt{0--n} & Anzahl Anwendungsprozesse \\
|
||||
\texttt{sidekiq['max\_concurrency']} & \texttt{8--25} & Hintergrundjobs parallel \\
|
||||
\texttt{backup\_keep\_time} & in Sekunden & Aufbewahrungsdauer Backups \\ \bottomrule
|
||||
\end{tabular}%
|
||||
}
|
||||
\end{table}
|
||||
|
||||
Eine geführte Erstkonfiguration, wie sie die \ac{SaaS}-Variante bietet, existiert nicht. Nach der Installation läuft die Instanz zwar, befindet sich aber in einem generischen Standardzustand. Alles Projektspezifische muss selbst zusammengesucht werden. Im hier beschriebenen Aufbau war dies der zeitaufwendigste Teil der Bereitstellung. Die reine Paketinstallation war in unter zehn Minuten abgeschlossen. Das anschliessende Einrichten von Erreichbarkeit, Mailversand, Container Registry und Runnern beanspruchte mehrere Stunden, weil die Optionen in \texttt{gitlab.rb} ohne Vorwissen über die jeweiligen Komponenten schwer einzuordnen sind \cite{painter_practical_2024}.
|
||||
|
||||
\subsection{Betrieb}
|
||||
|
||||
Im laufenden Betrieb wird GitLab über das Kommandozeilenwerkzeug \texttt{gitlab-ctl} gesteuert. Damit lassen sich die Hintergrunddienste starten, stoppen und überwachen \cite{painter_practical_2024}. Aktualisiert wird über den Paketmanager und das von GitLab vorgegebene Versionsschema. Beim Überspringen mehrerer Hauptversionen ist eine bestimmte Reihenfolge zwingend einzuhalten, da die enthaltenen Datenbankmigrationen aufeinander aufbauen. Ein direkter Sprung von einer alten auf eine deutlich neuere Version kann den Datenbestand inkonsistent zurücklassen \cite{gitlab_gitlab_nodate}. Sicherungen werden über den Befehl \texttt{gitlab-backup create} erzeugt und umfassen die \texttt{PostgreSQL}-Datenbank sowie alle Repositories und Artefakte.
|
||||
|
||||
Welche Folgen ein nicht funktionierendes Backup haben kann, zeigt der bereits in Abschnitt~1.3 angesprochene \textit{GitLab.com Database Incident} aus dem Jahr 2017. Durch eine fehlerhafte manuelle Aktion gingen sechs Stunden Nutzerdaten verloren \cite{GitLabcomDatabaseIncident}. Betroffen war zwar die \ac{SaaS}-Instanz, das Beispiel ist aber auch für eine eigene Instanz von Bedeutung. Ein Backup, das nicht regelmässig in einem Restore-Test überprüft wird, ist im Ernstfall kein Backup. Painter~\cite{painter_practical_2024} weist zudem darauf hin, dass die eigentlichen Aufwände bei einer Self-Managed-Instanz nicht in der Erstinstallation, sondern über die Lebensdauer hinweg anfallen. Dazu zählen Sicherheitsaktualisierungen, regelmässige Restore-Tests und die Überwachung der Datenbankkonsistenz.
|
||||
|
||||
\section{Evaluierung}
|
||||
|
||||
\subsection{Vorgehensweise}
|
||||
|
|
@ -300,7 +501,7 @@
|
|||
\section*{Abkürzungsverzeichnis}
|
||||
\begin{acronym}[Abkürzungsverzeichnis]
|
||||
\acro{IDE}{Integrated Development Environment}
|
||||
\acro{CD}{Continous Delivery, kontinuierliche Auslieferung}
|
||||
\acro{CD}{Continuous Delivery, kontinuierliche Auslieferung}
|
||||
\acro{SaaS}{Software as a Service}
|
||||
\acro{CI}{Continuous Integration, kontinuierliche Integration}
|
||||
\acro{NASDAQ}{National Association of Securities Dealers Automated Quotations}
|
||||
|
|
@ -314,6 +515,9 @@
|
|||
\acro{TFVC}{Team Foundation Version Control (TFVC)}
|
||||
\acro{CVS}{Concurrent Versions System}
|
||||
\acro{OSS}{Open Source Software}
|
||||
\acro{TLS}{Transport Layer Security}
|
||||
\acro{DAG}{Directed Acyclic Graph}
|
||||
\acro{URL}{Uniform Resource Locator}
|
||||
\end{acronym}
|
||||
|
||||
\printbibliography
|
||||
|
|
|
|||
Loading…
Reference in New Issue