Le Gitlab CI intègre depuis la version 8.8 de Gitlab la notion de pipeline. C’est une notion très à la mode permettant de pouvoir séparer son processus de build en plusieurs étapes distinctes, interdépendantes et parallélisables. Nous allons prendre ici l’exemple d’une application SpringBoot utilisant Maven et créer un pipeline de construction de l’application ayant le cheminement suivant
Dans un premier temps nous allons créer 2 répertoires partagés par nos runners pour nos builds maven
mkdir -p /var/lib/gitlab-runner/.m2 /var/lib/gitlab-runner/tools On configure ensuite le runner gitlab pour utiliser en read-only le .m2 et les outils. Editez le fichier /etc/gitlab-runner/config.toml:
concurrent = 2
check_interval = 0
[[runners]]
name = "runner01"
url = "http://gitlab.example.org/"
token = "99aab9a13c8efda114771f017fcf"
executor = "docker"
[runners.docker]
tls_verify = false
image = "debian:jessie"
privileged = false
disable_cache = true
volumes = ["/cache", "/var/lib/gitlab-runner/.m2:/.m2:ro", "/var/lib/gitlab-runner/tools:/tools:ro"]
[runners.cache]
Notre runner est pratiquement prêt, avant de le finir nous allons configurer le pipeline Maven afin que vous compreniez mieux la dernière phase. Vous pouvez voir ici 2 choses sortant du commun:
Notre pipeline maven s’appuie sur 5 étapes:
Les étapes de documentation, déploiement Nexus et de génération de release ne seront effectuées que dans certaines conditions:
Afin de s’y retrouver, je vous propose de regarder le graphe suivant Notre étape de tests est découpée en 2 tâches parallèles:
Passons maintenant au fichier .gitlab-ci.yml que nous allons ajouter au repository:
---
image: maven:3-jdk-8
cache:
paths:
- $HOME/.m2/
variables:
MAVEN_CLI_OPTS: "-s /.m2/settings.xml -B"
SONAR_PROJECT_NAME: "project-demo"
stages:
- build
- test
- deploy
- documentation
- release
maven:build:
stage: build
environment: staging
script:
- "mvn $MAVEN_CLI_OPTS clean compile"
artifacts:
when: on_success
expire_in: 1 day
paths:
- target/
maven:package:
stage: test
environment: staging
dependencies:
- maven:build
script: "mvn $MAVEN_CLI_OPTS package"
artifacts:
when: on_success
expire_in: 1 day
paths:
- target/
maven:sonar:
stage: test
environment: staging
dependencies:
- maven:build
script: "mvn $MAVEN_CLI_OPTS verify sonar:sonar -D sonar.projectName=$SONAR_PROJECT_NAME -Dsonar.gitlab.commit_sha=$CI_BUILD_REF -Dsonar.gitlab.ref_name=$CI_BUILD_REF_NAME"
artifacts:
when: on_success
expire_in: 1 day
paths:
- target/
maven:deploy-nexus:
stage: deploy
environment: staging
except:
- tags
- releases
dependencies:
- maven:package
- maven:sonar
script: "mvn $MAVEN_CLI_OPTS deploy"
artifacts:
when: on_success
expire_in: 1 day
paths:
- target/*.jar
maven:javadoc:
stage: documentation
environment: staging
only:
- tags
dependencies:
- maven:deploy-nexus
script: "mvn $MAVEN_CLI_OPTS javadoc:javadoc"
artifacts:
when: on_success
expire_in: 1 week
paths:
- target/site/apidocs/
maven:release:
stage: release
environment: staging
only:
- releases
dependencies:
- maven:deploy-nexus
script:
- "/tools/maven-release"
Nous utilisons ici une image docker officielle contenant un builder Maven 3.3 et une JVM Java 8. Gitlab 8.16 et inférieurs ne permettant pas de pousser depuis le CI nous allons devoir ruser en utilisant un script avec une clef privée spécifique d’édition des repositories. Je reviendrai plus tard sur la méthode pour Gitlab 9.0 et supérieurs. Je vous propose de regarder le script ci-dessous:
#! /bin/bash
which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y ) > /dev/null
# Run ssh-agent (inside the build environment)
eval $(ssh-agent -s) > /dev/null
# Add the SSH key stored in SSH_PRIVATE_KEY variable to the agent store
ssh-add /tools/.ssh/id_rsa > /dev/null
mkdir -p ~/.ssh
ssh-keyscan gitlab.example.org > ~/.ssh/known_hosts 2>/dev/null
[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
git config --global user.email 'gitlab-ci@example.org'
git config --global user.name 'Gitlab CI'
# Reconfigure push repository to use SSH
CI_PUSH_REPO=`echo $CI_BUILD_REPO | perl -pe 's#.*@(.+?(\:\d+)?)/#git@\1:#'`
git remote set-url --push origin "${CI_PUSH_REPO}"
# Maven doesn't like detach HEADs, attach
git checkout -B "$CI_BUILD_REF_NAME"
mvn $MAVEN_CLI_OPTS release:clean -DskipTests=true
mvn $MAVEN_CLI_OPTS release:prepare -DskipTests=true
# prepare done, pushing tags
git push origin --tags
mvn $MAVEN_CLI_OPTS release:perform -DskipTests=true
Il s’agit ici de résoudre 2 problématiques:
Enfin on pousse les tags générés par Maven et on pousse l’artefact vers Nexus. Le push du tag va déclencher un second pipeline générant automatiquement la documentation.
Nous avons vu ici comment utiliser efficacement le Gitlab CI pour construire une application standard Maven depuis Gitlab. Si vous utilisez Jenkins, Gitlab CI offre une alternative intéressante, notamment par des pipelines extrêmement flexibles, vous permettant de construire facilement des applications au moyen de conteneurs Docker, et donc reproductibles, avec des workspaces propres. A vous de jouer !