Ich möchte lokal einen Buildserver einrichten um Features zu testen und einen Buildprozess zu entwickeln. Basieren soll dies alles auf docker bzw. docker-compose unter Linux und Windows. Nach der Installation sollen fertige Beispielprojekte eingerichtet sein. Das Versionsverwaltungssystem soll gitlab sein. Dies ist etwas aufwendig nur für einen git Server, aber ich wollte sowieso mit gitlab spielen. Der Buildserver wird Jenkins. Das erste Projekt soll ein buildpipeline Projekt sein, was per maven einen Java 16 Projekt mit einem Junit5 Testfall ausführt. Im Laufe der Zeit sollen weitere Beispiele dazu kommen.
Einrichtung Gitlab
Ziel ist es gitlab fertig eingerichtet mit einem Beispielprojekt zu starten. Unter Windows muss berücksichtigt werden, dass Verzeichnisse mit voller Berechtigung in den docker container gemountet werden. Bei der Installation der ssh keys gibt es dann aber einen Fehler da die Berechtigungen zu großzügig sind. Deswegen darf unter Windows /var/opt/gitlab nicht direkt auf ein Verzeichnis gemountet werden. Unter Linux ist das natürlich möglich.
volumes:
- git-volume:/var/opt/gitlab
...
volumes:
git-volume:
Das initiale Passwort kann über eine Umgebungsvariable gesetzt werden
environment:
GITLAB_OMNIBUS_CONFIG: |
gitlab_rails['initial_root_password'] = "password";
Zusammen ergibt das eine docker-compose.yml Datei mit folgenden Inhalt:
version: "3.3"
services:
gitlab:
image: 'gitlab/gitlab-ce:13.8.5-ce.0'
container_name: gitlab
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://localhost';
gitlab_rails['initial_root_password'] = "password";
ports:
- '80:80'
- '443:443'
- '22:22'
volumes:
- ./data/gitlab/config:/etc/gitlab
- ./data/gitlab/logs:/var/log/gitlab
- git-volume:/var/opt/gitlab
volumes:
git-volume:
Damit wird ein gitlab gestartet und hat bereits ein initiales Passwort gesetzt.
Beispielprojekt in git anlegen
Nun ist aber noch kein Beispielprojekt erstellt. Dies habe ich in einem eigenen Docker Container umgesetzt. Dieser wird gestartet und wartet darauf, dass der git Container über http erreichbar ist und erstellt falls noch nicht vorhanden ein git Projekt. Dazu wird ein dockerfile erstellt in dem der git client und wget installiert wird.
FROM ubuntu:20.04
RUN apt update
RUN apt install -y git wget
Da gitlab ohne ssh keys eingerichtet ist müssen Benutzername und Passwort in eine credentials Datei gespeichert. Diese wird beim ausführen des Containers gefüllt.
RUN git config --global credential.helper 'store --file /work/.git-credentials'
Im Container sind drei Skripte enthalten. start.sh, wait-for-git.sh und create-project.sh
Skript start.sh
Überprüft alle Umgebungsvariablen und erstellt für jeden Ordner in files/projects/ (im Container /git/) ein git Projekt. Dieser Ordner könnte auch als Volume eingebunden werden um beliebige Projekte zu erstellen. Hier werden aber die Projekte mit dem Image mitgeliefert.
for project in *; do
echo "Create git project ${project} on ${HOSTNAME} if needed"
PATH_TO_PROJECT="${GIT_PROJECT_DIR}/${project}"
/usr/bin/wait-for-git.sh ${HOSTNAME} ${GIT_USER} ${project} && echo "Project ${project} already created" || /usr/bin/create-project.sh ${HOSTNAME} ${GIT_USER} ${project} ${PATH_TO_PROJECT}
done
Skript wait-for-git.sh
Wartet bis der gitserver über http erreichbar ist und keinen Fehler meldet. Danach wird geprüft ob das Projekt bereits existiert. Wenn ja wird 0 zurück gegeben.
until wget --quiet http://${HOSTNAME} -O /dev/null
do
echo "git server http://${HOSTNAME} is not online"
sleep 5
done
git ls-remote http://${HOSTNAME}/${GIT_PATH}/${PROJECT}.git master > /dev/null 2>&1
Skript create-project.sh
Initialisiert ein git Projekt, erstellt eine Readme.md und commited und pushed ein Projekt zum git server.
git init
echo "${PROJECT}" > Readme.md
git add *
git commit -m "initial commit"
git push --set-upstream http://${HOSTNAME}/${GIT_PATH}/${PROJECT}.git master
Aufruf in docker-compose.yml
Der Container kann einfach als Service mit aufgenommen werden:
create-git-examples:
build:
context: ./git-example-projects
container_name: git-example-projects
environment:
GIT_HOST: gitlab
GIT_USER: root
GIT_PASSWORD: password
Jenkins einrichten
Aufgabe ist es automatisch die benötigten Plugins, Jenkins Konfiguration und Jobs zu erstellen. Dazu habe ich einen eigenes Docker image erstellt welches vom offiziellen jenkins image erbt. Für die Installation von Plugins kann das Kommandozeilen Programm jenkins-plugin-cli verwendet werden. Die Konfiguration von Jenkins übernimmt das Plugin configuration-as-code welches dann über eine .yml Datei gesteuert werden kann. Die Jobs sind einfach nur die config.xml Dateien die in der Ordner /usr/share/jenkins/ref/jobs/ kopiert werden und beim initialisieren automatisch erstellt werden.
FROM jenkins/jenkins:lts
RUN jenkins-plugin-cli --plugins configuration-as-code:1.47 role-strategy:3.1 workflow-aggregator:2.6 git:4.7.0 pipeline-maven docker-build-publish:1.3.3 adoptopenjdk:1.3
COPY ./files/jenkins.yml /usr/share/jenkins/ref/config_as_code/jenkins.yml
ENV CASC_JENKINS_CONFIG /usr/share/jenkins/ref/config_as_code/jenkins.yml
COPY ./files/jobs/ /usr/share/jenkins/ref/jobs/
Die jenkins Konfiguration kann manuell über die Oberfläche durchgeführt werden und danach kann man sich das Ergebnis als .yml Datei anschauen:


