Pipeline CI/CD : comprendre et réparer un pipeline rouge

Publié le · Mis à jour le

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 .jar et 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. -DskipTests dans le job paquet n'est pas une triche : les tests ont déjà tourné dans le job tests, inutile de les relancer.

Astuce : l'image maven:3.9-eclipse-temurin-21 fixe la version de Java du pipeline. Elle doit correspondre à celle du pom.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 status pour 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

  1. Lance mvn verify avant de pousser. La plupart des pipelines rouges s'évitent en une commande.
  2. Lis la première erreur du journal, pas la dernière ligne.
  3. 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.
  4. Ne désactive jamais un test pour rendre le pipeline vert. Si un test te semble faux, parles-en.
  5. Ne pousse jamais directement sur la branche principale. Passe par une merge request, pour que le pipeline vérifie ton code avant la fusion.
  6. 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.
  7. Aucun secret dans le dépôt. Les mots de passe et jetons vont dans les variables CI/CD.
  8. Ne modifie pas le .gitlab-ci.yml sans 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.

Avis sur l'article

Pas encore de note : soyez le premier à donner votre avis.

Les avis sont publiés après validation par le modérateur.

Votre note