Dit was een perfecte kans om voor een nieuw opgezette applicatie de build pipeline in te richten. Voorheen werd dit in Jenkins gedaan, een koppeling naar GitStash ontbrak, niet heel handig als meerdere teams deze omgevingen gebruiken en je moet gaan zoeken naar die ene build. Een ander nadeel was dat de buildserver configuratie in Jenkins zelf werd gedaan, historie en versiebeheer laten hier te wensen over.
De pipeline in Gitlab CI wordt in de leesbare taal YAML geschreven. Deze configuratie files kun je in je software project opnemen net zoals iedere andere software of configuratie file en staan daardoor automatisch in versiebeheer. Met behulp van de GitLab CI documentatie kun je een vliegende start maken. Ik heb er voor gekozen om op het hoogste niveau in mijn Maven project alle stappen van mijn pipeline te definiëren in de desbetreffende .gitlab-ci.yml file, dit zijn je ‘Stages’. Tevens verwijs ik naar een andere .yml file voor de daadwerkelijke configuratie implementatie van elke stage. Dat ziet er als volgt uit:
stages:
– build
– deploy
– test
include:
– ‘ci-jobs/.build-ci.yml’
– ‘ci-jobs/.deploy-ci.yml’
– ‘ci-jobs/.test-ci.yml’
Oké, de flow van onze pipeline staat, maar het doet nog niks. Laten we de file uitbreiden met het configureren van de ‘build’ stage. In de ci-jobs/.build-ci.yml file vertel je eerst welke stage dit is en kies ik er voor om één job genaamd ‘build-ci’ te maken. Vervolgens kunnen we simpelweg met UNIX commando’s vertellen welke scripts er uitgevoerd moeten worden. Dit is dus feitelijk hetzelfde als je command line in bijvoorbeeld je lokale Linux ontwikkelomgeving.
Nu moet er nog een en ander ingericht worden zodat GitLab daadwerkelijk in staat is om je pipeline uit te kunnen voeren. Zogenaamde GitLab runners zijn je beschikbare resources, deze pakken je GitLab CI job op zodra de pipeline gestart is. Maar om Maven commando’s uit te voeren en Java code te compileren moet deze tooling wel beschikbaar zijn voor de GitLab runner. Dit kun je inrichten door bijvoorbeeld een Docker image met voorgeïnstalleerde tooling aan GitLab toe te voegen. Dit image nemen we op in de ‘build-ci’ job configuratie. Nu weet de GitLab runner exact op welk image hij je scripts moet uitvoeren.
Omdat dit niet de enige stage is die we in deze pipeline willen runnen is het wel handig dat de gebouwde artifacts in je target directory bewaard blijven. Zo kunnen we bijvoorbeeld in de test stage deze gebruiken zonder de hele code weer opnieuw te moeten compileren. Daarnaast hoeft Maven ook niet bij elk commando alle dependencies opnieuw binnen te halen. Seze bewaren we ook doormiddel van cache voor de .m2/repository/ directory te configureren. De complete build stage configuratie ziet er nu als volgt uit:
stages:
– build
build-ci:
stage: build
image: mijn-gitlab-docker-image-met-maven-en-jdk-8
script:
– mvn clean install
artifacts:
paths:
– “*/target**/*”
cache:
key: “$CI_PROJECT_NAME”
paths:
– .m2/repository/
Op het moment dat ik mijn wijzigingen push of merge start GitLab automatisch met het runnen van mijn pipeline, dat ziet er goed uit!
Je kunt elke job aanklikken om de command line output van je scripts te zien. Handig om te zien waarom iets bijvoorbeeld gefaald is. Door meerdere jobs in één stage op te nemen kunnen jobs parallel lopen. Meerdere GitLab runners zijn hiervoor een vereiste.
Nog een handige tip voor het ontwikkelen van je pipeline is lokaal runnen en debuggen. Elke wijziging naar je remote branch pushen kost immers tijd. Zorg dat je ingelogd bent op je Docker omgeving. Vervolgens kun je de Docker image uit GitLab lokaal bouwen en op inloggen. Zo kun je daadwerkelijk proberen en controleren wat er gebeurt bij het uitvoeren van je scripts. Bijvoorbeeld met dit commando:
docker run –rm -ti -v $PWD:/build -w /build mijn-gitlab-docker-image-met-maven-en-jdk-8 /bin/bash
Zoals je ziet kun je met deze krachtige tool een vliegende start maken. Schedulen met behulp van crontab voor bijvoorbeeld een nighly build is ook mogelijk. Je kunt bij een merge request automatisch de pipeline laten lopen en je ziet meteen het resultaat, ‘per ongeluk’ niet compilerende code merge is geen optie meer! En nog belangrijker, mocht het toch ooit gebeuren, dan is altijd terug te herleiden waar het fout is gegaan.