GitLab: Installation und Konfiguration - ein Tutorial
GitLab - ein Werkzeug, so wichtig wie fast nichts anderes. Ich benutze GitLab nun schon seit 2014. Bei der damaligen Installation habe ich einige Fehler gemacht, und mich immer wieder darüber geärgert. 2017 der erste Umzug mit allen Projekte auf einen neuen Server. Oh Du rosige Zukunft. Was mir nicht bewusst war: Die Fehler sind mit umgezogen. 2019 der zweite Umzug. Auf einen neuen Server natürlich. Und die Fehler? ...rate mal....
2021. Das Jahr, das wohl alles in den Schatten stellt und alles von Grund auf ändert. Denn: Die Fehler ziehen nicht mit um. Nein, diesmal soll alles besser werden, die Unzulänglichkeiten von 7 Jahren werden nach dem Umzug einfach hinfort formatiert. Im wahrsten Sinne des Wortes. Aber was genau war passiert, was ist der schlimmste Fehler, den man eigentlich machen kann? Das ist sehr einfach zu beantworten.
Man installiert GitLab nicht auf einem Server auf dem schon was darauf ist. Nein, das macht man wirklich nicht. Jeder der denkt, "Ach, ich hab da noch diese Kiste, da laufen nur ein paar Stagings drauf...", denen sei geraten: LASST ES! Denn spätestens, wenn auf dem Server bereits ein Dienst läuft, auf dem Port 80 und 443 verwendet werden, darf man sich mit dem Thema: "Apache als Reverse Proxy für den GitLab NGINX" befassen. Das klingt am Anfang noch besonders motivierend, aber wenn das Thema Container Registry und andere Nettigkeiten ins Spiel kommen, darf man sich immer wieder mit der Frage beschäftigen: Und welche Ports müssen jetzt wohin? Und für den Docker Login gibt es wohl keine zuverlässige Lösung, diese durch einen Apache zu streamen. Und wer will schon einen blöden Port in seiner GitLab URL.
Vorbereitung: EC2 Instanz
Es gibt im AWS Marketplace bereits fertige Vorlagen zur direkten Nutzung auf einer EC2 Instanz, allerdings sind diese relativ schlecht bewertet. Aus diesem Grund wird die Instanz ein aktuelles CentOS 8 sein, und GitLab wird als normale CE Edition darauf installiert und konfiguriert. Für eine normale TYPO3 Agency wird auch nicht gleich die c5.xlarge Instanz benötigt, welche aktuell mit über $ 120 zu Buche schlägt, sondern für den normalen Gebrauch als Repository, Registry und Ticketsystem / Service Desk reicht schon alles ab der Instanz t3a.medium, welche ich für diesen Artikel verwende. Die Merkmale dieser Instanz sollten wie folgt sein:
- Instanz-Typ: t3a.medium und aufwärts
- Amazon AMI: CentOS 8 (x86_64)- with Updates HVM (Link)
- Volume: GP3 mit 20 GiB oder mehr nach Belieben
- Sicherheitsgruppe:
- SSH, Port 22 auf eigene IP
- HTTP, Port 80 von überall
- HTTPS, Port 443 von überall
Als Nächstes wird eine feste IP-Adresse für die Instanz benötigt. Dazu lege ich eine IP-Adresse aus dem AWS Pool mit Elastic-IP an. Diese IP-Adresse wird dann der Instanz zugewiesen. Nun können die A-Records erstellt werden:
- gitlab.example.com > soeben erstellte IP-Adresse
- registry.gitlab.example.com > soeben erstellte IP-Adresse
Im Folgenden wird nun der Server vorbereitet und die benötigte Software installiert
Vorbereitung: Server einrichten
Tatsächlich wird gar nicht so viel benötigt, um GitLab ans Laufen zu bekommen. Erst mal steht der Connect auf den Server an:
$ ssh -A centos@gitlab.example.com
Update des Servers:
$ sudo dnf update
Anschließend werden benötigte Pakete installiert:
$ sudo dnf install -y git curl policycoreutils openssh-server perl
Für den GitLab Runner, welcher Docker Images lädt, wird noch Docker installiert:
$ sudo yum-config-manager \
--add-repo \
download.docker.com/linux/centos/docker-ce.repo
$ sudo dnf install docker-ce docker-ce-cli containerd.io
Dienst aktivieren:
$ sudo systemctl enable docker
und starten:
$ sudo service docker start
GitLab Installation durchführen
Auch die Installation von GitLab selbst ist mit ein paar wenigen Schritten erledigt. Ich verzichte hier auf zusätzliche Serverpakete wie Postfix oder Apache, da der Mailversand über den AWS SES von Amazon geleitet wird, und GitLab für alle Dienste NGINX als Webserver mitbringt, und der da auch perfekt konfiguriert ist.
Installieren des GitLab CE Repos:
$ curl packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash
Damit das SSL Zertifikat gleich erstellt wird, wird der Hostname des Servers vor der Installation via EXPORT gesetzt und erst dann installiert:
$ sudo EXTERNAL_URL="https://gitlab.example.com" dnf install -y gitlab-ce
Nach der Installation erscheint dann die Meldung, dass GitLab installiert und konfiguriert wurde:
gitlab Reconfigured!
*. *.
*** ***
***** *****
.****** *******
******** ********
,,,,,,,,,***********,,,,,,,,,
,,,,,,,,,,,*********,,,,,,,,,,,
.,,,,,,,,,,,*******,,,,,,,,,,,,
,,,,,,,,,*****,,,,,,,,,.
,,,,,,,****,,,,,,
.,,,***,,,,
,*,.
_______ __ __ __
/ ____(_) /_/ / ____ _/ /_
/ / __/ / __/ / / __ `/ __ \
/ /_/ / / /_/ /___/ /_/ / /_/ /
\____/_/\__/_____/\__,_/_.___/
Thank you for installing GitLab!
GitLab should be available at gitlab.example.com
For a comprehensive list of configuration options please see the Omnibus GitLab readme
gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md
Help us improve the installation experience, let us know how we did with a 1 minute survey:
gitlab.fra1.qualtrics.com/jfe/form/SV_6kVqZANThUQ1bZb
Überprüfung läuft : gitlab-ce-13.12.3-ce.0.el8.x86_64 1/1
Installiert:
gitlab-ce-13.12.3-ce.0.el8.x86_64
Fertig.
Erster Log-In und Admin Account
AWS SES: SMTP Service für den Versand von E-Mails
Die Konfiguration für den SMTP Dienst wird in /etc/gitlab/gitlab.rb
erledigt. Dort wird im Bereich der "Gitlab email server settings
" folgende Konfigration hinterlegt:
gitlab_rails['smtp_domain'] = "example.com"
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "email-smtp.eu-central-1.amazonaws.com"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "IAM_USERNAME"
gitlab_rails['smtp_password'] = "IAM_PASSWORD"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['gitlab_email_enabled'] = true
gitlab_rails['gitlab_email_from'] = 'gitlab@example.com'
gitlab_rails['gitlab_email_display_name'] = 'Gitlab on example.com'
gitlab_rails['gitlab_email_reply_to'] = 'gitlab@example.com'
gitlab_rails['gitlab_email_subject_suffix'] = 'Gitlab notify'
Nach dem einfügen und speichern der Datei wird ein "reconfigure" ausgeführt:
sudo gitlab-ctl reconfigure
Testen, ob E-Mails versendet werden, geht nur über die Konsole, im Admin Bereich gibt es leider keine Möglichkeit. Die Konsole wird wie folgt gestartet:
sudo gitlab-rails console
Test E-Mail versenden:
Notify.test_email('eddi.doe@example.com', 'Message Subject', 'Message Body').deliver_now
Wird die Mail versendet, sollte die Konsole wie folgt aussehen:
$ sudo gitlab-rails console
--------------------------------------------------------------------------------
Ruby: ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-linux]
GitLab: 13.12.3 (757327a59bc) FOSS
GitLab Shell: 13.18.0
PostgreSQL: 12.6
--------------------------------------------------------------------------------
Loading production environment (Rails 6.0.3.6)
irb(main):001:0> Notify.test_email('eddi.doe@example.com', 'Message Subject', 'Message Body').deliver_now
Notify#test_email: processed outbound mail in 1.2ms
Delivered mail 60c60b9b39bf5_16e265a28967cc@ip-172-31-9-223.eu-central-1.compute.internal.mail (342.1ms)
Date: Sun, 13 Jun 2021 13:43:55 +0000
From: GitLab <gitlab@gitlab.example.com>
Reply-To: GitLab <noreply@gitlab.example.com>
To: eddi.doe@example.com
Message-ID: <60c60b9b39bf5_16e265a28967cc@ip-172-31-9-223.eu-central-1.compute.internal.mail>
Subject: Message Subject
Mime-Version: 1.0
Content-Type: text/html;
charset=UTF-8
Content-Transfer-Encoding: 7bit
Auto-Submitted: auto-generated
X-Auto-Response-Suppress: All
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p>Message Body</p></body></html>
=> #<Mail::Message:197560, Multipart: false, Headers: <Date: Sun, 13 Jun 2021 13:43:55 +0000>, <From: GitLab <gitlab@gitlab.example.com>>, <Reply-To: GitLab <noreply@gitlab@example.com>>, <To: eedi.doe@example.com>, <Message-ID: <60c60b9b39bf5_16e265a28967cc@ip-172-31-9-223.eu-central-1.compute.internal.mail>>, <Subject: Message Subject>, <Mime-Version: 1.0>, <Content-Type: text/html; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>, <Auto-Submitted: auto-generated>, <X-Auto-Response-Suppress: All>>
irb(main):002:0>
Eingehende E-Mails: Sub-Addressing für Issues
Ein anderes interessantes Thema sind die eingehenden Mails auf den GitLab Server. Wird dem GitLab ein Postfach zugewiesen, dass Sub-Addressing kann, können auf Tickets, die der GitLab versendet, geantwortet werden. Die Antworten werden automatisch an das Ticket als Kommentar angehängt. Viele Dienste unterstützen das Sub-Addressing, unter anderem Gmail, Google Apps, Yahoo! Mail, Outlook.com und iCloud. Der vermutlich wichtigste unterstützt per Default nicht: Microsoft Exchange Server. Aber auch da gibt es eine Möglichkeit, über die PowerShell kann das Feature für Exchange aktiviert werden. Um die E-Mails in GitLab empfangen zu können, wird der Exchange Server via Microsoft Graph abgefragt. Eine Anleitung zur Einrichtung dazu findet sich auf gitlab.com.
GitLab Runner: Docker-Images für GitLab CI nutzen
Das nächste Feature ist das Einrichten eines Gitlab Runner. Der GitLab Runner in diesem Artikel ist vom Typ Docker. Damit lassen sich von Dockerhub Images laden und für die Pipeline nutzen, um Beispielsweise Code zu testen, Frontend Builds laufen zu lassen oder um Deployments durchzuführen. Der Vorteil des Docker Executors gegenüber dem Shell Executor ist deutlich: Auf dem GitLab Host muss nichts installiert werden, was in der Pipeline eventuell benötigt wird. Runner erstelle ich in der Regel immer Gruppenbezogen. Um einen Runner einrichten zu können, muss gitlab-runner zunächst installiert werden:
#
$ curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | sudo bash
#
$ sudo dnf install gitlab-runner
#
$ sudo gitlab-runner start
Container Registry: Ein eigenes Dockerhub via GitLab
Gerade wenn Projekte eigene Docker Images benötigen, oder die GitLab Pipeline auf ein eigenes Image aufbaut, ergibt es Sinn, eine eigene Container-Registry zu nutzen. GitLab stellt dafür entsprechende Funktionen bereit. Am einfachsten ist die Konfiguration, wenn die Registry unter einer eigenen Domain läuft. In diesem Fall wird die Registry unter registry.gitlab.example.com veröffentlicht. Dazu ist eine kleine Konfiguration in /etc/gitlab/gitlab.rb
nötig, und zwar im Bereich der "Container registry settings":
registry_external_url 'https://registry.gitlab.example.com'
Danach ein reconfigure des GitLab:
sudo gitlab-ctl reconfigure
Damit jetzt ein Docker Image in die Registry des Projekts kann, hier ein einfaches Dockerfile für einen ersten Test:
FROM centos:8
RUN dnf install -y dnf-utils rpms.remirepo.net/enterprise/remi-release-8.rpm
RUN dnf module reset php
RUN dnf module enable php:remi-7.4 -y
RUN dnf module reset nodejs
RUN dnf module enable nodejs:14 -y
RUN dnf install -y openssh-clients php php-gd php-xml php-mbstring php-curl php-zip wget unzip git gcc-c++ make nodejs rsync libxml2
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php composer-setup.php --install-dir=/usr/local/bin --filename=composer
Das docker Image wird mit folgendem Befehl gebaut (Den Befehl gibt es in GitLab unter "Packages & Registries" > "Container Registry"):
$ docker build -t registry.gitlab.example.com/test/test .
Ist das Image gebaut, kann es in das Registry geladen werden. Zuerst anmelden via SSH:
# manfredrutschmann @ MacPro in ~/ddev/gitlab.example.com on git:master x [20:09:01] C:1
$ docker login registry.gitlab.example.com
Username: root
Password:
Login Succeeded
Danach das Image pushen:
# manfredrutschmann @ MacPro in ~/ddev/gitlab.example.com on git:master x [20:10:41]
$ docker push registry.gitlab.example.com/test/test
Using default tag: latest
The push refers to repository [registry.gitlab.example.com/test/test]
2fc28a350b93: Pushed
3ca5ad08d39d: Pushed
3cb2ac62d60b: Pushed
53ed9eaa6d25: Pushed
b95224d44e7c: Pushed
b3c655eca3c0: Pushed
f729d633f733: Pushed
9845aa05ad48: Pushed
2653d992f4ef: Pushed
latest: digest: sha256:d29e59de6c62229de2cb32b58a116e534d1e941bc6b74ed3a26ae54d2a9a0186 size: 2218
Package Registry: Ein eigenes Packagist via GitLab
Oftmals werden in mehreren Projekten dieselben Pakete benötigt, sie sollen aber privat bleiben, da sie Projektbezogen sind. Man könnte via Composer nun mit VCS Repositories oder Git Submodulen arbeiten, allerdings finde ich beide Varianten nicht sehr schön. Mit der Package Registry lassen sich aber Composer Pakete taggen und über den eigenen GitLab Server wieder in Projekte einbinden, ähnlich wie das mittels Require von Packagist gemacht wird. Das ist dann natürlich besonders praktikabel. Für meine Projekte bezieht sich das in der Regel auf TYPO3 Extensions.
Bevor es losgehen kann, wird im Projekt ein entsprechender Shell Runner registriert, da das Erstellen des Package beim Commit mit einem GitLab Runner via gitlab.ci.yaml durchgeführt wird:
$ sudo gitlab-runner register --url gitlab.example.com --registration-token sbfWSkQowTTwMNuorRnN
Enter the GitLab instance URL (for example, gitlab.com/):
[https://gitlab.example.com/]:
Enter the registration token:
[sbfWSkQowTTwMNuorRnN]:
Enter a description for the runner:
[ip-172-31-9-223.eu-central-1.compute.internal]: package-registry
Enter tags for the runner (comma-separated):
Registering runner... succeeded runner=sbfWSkQo
Enter an executor: custom, docker, docker-ssh, shell, docker+machine, docker-ssh+machine, kubernetes, parallels, ssh, virtualbox:
shell
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
Der Runner Executor ist diesmal "Shell".
Damit das Image gebaut wird, wird das Package in ein eigenes Projekt gepusht. Dabei wird die folgende CI Yaml verwendet:
# This file is a template, and might need editing before it works on your project.
# Publishes a tag/branch to Composer Packages of the current project
publish:
image: curlimages/curl:latest
stage: build
variables:
URL: "$CI_SERVER_PROTOCOL://$CI_SERVER_HOST:$CI_SERVER_PORT/api/v4/projects/$CI_PROJECT_ID/packages/composer?job_token=$CI_JOB_TOKEN"
script:
- version=$([[ -z "$CI_COMMIT_TAG" ]] && echo "branch=$CI_COMMIT_REF_NAME" || echo "tag=$CI_COMMIT_TAG")
- insecure=$([ "$CI_SERVER_PROTOCOL" = "http" ] && echo "--insecure" || echo "")
- response=$(curl -s -w "\n%{http_code}" $insecure --data $version $URL)
- code=$(echo "$response" | tail -n 1)
- body=$(echo "$response" | head -n 1)
# Output state information
- if [ $code -eq 201 ]; then
echo "Package created - Code $code - $body";
else
echo "Could not create package - Code $code - $body";
exit 1;
fi