Aller au contenu
CI/CD & Automatisation medium

Pipelines parent-enfant GitLab CI/CD

21 min de lecture

logo gitlab

Votre pipeline a 50 jobs et devient ingérable ? Les pipelines parent-enfant permettent de découper un pipeline complexe en sous-pipelines indépendants. Le parent orchestre, les enfants exécutent.

À la fin de ce module, vous saurez :

  • Déclencher un pipeline enfant : trigger: include avec un fichier local
  • Contrôler l’attente : strategy: depend vs strategy: mirror
  • Passer des variables : explicites ou via dotenv
  • Partager des artefacts : needs:pipeline:job entre parent et enfant
  • Déclencher multi-projet : trigger: project vers un autre repo
  • Organiser un monorepo : un pipeline par composant

Avant de continuer, assurez-vous de maîtriser :

Sans découpage, votre .gitlab-ci.yml ressemble à ça :

# ❌ Un fichier de 500 lignes avec TOUT dedans
build_frontend:
script: npm run build
build_backend:
script: go build
build_api:
script: python setup.py
test_frontend:
script: npm test
test_backend:
script: go test
test_api:
script: pytest
deploy_frontend:
# ... et ça continue

Problèmes concrets :

  • Maintenance : Qui est responsable de quoi ? Tout le monde modifie le même fichier.
  • Lisibilité : 50 jobs dans un seul fichier = cauchemar à débugger.
  • Performance : Le backend n’a pas changé ? Dommage, on le rebuild quand même.
  • Isolation : Le test frontend échoue ? Impossible de déployer le backend qui est OK.
Sans parent-enfantAvec parent-enfant
Un seul .gitlab-ci.yml géantFichiers séparés par composant
Difficile à maintenirResponsabilité claire (l’équipe front gère frontend/.gitlab-ci.yml)
Tout s’exécute toujoursExécution conditionnelle par composant
Un échec bloque toutIsolation des problèmes

pipeline parent-enfants

Un trigger est un job spécial qui ne fait qu’une chose : lancer un autre pipeline. Il ne contient pas de script: — juste une instruction trigger: qui dit “à ce moment, démarre ce pipeline enfant”.

Le fichier .gitlab-ci.yml à la racine du projet contient uniquement des jobs de déclenchement :

# .gitlab-ci.yml (racine du projet)
stages:
- triggers # Un seul stage : déclencher les enfants
# 🎭 Job qui déclenche le pipeline frontend
trigger_frontend:
stage: triggers
trigger: # 👈 Mot-clé magique : ce n'est pas un job normal
include: frontend/.gitlab-ci.yml # 👈 Chemin vers le fichier CI de l'enfant
strategy: depend # 👈 "Attends que l'enfant finisse"
# 🎭 Job qui déclenche le pipeline backend
trigger_backend:
stage: triggers
trigger:
include: backend/.gitlab-ci.yml
strategy: depend

Décortiquons :

  1. trigger: — Ce mot-clé transforme le job en “lanceur de pipeline”. Pas de script:, pas de image:.
  2. include: frontend/.gitlab-ci.yml — Le chemin du fichier CI enfant, relatif à la racine du repo.
  3. strategy: depend — Le parent attend la fin de l’enfant avant de continuer. Sans ça, il passe immédiatement au job suivant.

Le fichier enfant est un .gitlab-ci.yml classique. Il ne sait même pas qu’il est “enfant” — il s’exécute normalement :

frontend/.gitlab-ci.yml
stages:
- build
- test
build:
stage: build
image: node:20 # Son propre environnement
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
test:
stage: test
image: node:20
script:
- npm test

Avantage : L’équipe frontend peut modifier ce fichier sans toucher au reste. Chaque composant a son propre “mini-pipeline”.

La forme la plus simple — l’enfant est un fichier dans le même repo :

trigger_job:
trigger:
include: path/to/child.yml # Chemin relatif depuis la racine du repo

strategy: depend — le paramètre le plus important

Section intitulée « strategy: depend — le paramètre le plus important »

Sans strategy: depend, voici ce qui se passe :

Parent : trigger_frontend → ✅ success (immédiatement !)
Enfant : → build → test → ❌ échoue
Résultat : le parent est VERT alors que l'enfant a échoué !

Avec strategy: depend :

Parent : trigger_frontend → ⌛ attend...
Enfant : → build → test → ❌ échoue
Résultat : le parent passe en ❌ échec aussi
trigger_job:
trigger:
include: child.yml
strategy: depend # ✅ Attend la fin et hérite du statut

strategy: depend vs strategy: mirror — quelle différence ?

Section intitulée « strategy: depend vs strategy: mirror — quelle différence ? »

Les deux attendent l’enfant, mais diffèrent sur les cas limites :

Situationdependmirror
Enfant réussitParent ✅Parent ✅
Enfant échoueParent ❌Parent ❌
Enfant annulé (cancel)Parent ❌ (failed)Parent ⏹ (cancelled)
Enfant en warningParent ✅Parent ⚠️ (warning)

En pratique :

  • depend : le plus courant, convient à 99% des cas
  • mirror : reflet exact du statut enfant (utile avec les pipelines auto-cancelés)
