Gitlab + Jenkins + buildpipeline + Maven + Java Docker Umgebung für Entwickler

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:

Configuration as Code Plugin aufrufen
Konfiguration anzeigen.

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"
Fertig ausgeführter Job

Gesamtes Projekt

Links

https://stackoverflow.com/questions/60229016/one-line-console-command-to-set-first-root-password-in-gitlab

https://docs.tibco.com/pub/mash-local/4.1.1/doc/html/docker/GUID-BD850566-5B79-4915-987E-430FC38DAAE4.html

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“

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.