Skip to main content

Pipelines

Hoewel we met het 'freestyle' project in de vorige oefening al behoorlijk wat flexibiliteit hadden, laat Jenkins ook toe om complexere sequenties te bouwen voor bijvoorbeeld continuous deployment.

Daarvoor gebruik je een Pipeline-project.

Jenkins laat toe om zo'n pipeline te declareren in een Jenkinsfile in je repository, of in de user interface van Jenkins. De syntax is verder identiek.

Het gebruik van een Jenkinsfile geniet meestal de voorkeur, omdat je dan ook een versiegeschiedenis hebt van je build-omgeving.

Een voorbeeld van zo'n Jenkinsfile zie je hieronder:

pipeline {
agent { <1>
docker { image 'node:14-alpine' }
}
stages { <2>
stage('Test') {
steps { <3>
sh 'node --version'
}
}
}
}

[1] Met de agent (of node) geef je aan waar je pipeline moet uitgevoerd worden. Docker is een optie, andere mogelijkheden zijn bijvoorbeeld andere servers, Kubernetes clusters, virtuele machines. Deze agents hoeven dus zeker niet lokaal op de Jenkins-server geïnstalleerd te zijn, al doen we dit wel voor deze workshop.

[2] Stages vormen het hoogste niveau van opdeling in de pipeline.

[3] Steps zijn specifieke acties.

Prerequisites

Ga naar de admin-sectie van je Jenkins installatie, en installeer de 'Docker Pipeline'-plugin.

Op de build server zal het eveneens nodig zijn om Docker te installeren. Volg daarvoor de officiële documentatie op https://docs.docker.com/engine/install/ubuntu/ Vergeet daarbij zeker de postinstall stappen niet, in het bijzonder moet je de 'Jenkins'-user toevoegen aan de docker group om te vermijden dat je te weinig permissies hebt.

warning

Op die manier hebben je containers root-permissies. Deze manier van werken is dus niet bruikbaar als je ook externen op je platform hebt...

Een eenvoudige pipeline opzetten

Maak een nieuw project (type: Pipeline, naam 'Mijn Pipeline project') en koppel dezelfde repository als in het freestyle project. Dat doe je in dit geval door bij Pipeline te kiezen voor "Pipeline script from SCM".

pipeline {
agent {
docker {
image 'python:3.8'
args '-u root:root'
}
}
stages {
stage('Python3.8') {
steps {
sh 'echo "Start Testing..."'
sh 'pip3 install -r requirements.txt'
sh 'pip3 install pytest'
sh 'pytest *.py'
}
}
}
}

Deze Jenkinsfile plaats je in de root van je Gitlab-repository. Deze zal, net zoals later '.gitlaci.yml' automatisch ingelezen worden door Jenkins om de nodige pipelines uit te voeren.

Werk op basis van bovenstaande aanzet verder uit in een "Jenkinsfile" in jouw repository:

  • Zorg ervoor dat er extra stages komen waarbij dezelfde test doorlopen wordt in respectievelijk python 3.4, 3.8 en 3.9. Zo krijg je meteen te zien als alle packages beschikbaar zijn in die bepaalde Python versies. Je zal hierbij moeten agents toevoegen aan iedere stage. (documentatie: https://www.jenkins.io/doc/book/pipeline/docker/#using-multiple-containers)

  • Voeg voor die drie stages ook een pylint step toe. Je zal daarbij pylint moeten installeren, en het ook uitvoeren uiteraard. Net zoals in voorgaande oefeningen zorgen we voor een output naar een tekstbestand, dat achteraf ook als artefact moet bewaard worden.

  • Zorg ervoor dat de repository elk uur gescand wordt, en dat in geval van wijzigingen automatisch een nieuwe build gestart wordt.

Conclusie: Met deze opgave kreeg je een idee van de werking van Jenkins. Uiteraard is dit slechts het begin. We eindigen de oefening met enkele falende stages omdat deze specifieke versie van Flask niet beschikbaar is voor specifieke Python-versies (3.9) of niet compatibel is met de syntax (3.4). Dat zou het begin kunnen vormen van een volledige pipeline, die code steeds gaat testen tov verschillende versies van Python om op die manier compatibiliteit met oudere versies te garanderen naar klanten.

Jenkins is een gevestigde waarde in het CI/CD landschap. Vooral voor het builden en testen zijn er veel mogelijkheden. Het deployen kwam in deze oefening minder aan bod, maar je kan je voorstellen dat je met enkele extra stappen het resulterend bestand ook kan kopiëren naar een externe server, een cloud-omgeving, ...