Damit Jenkins den Installations-Assistenten starten muss noch eine Umgebungsvariabe gesetzt werden. Je nach Projekten sollte der Jenkins auch mit ausreichend Ram gestartet werden.
environment:
JAVA_OPTS: -Djenkins.install.runSetupWizard=false -Xmx8192m
Die Vollständige Service Definition sieht dann wie Folgend aus.
jenkins:
container_name: jenkins
environment:
JAVA_OPTS: -Djenkins.install.runSetupWizard=false -Xmx8192m
ports:
- 8080:8080
- 50000:50000
volumes:
- ./data/jenkins:/var/jenkins_home
build:
context: ./jenkins
depends_on:
- gitlab
Starten der Umgebung
# Alles starten
docker-compose up
# Alles im Hindergrund starten
docker-compose up -d
# Dockerfiles neu bauen und starten
docker-compose up --build
# Imges bauen und einzeln starten
docker-compose up --build gitlab
docker-compose up --build jenkins
docker-compose up --build create-git-examples
Beispielprojekt mit Java16 und Build Pipeline
Das Beispielprojekt besteht aus einem einfachen Jenkinsfile und einer Klasse und die dazugehörige Testklasse.
pipeline {
agent any
tools {
maven 'maven-3.6.3'
jdk 'jdk16'
}
stages {
stage ('Build') {
steps {
sh 'mvn -Dmaven.test.failure.ignore=true install'
}
post {
success {
junit 'target/surefire-reports/**/*.xml'
}
}
}
}
}
Die „Tools“ wurden vorher in der Jenkins Konfiguration erstellt:
tool:
git:
installations:
- home: "git"
name: "Default"
jdk:
installations:
- name: "jdk16"
properties:
- installSource:
installers:
- adoptOpenJdkInstaller:
id: "jdk-16+36"

Gesamtes Projekt
Links
https://git-scm.com/docs/git-credential-store
https://github.com/ufoscout/docker-compose-wait
https://www.praqma.com/stories/start-jenkins-config-as-code/
https://www.jenkins.io/blog/2017/02/07/declarative-maven-project/
http://www.thinkcode.se/blog/2019/12/23/jenkins-configuration-as-code
Eine Antwort auf „Gitlab + Jenkins + buildpipeline + Maven + Java Docker Umgebung für Entwickler“