TP9 : Pipeline as Code avec Jenkins (Jenkinsfile, agents Docker, Multibranch)
Vous avez installé Jenkins au TP4 et découvert un pipeline CI hébergé avec GitHub Actions au TP3. Ce TP vous apprend à décrire un pipeline Jenkins dans le dépôt (Jenkinsfile) : stages, exécution parallèle, agents Docker, credentials, blocs post, artefacts, tag d’image basé sur le Git SHA, puis un job Multibranch qui construit chaque branche et chaque Pull Request.
Fichiers de départ :
Jenkinsfile
1. Objectifs pédagogiques
À l’issue du TP, vous serez capable de :
- distinguer pipeline déclaratif et scripté, et lire la structure
pipeline / agent / stages / steps / post; - exécuter un stage dans un conteneur Docker éphémère (
agent { docker … }) ; - paralléliser des stages et publier des résultats de tests JUnit ;
- utiliser un credential Jenkins sans jamais l’afficher dans les logs ;
- tagger une image avec le Git SHA et la pousser uniquement depuis
main; - configurer un Multibranch Pipeline relié à GitHub.
Les images de cette page sont des schémas explicatifs, pas des captures d’écran.
2. Environnement du TP
-
Jenkins LTS fonctionnel (TP4, partie 4) avec Docker sur la même machine. L’utilisateur qui exécute Jenkins doit pouvoir lancer
docker:sudo usermod -aG docker jenkins && sudo systemctl restart jenkins # Jenkins installé en serviceSi Jenkins tourne lui-même dans un conteneur, montez
/var/run/docker.socket installez le client Docker dans l’image (voir la doc Jenkins in Docker). -
Plugins (Manage Jenkins → Plugins) : Pipeline, Git, GitHub Branch Source, Docker Pipeline, JUnit, Credentials Binding, Workspace Cleanup, Timestamper.
-
Le projet
contact-apidu TP8 poussé dans un dépôt GitHub personnel, avec unDockerfilemulti-stage écrit selon le TP7. -
Un compte Docker Hub.
| Terme | Signification |
|---|---|
| Jenkinsfile | Fichier versionné qui décrit le pipeline (Pipeline as Code). |
| Agent | Où s’exécute le pipeline ou un stage : nœud Jenkins, label, conteneur Docker. |
| Stage / Step | Étape logique visible dans l’interface / commande élémentaire (sh, echo, junit). |
| post | Actions exécutées selon le résultat : always, success, failure, cleanup. |
| Credential | Secret stocké chiffré par Jenkins, injecté le temps d’un bloc withCredentials. |
| Multibranch | Job qui découvre les branches et PR d’un dépôt et crée un pipeline pour chacune. |
3. Partie 1 : Premier pipeline depuis le dépôt
- Copier le squelette
Jenkinsfileà la racine de votre dépôtcontact-api, remplacerIMAGE_NAME, commiter et pousser. - Créer un job Pipeline → Pipeline script from SCM → Git → URL de votre dépôt → branche
main→ Script PathJenkinsfile. - Lancer le build et parcourir la Console Output et la vue des stages.
- Ajouter un lint au projet (
npm pkg set scripts.lint="eslint ."aprèsnpm i -D eslint @eslint/jsetnpx eslint --init, ounode --check src/**/*.jsen version minimale).
4. Partie 2 : Agents Docker, parallélisme et rapports
-
Exécuter
InstalletQualitydans un agentnode:24-alpine(reuseNode truepour partager l’espace de travail). -
Remplacer le stage
Qualitypar un blocparallelcontenantLintetUnit tests. -
Produire un rapport JUnit avec Vitest et le publier dans
post { always { junit … } }:npx vitest run --reporter=default --reporter=junit --outputFile.junit=reports/junit.xml -
Ajouter
disableConcurrentBuilds()dansoptions. -
Faire échouer volontairement un test : vérifier que les stages suivants sont sautés, que le bloc
failures’exécute et que l’onglet Tests affiche le test en échec.
5. Partie 3 : Image tagguée avec le Git SHA, credentials et push
-
Créer le credential
dockerhub(Manage Jenkins → Credentials → System → Global) de type Username with password, avec un access token Docker Hub (pas votre mot de passe). -
Calculer
SHORT_SHAaprès le checkout :script { env.SHORT_SHA = env.GIT_COMMIT.take(7) } -
Construire
${IMAGE_NAME}:${SHORT_SHA}avec le labelorg.opencontainers.image.revision=${GIT_COMMIT}. -
Pousser l’image uniquement sur
main:withCredentials([usernamePassword(credentialsId: 'dockerhub', usernameVariable: 'DH_USER', passwordVariable: 'DH_TOKEN')]) { sh 'echo "$DH_TOKEN" | docker login -u "$DH_USER" --password-stdin' sh 'docker push "$IMAGE_NAME:$SHORT_SHA"' }Utilisez des guillemets simples autour des commandes
shqui manipulent des secrets : c’est le shell, pas Groovy, qui remplace les variables, et le secret n’apparaît pas dans le script interpolé. Vérifiez dans la console que le token est masqué (****). -
Archiver un fichier
image.txtcontenant la référence complète de l’image (archiveArtifacts). -
Vérifier que le tag affiché sur Docker Hub correspond à
git rev-parse --short HEAD.
6. Partie 4 : Multibranch Pipeline
-
Créer un credential GitHub (Username with password : identifiant GitHub + fine-grained personal access token en lecture seule sur le dépôt).
-
Créer un job Multibranch Pipeline → source GitHub → votre dépôt. Dans Scan Multibranch Pipeline Triggers, cocher Periodically if not otherwise run (2 minutes).
La VM de lab n’est pas joignable depuis Internet : GitHub ne peut pas appeler Jenkins par webhook. Le scan périodique remplace le webhook.
-
Créer une branche
feature/rate-limit-config, la pousser, ouvrir une Pull Request et observer l’apparition des jobsfeature/…etPR-1. -
Vérifier que le stage
Pushest sauté (skipped) sur la branche et la PR, et exécuté surmainaprès le merge.
Défi
- Extraire les étapes
docker build/docker pushdans une Shared Library Jenkins (vars/buildAndPush.groovy) chargée par@Library('ci-lib') _.- Installer le plugin GitHub Checks (ou Embeddable Build Status) pour afficher le résultat du build dans la Pull Request.
7. Livrables
Captures à déposer dans captures/ :
| Fichier | Contenu attendu |
|---|---|
pipeline-stages.png |
Vue des stages avec Lint et Unit tests en parallèle |
junit-report.png |
Onglet Tests avec un test en échec puis corrigé |
credentials-masked.png |
Console où le token Docker Hub apparaît sous forme **** |
dockerhub-sha-tag.png |
Image contact-api:<sha> sur Docker Hub + git rev-parse --short HEAD |
multibranch.png |
Jobs main, feature/… et PR-1 dans le Multibranch |
shared-library.png |
(défi) pipeline utilisant la Shared Library |
Ainsi que le Jenkinsfile final.