trigger_job:
trigger:
include: child.yml
strategy: mirror # Miroir strict du statut enfant

forward : transmettre automatiquement les variables

Section intitulée « forward : transmettre automatiquement les variables »

Par défaut, l’enfant ne reçoit pas les variables du parent. Avec forward:, vous pouvez transmettre automatiquement :

trigger_job:
trigger:
include: child.yml
forward:
yaml_variables: true # Variables définies dans le YAML parent
pipeline_variables: true # Variables passées via l'interface web ou API

Quand utiliser forward: ?

  • Vous avez beaucoup de variables à passer
  • Vous voulez que l’enfant hérite du contexte complet du parent

Quand utiliser variables: explicites ? (voir section suivante)

  • Vous voulez contrôler précisément ce qui est passé
  • Vous avez besoin de renommer ou transformer des variables

Un pipeline enfant s’exécute dans son propre contexte. Il ne voit pas automatiquement les variables du parent. Si le parent connaît la version à déployer (VERSION=1.2.3), comment la transmettre ?

Définissez les variables directement dans le job trigger :

trigger_frontend:
variables:
ENVIRONMENT: "staging" # Valeur fixe
VERSION: $CI_COMMIT_SHA # Valeur dynamique du parent
DEBUG: "true" # Configuration pour l'enfant
trigger:
include: frontend/.gitlab-ci.yml
strategy: depend

Dans l’enfant, ces variables sont disponibles comme n’importe quelle variable :

frontend/.gitlab-ci.yml
deploy:
script:
- echo "Déploiement version $VERSION sur $ENVIRONMENT"
- ./deploy.sh

Parfois, la valeur à passer n’est connue qu’après l’exécution d’un job. Par exemple : la version est calculée dynamiquement, ou un ID est généré.

Étape 1 : Générer le fichier dotenv dans un job du parent

prepare:
stage: prepare
script:
# Calcule la version dynamiquement
- VERSION=$(./scripts/compute-version.sh)
# Écrit dans le fichier dotenv (format : CLÉ=valeur)
- echo "VERSION=$VERSION" >> build.env
- echo "BUILD_DATE=$(date +%Y-%m-%d)" >> build.env
artifacts:
reports:
dotenv: build.env # 👈 GitLab charge ces variables automatiquement

Étape 2 : Utiliser ces variables dans le trigger

trigger_deploy:
stage: deploy
needs: ["prepare"] # Important : doit attendre le job qui crée le dotenv
variables:
VERSION: $VERSION # Provient de build.env
BUILD_DATE: $BUILD_DATE
trigger:
include: deploy.yml
strategy: depend

Pourquoi ? Parent et enfant sont des pipelines distincts, avec leurs propres IDs. Le mot-clé needs: ["job"] cherche un job dans le même pipeline.

GitLab fournit une syntaxe spéciale pour récupérer des artefacts entre pipelines.

Parent → Child (même projet) : needs:pipeline:job

Section intitulée « Parent → Child (même projet) : needs:pipeline:job »

Étape 1 : Le parent produit un artefact ET passe son ID de pipeline

# Dans le parent
build_artifacts:
stage: build
script:
- echo "artifact from parent" > artifact.txt
- ./compile.sh
artifacts:
paths:
- artifact.txt
- dist/
trigger_child:
stage: deploy
trigger:
include: path/to/child-pipeline.yml
strategy: depend
variables:
PARENT_PIPELINE_ID: $CI_PIPELINE_ID # 👈 Passe l'ID du pipeline parent

Étape 2 : L’enfant récupère l’artefact en référençant le pipeline parent

# Dans l'enfant (child-pipeline.yml)
test_child:
stage: test
script:
- ls -la # Vérifie que l'artefact est là
- cat artifact.txt # Utilise l'artefact
needs:
- pipeline: $PARENT_PIPELINE_ID # 👈 ID du pipeline source
job: build_artifacts # 👈 Nom du job qui a créé l'artefact

Comment ça marche :

  1. $CI_PIPELINE_ID contient l’ID unique du pipeline parent (ex: 123456)
  2. On passe cet ID à l’enfant via variables:
  3. L’enfant utilise needs:pipeline: pour dire “va chercher les artefacts de ce pipeline-là”
  4. GitLab télécharge l’artefact du job build_artifacts du pipeline 123456

Pour récupérer un artefact d’un autre projet (pas juste un autre pipeline), utilisez needs:project :

# Dans le pipeline du projet B
test_downstream:
stage: test
script:
- ls -la artifact.txt
- ./use-artifact.sh
needs:
- project: my-group/upstream_project # Chemin du projet source
job: build_artifacts # Job qui a produit l'artefact
ref: main # Branche du projet source
artifacts: true # Télécharger les artefacts

Votre application est découpée en plusieurs repos :

  • my-company/frontend — l’application React
  • my-company/backend — l’API Go
  • my-company/deployment — les scripts de déploiement Kubernetes

Quand le frontend est buildé, vous voulez déclencher le déploiement dans le repo deployment.

