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 service

    Si Jenkins tourne lui-même dans un conteneur, montez /var/run/docker.sock et 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-api du TP8 poussé dans un dépôt GitHub personnel, avec un Dockerfile multi-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

Stages du pipeline : checkout, install, lint et tests en parallèle, build, push, post Stages du pipeline : checkout, install, lint et tests en parallèle, build, push, post

  • Copier le squelette Jenkinsfile à la racine de votre dépôt contact-api, remplacer IMAGE_NAME, commiter et pousser.
  • Créer un job Pipeline → Pipeline script from SCM → Git → URL de votre dépôt → branche main → Script Path Jenkinsfile.
  • 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ès npm i -D eslint @eslint/js et npx eslint --init, ou node --check src/**/*.js en version minimale).

4. Partie 2 : Agents Docker, parallélisme et rapports

  • Exécuter Install et Quality dans un agent node:24-alpine (reuseNode true pour partager l’espace de travail).

  • Remplacer le stage Quality par un bloc parallel contenant Lint et Unit 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() dans options.

  • Faire échouer volontairement un test : vérifier que les stages suivants sont sautés, que le bloc failure s’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_SHA après le checkout :

    script { env.SHORT_SHA = env.GIT_COMMIT.take(7) }
  • Construire ${IMAGE_NAME}:${SHORT_SHA} avec le label org.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 sh qui 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.txt contenant 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

Multibranch : Jenkins scanne GitHub et crée un job par branche et par PR Multibranch : Jenkins scanne GitHub et crée un job par branche et par PR

  • 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 jobs feature/… et PR-1.

  • Vérifier que le stage Push est sauté (skipped) sur la branche et la PR, et exécuté sur main après le merge.

Défi

  1. Extraire les étapes docker build / docker push dans une Shared Library Jenkins (vars/buildAndPush.groovy) chargée par @Library('ci-lib') _.
  2. 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.