Pipeline CI/CD : comprendre et réparer un pipeline rouge
L'idée en une phrase
Un pipeline CI/CD est une suite d'étapes automatiques (compiler, tester, construire, déployer) lancée à chaque fois que tu pousses du code. S'il est vert, ton code peut avancer. S'il est rouge, quelque chose doit être corrigé. Cette fiche t'explique comment il fonctionne et, surtout, comment réagir quand il échoue.
Une image pour comprendre : la check-list avant le décollage
Avant chaque vol, les pilotes déroulent une check-list : carburant, volets, instruments… dans un ordre précis. Si un point échoue, l'avion ne décolle pas, et peu importe que tout le reste soit bon.
Un pipeline, c'est la même chose pour ton code :
- chaque étape est un point de la check-list ;
- les étapes s'enchaînent dans l'ordre ;
- une seule étape en échec arrête tout : le code ne part pas en production.
Et comme pour un avion, on ne saute pas un point de la check-list « parce qu'on est pressé ».
CI et CD : deux sigles, deux rôles
| Sigle | Signifie | Ce que ça fait |
|---|---|---|
| CI | Continuous Integration (intégration continue) | à chaque push : compiler et lancer les tests, pour vérifier que ton code ne casse rien |
| CD | Continuous Delivery / Deployment (livraison ou déploiement continu) | construire l'application et la déployer, sur un environnement de test puis en production |
La CI répond à la question « mon code est-il correct ? ». La CD répond à « comment l'amener jusqu'aux utilisateurs ? ».
Le vocabulaire
Les exemples utilisent GitLab CI, mais les idées sont les mêmes avec GitHub Actions, Jenkins ou les autres outils.
| Terme | Ce que c'est |
|---|---|
| pipeline | l'ensemble du processus, lancé par un push ou une merge request |
| stage (étape) | un groupe de travaux qui s'exécutent au même moment ; les stages s'enchaînent dans l'ordre |
| job (travail) | une tâche précise : « lancer les tests », « construire le jar » |
| runner | la machine qui exécute les jobs |
| artefact | un fichier produit par un job et conservé (le .jar, un rapport de tests) |
Pipeline
├── stage "test" → job "tests"
├── stage "package" → job "paquet" (seulement si "test" a réussi)
└── stage "deploy" → jobs "deployer-recette", "deployer-production"
Un pipeline réel, ligne par ligne
Avec GitLab, le pipeline est décrit dans un fichier .gitlab-ci.yml, à la racine du projet. Voici celui d'une application Spring Boot classique :
stages:
- test
- package
- deploy
default:
image: maven:3.9-eclipse-temurin-21 # chaque job tourne dans ce conteneur : Maven + Java 21
variables:
MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
cache:
key: maven
paths:
- .m2/repository # les dépendances Maven sont gardées d'un pipeline à l'autre
tests:
stage: test
script:
- mvn -B verify # compile et lance tous les tests
artifacts:
when: always # garde le rapport même si les tests échouent
reports:
junit: target/surefire-reports/TEST-*.xml
paquet:
stage: package
script:
- mvn -B package -DskipTests # les tests ont déjà réussi à l'étape précédente
artifacts:
paths:
- target/*.jar
expire_in: 1 week
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # seulement sur la branche principale
deployer-recette:
stage: deploy
script:
- ./deploy.sh recette
environment: recette
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
deployer-production:
stage: deploy
script:
- ./deploy.sh production
environment: production
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual # un humain doit cliquer pour déployer en production
Ce qu'il faut comprendre :
- sur ta branche (ou ta merge request), seuls les tests tournent : on vérifie ton code ;
- sur la branche principale, après la fusion, le pipeline va plus loin : il construit le
.jaret le déploie automatiquement en recette (l'environnement de test) ; - la production demande un clic manuel : quelqu'un décide du moment de la mise en production.
Note :
-B(batch mode) rend la sortie de Maven plus lisible dans un pipeline.-DskipTestsdans le jobpaquetn'est pas une triche : les tests ont déjà tourné dans le jobtests, inutile de les relancer.
Astuce : l'image
maven:3.9-eclipse-temurin-21fixe la version de Java du pipeline. Elle doit correspondre à celle dupom.xml(voir la fiche sur le JDK).
Ton pipeline est rouge : la méthode
C'est la situation que tu rencontreras le plus souvent. Pas de panique : un pipeline rouge, c'est la check-list qui fait son travail.
1. Trouve le job en échec
Dans GitLab, ouvre le pipeline : le job en échec est marqué d'une croix rouge. Clique dessus pour afficher son journal (le log).
2. Cherche la première erreur, pas la dernière ligne
Le journal peut faire des milliers de lignes. La dernière ligne dit souvent juste « Job failed ». Cherche (Ctrl+F) ERROR ou FAIL, et lis la première occurrence : les suivantes sont souvent des conséquences de la première.
3. Identifie le type d'échec
| Ce que tu lis | Type d'échec | Que faire |
|---|---|---|
COMPILATION ERROR, cannot find symbol |
le code ne compile pas | corrige le code ; vérifie que tu as bien commité tous les fichiers |
Tests run: 120, Failures: 2 |
des tests échouent | lis le nom des tests en échec et leur message ; GitLab les affiche aussi dans l'onglet Tests de la merge request |
Could not resolve dependencies, Connection timed out |
réseau ou dépôt de dépendances indisponible | relance le job une fois ; si ça persiste, préviens l'équipe |
release version 21 not supported |
mauvaise version de Java | vérifie l'image Docker du pipeline et le pom.xml |
Job's log exceeded limit, job timed out |
le job a été trop long ou trop bavard | un test bloqué, une boucle infinie, trop de logs : cherche ce qui a changé |
4. Reproduis sur ton poste
Lance la même commande que le pipeline :
mvn -B verify
Si l'erreur apparaît aussi chez toi, tu peux la corriger tranquillement dans ton IDE.
5. « Mais ça marche chez moi ! »
Si l'erreur n'apparaît que dans le pipeline, c'est qu'une différence existe entre ton poste et le runner. Les causes classiques :
- un fichier non commité : ton code dépend d'un fichier présent sur ton disque mais pas dans Git (
git statuspour vérifier) ; - une version de Java différente ;
- un test qui dépend de ton environnement : fuseau horaire, langue du système, un fichier dans ton dossier personnel, une base de données locale ;
- un test qui dépend de l'ordre : il passe seul, mais échoue après un autre test qui a modifié des données partagées ;
- un test qui dépend de l'heure : il échoue à minuit, le dernier jour du mois, ou un 29 février.
Astuce : le pipeline est le juge de paix. C'est un environnement propre, sans les fichiers oubliés de ton poste. S'il échoue et que ton poste réussit, c'est généralement ton poste qui cache le problème.
Le test qui échoue « une fois sur dix »
Un test qui échoue au hasard (on parle de test instable, ou flaky) est un vrai bug, dans le test ou dans le code. Relancer le pipeline jusqu'à ce qu'il passe le rend vert aujourd'hui, mais le problème reviendra. Signale-le à l'équipe.
Les secrets : jamais dans le code
Le déploiement a besoin de mots de passe, de clés d'accès, de jetons. Ils ne doivent jamais apparaître dans le .gitlab-ci.yml, ni nulle part dans le dépôt Git : tout le monde peut lire le dépôt, et Git garde l'historique pour toujours, même si tu supprimes la ligne ensuite.
Dans GitLab, les secrets sont rangés dans les variables CI/CD du projet (Settings → CI/CD → Variables), avec deux options importantes :
| Option | Effet |
|---|---|
| Masked (masquée) | la valeur est remplacée par [MASKED] si elle apparaît dans un journal |
| Protected (protégée) | la variable n'est disponible que sur les branches protégées, comme la branche principale |
Le pipeline les utilise comme des variables d'environnement :
script:
- ./deploy.sh --token "$DEPLOY_TOKEN" # ✅ la valeur vient des variables CI/CD
Note : si tu as commité un secret par erreur, le supprimer dans un nouveau commit ne suffit pas : il reste dans l'historique. Préviens immédiatement l'équipe pour que le secret soit changé. C'est la seule vraie protection, et il n'y a aucune honte à le signaler vite.
Les bonnes habitudes
- Lance
mvn verifyavant de pousser. La plupart des pipelines rouges s'évitent en une commande. - Lis la première erreur du journal, pas la dernière ligne.
- Ne relance pas un job en boucle en espérant qu'il passe. Une relance pour un problème de réseau, oui ; au-delà, cherche la cause.
- Ne désactive jamais un test pour rendre le pipeline vert. Si un test te semble faux, parles-en.
- Ne pousse jamais directement sur la branche principale. Passe par une merge request, pour que le pipeline vérifie ton code avant la fusion.
- Une branche principale rouge est une priorité pour toute l'équipe : elle bloque tous les déploiements. Si c'est ton commit, occupe-t'en tout de suite ou demande de l'aide.
- Aucun secret dans le dépôt. Les mots de passe et jetons vont dans les variables CI/CD.
- Ne modifie pas le
.gitlab-ci.ymlsans en parler. Il est partagé par toute l'équipe et touche aux déploiements.
À retenir
- Un pipeline est une check-list automatique : compiler, tester, construire, déployer. Une étape en échec arrête tout.
- La CI vérifie ton code à chaque push ; la CD l'amène jusqu'aux environnements, la production demandant souvent un clic manuel.
- Pipeline rouge : ouvre le job, cherche la première erreur, identifie son type, reproduis-la sur ton poste.
- « Ça marche chez moi » cache souvent un fichier non commité, une autre version de Java ou un test dépendant de l'environnement.
- Les secrets ne vont jamais dans le dépôt, mais dans les variables CI/CD, masquées et protégées.