trigger_deployment:
trigger:
project: my-company/deployment # Chemin complet du projet cible
branch: main # Branche à déclencher
strategy: depend # Attend la fin

Différence avec include: :

  • include: → fichier dans le même repo → child pipeline
  • project: → pipeline dans un autre repo → multi-project pipeline

Passez du contexte au pipeline cible :

deploy_production:
variables:
DEPLOY_ENV: "production" # Où déployer
APP_VERSION: $CI_COMMIT_TAG # Quelle version
SOURCE_PROJECT: $CI_PROJECT_PATH # D'où ça vient
trigger:
project: my-company/deployment
branch: main
strategy: depend

Structure :

monorepo/
├── .gitlab-ci.yml # Parent
├── frontend/
│ ├── .gitlab-ci.yml # Enfant frontend
│ └── src/
├── backend/
│ ├── .gitlab-ci.yml # Enfant backend
│ └── src/
└── shared/
└── utils/
.gitlab-ci.yml
stages:
- prepare
- build
- deploy
# Déterminer ce qui a changé
changes:
stage: prepare
script:
- |
if git diff --name-only HEAD~1 | grep -q "^frontend/"; then
echo "FRONTEND_CHANGED=true" >> build.env
fi
if git diff --name-only HEAD~1 | grep -q "^backend/"; then
echo "BACKEND_CHANGED=true" >> build.env
fi
artifacts:
reports:
dotenv: build.env
# Déclencher frontend si modifié
trigger_frontend:
stage: build
needs: ["changes"]
trigger:
include: frontend/.gitlab-ci.yml
strategy: depend
rules:
- if: $FRONTEND_CHANGED == "true"
# Déclencher backend si modifié
trigger_backend:
stage: build
needs: ["changes"]
trigger:
include: backend/.gitlab-ci.yml
strategy: depend
rules:
- if: $BACKEND_CHANGED == "true"
frontend/.gitlab-ci.yml
stages:
- install
- build
- test
install:
stage: install
script: npm ci
cache:
key: frontend-deps
paths:
- .npm/
variables:
npm_config_cache: '$CI_PROJECT_DIR/.npm'
build:
stage: build
script: npm run build
artifacts:
paths:
- dist/
test:
stage: test
script: npm test
LimiteValeur
Profondeur child pipelines (parent → child → grandchild)2 niveaux max
Taille de la hiérarchie downstream1000 pipelines par défaut (paramétrable)
Fichiers include par child pipeline3 fichiers max
  1. Toujours strategy: depend sauf si vous voulez explicitement ne pas attendre

  2. Un fichier CI par composant : frontend/.gitlab-ci.yml, backend/.gitlab-ci.yml

  3. Conditions sur les triggers : ne déclenchez que ce qui a changé

  4. Variables explicites : documentez ce que vous passez aux enfants

  5. Nommez clairement : trigger_frontend, trigger_backend, pas job1, job2

Symptôme : Le pipeline parent affiche ✅ success, mais en regardant les détails, l’enfant est en ❌ failed.

Cause : Vous avez oublié strategy: depend.

Solution :

trigger_job:
trigger:
include: child.yml
strategy: depend # 👈 Ajoutez ceci

Symptôme : L’enfant affiche $VERSION littéralement au lieu de la valeur.

Cause : La variable n’est pas passée au trigger.

Solution : Ajoutez-la dans variables: du job trigger :

trigger_job:
variables:
VERSION: $VERSION # 👈 Passez explicitement
trigger:
include: child.yml

Symptôme : GitLab refuse de créer le pipeline.

Cause : Vous avez parent → enfant → petit-enfant → arrière-petit-enfant… GitLab limite à 2 niveaux.

Solution : Restructurez pour avoir au max parent → enfant → petit-enfant.

Symptôme : file not found ou invalid config.

Cause : Le chemin dans include: est incorrect.

Solution : Le chemin est relatif à la racine du repo, pas au fichier parent :

# ❌ Si le parent est dans ci/parent.yml
trigger:
include: ../frontend/.gitlab-ci.yml # NE FONCTIONNE PAS
# ✅ Toujours depuis la racine
trigger:
include: frontend/.gitlab-ci.yml # OK

Symptôme : needs: ["build"] échoue avec “job not found”.

Cause : needs classique ne traverse pas les pipelines.

Solution : Utilisez needs:pipeline:job (voir section Passer des artefacts).

Symptôme : Erreur d’autorisation.

Cause : Le projet source n’autorise pas le projet destination.

Solution : Configurez la Job token scope allowlist côté projet source (Settings → CI/CD → Token access).

  1. trigger: include crée un pipeline enfant à partir d’un fichier local
  2. strategy: depend fait attendre le parent ; mirror pour un reflet strict
  3. variables: passe des variables à l’enfant
  4. Artefacts : utilisez needs:pipeline:job (parent→child) ou needs:project (multi-projet)
  5. trigger: project déclenche un pipeline dans un autre projet
  6. Limite : 2 niveaux de profondeur, 1000 pipelines downstream max
  7. $CI_PIPELINE_SOURCE vaut parent_pipeline dans un child pipeline

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.