Aller au contenu
CI/CD & Automatisation medium

Lab 16, Pipelines parent-enfant dynamiques

60 min de lecture

logo gitlab

Un pipeline statique peut devenir coûteux quand il traite tous les cas de la même manière. Dans ce lab, vous introduisez une orchestration parent-enfant pour générer un plan d'exécution dynamique, piloté par un script versionné dans le dépôt.

  • Concevoir une étape d'orchestration dans un pipeline CI
  • Générer dynamiquement un YAML enfant depuis un script shell
  • Déclencher un child pipeline avec trigger et artifact
  • Ajouter une logique contextuelle simple (branche par défaut vs autre branche)

Ce pattern devient utile quand un pipeline doit s'adapter à des changements fréquents de périmètre. Un monolithe CI finit par lancer trop de jobs pour des modifications mineures.

Vous utiliserez cette approche quand :

  • différents services doivent déclencher des sous-pipelines spécialisés ;
  • vous voulez isoler la logique de décision dans un script maintenable ;
  • vous cherchez à réduire le coût CI sans perdre de contrôle.

La branche starter/lab-16 contient déjà le découpage en fichiers ci/*.yml et la matrice du lab précédent. Ne la modifiez pas encore : la baseline poussée à l'étape 3 sert de point de comparaison, vous devez pouvoir constater à la fin que le nombre de jobs exécutés a changé. Si votre glab n'est pas configuré sur le projet, faites-le maintenant, l'étape de validation en dépend.

  1. Basculez sur la branche du lab

    Fenêtre de terminal
    cd pipeline-craft
    git checkout starter/lab-16
  2. Vérifiez la structure existante

    Le pipeline est déjà découpé et matriciel, mais pas encore dynamique.

  3. Lancez une baseline

    Fenêtre de terminal
    git push origin starter/lab-16

Le pipeline actuel exécute toujours la même séquence, même pour des cas simples. Vous allez introduire une orchestration pour produire un sous-plan plus ciblé.

L'orchestration vit dans son propre fichier pour rester lisible, mais surtout parce qu'un job de type trigger ne peut pas coexister avec un script dans la même définition. Vous écrivez donc deux jobs distincts : l'un génère le YAML et le publie en artifact, l'autre le consomme. L'expire_in court n'est pas une coquetterie : un artifact de configuration régénéré à chaque pipeline n'a aucune raison d'occuper le stockage GitLab pendant des semaines.

  1. Créez ci/orchestration.yml

  2. Ajoutez un job generate-child-pipeline

  3. Publiez child-pipeline.yml en artifact

    Indice : utilisez un expire_in court pour cet artifact temporaire.

👉 Vérifier votre solution (Étape 1)
generate-child-pipeline:
stage: orchestrate
image: alpine:3.20@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc
before_script:
- apk add --no-cache bash git
script:
- chmod +x scripts/generate-child-pipeline.sh
- ./scripts/generate-child-pipeline.sh
artifacts:
paths:
- child-pipeline.yml
expire_in: 1 day
run-child-pipeline:
stage: orchestrate
needs:
- generate-child-pipeline
trigger:
include:
- artifact: child-pipeline.yml
job: generate-child-pipeline
strategy: depend
rules:
- if: $CI_PIPELINE_SOURCE == "push"
- if: $CI_PIPELINE_SOURCE == "merge_request_event"

Le script porte toute la logique de décision, et c'est aussi le seul endroit où vous pouvez vous tromper sans que GitLab vous prévienne : un YAML mal indenté sera accepté par le job de génération et rejeté seulement au déclenchement du child pipeline. Écrivez le squelette commun avec un cat en heredoc quoté (<<'YAML'), qui empêche le shell d'interpréter les $ du contenu, puis ajoutez les blocs conditionnels par concaténation.

  1. Créez le script scripts/generate-child-pipeline.sh

    Indice : ce fichier n'existe pas dans le starter, vous devez le créer.

  2. Ajoutez une logique contextuelle

    Exemple : ajouter un job supplémentaire si la branche vaut main.

  3. Vérifiez que le script est exécutable

    Fenêtre de terminal
    chmod +x scripts/generate-child-pipeline.sh
👉 Vérifier votre solution (Étape 2)
#!/usr/bin/env bash
set -euo pipefail
# Dynamic child pipeline used in Lab 16.
# It adapts jobs according to branch context.
cat > child-pipeline.yml <<'YAML'
stages:
- verify
child-smoke:
stage: verify
image: alpine:3.20@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc
script:
- echo "Smoke check in child pipeline"
YAML
if [[ "${CI_COMMIT_BRANCH:-}" == "${CI_DEFAULT_BRANCH:-}" ]]; then
cat >> child-pipeline.yml <<'YAML'
child-default-branch-check:
stage: verify
image: alpine:3.20@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc
script:
- echo "Extra checks on default branch"
YAML
fi
cat child-pipeline.yml

Le job de déclenchement relie l'artifact au pipeline enfant par deux clés qui vont ensemble : artifact désigne le fichier, job désigne le job qui l'a produit. Ces deux clés sont au même niveau d'indentation dans l'élément de liste, une erreur d'un espace ici et GitLab refuse tout le fichier. Le needs garantit par ailleurs que la génération est terminée avant la lecture de l'artifact, y compris si les deux jobs partagent le même stage.

  1. Ajoutez un job run-child-pipeline

  2. Utilisez trigger avec include artifact

    Indice : gardez strategy: depend pour propager l'état du pipeline enfant.

  3. Ajoutez ci/orchestration.yml dans les includes du pipeline racine

👉 Vérifier votre solution (Étape 3)

Le pipeline racine ajoute un stage orchestrate et inclut le fichier d'orchestration.

stages:
- lint
- test
- orchestrate
- build
- deploy
include:
- local: ci/lint.yml
- local: ci/test.yml
- local: ci/build.yml
- local: ci/deploy.yml
- local: ci/orchestration.yml

glab ci lint valide la syntaxe du pipeline racine côté serveur, y compris les include. En revanche, il ne voit pas le child-pipeline.yml, qui n'existe pas encore au moment du lint : le fichier enfant n'est validé qu'à l'exécution réelle. C'est pour cette raison que le lab vous fait pousser puis observer les deux niveaux de pipeline dans l'interface GitLab plutôt que de vous arrêter au lint.

  1. Validez la syntaxe du pipeline racine

    Fenêtre de terminal
    glab ci lint .gitlab-ci.yml
  2. Commit

    Fenêtre de terminal
    git add .gitlab-ci.yml ci/orchestration.yml scripts/generate-child-pipeline.sh
    git commit -m "ci: add dynamic parent-child orchestration"
    git push origin starter/lab-16
  3. Vérifiez les deux niveaux de pipeline dans GitLab

👉 Vérifier votre solution (Étape 4)
  • generate-child-pipeline produit bien child-pipeline.yml en artifact ;
  • run-child-pipeline déclenche le child pipeline via trigger.include.artifact ;
  • le parent attend le résultat enfant (strategy: depend) ;
  • un job supplémentaire apparaît dans le child pipeline sur la branche par défaut.

Les trois blocs repliés ci-dessous donnent l'état final des fichiers touchés par ce lab. Ouvrez-les seulement pour comparer avec votre version : le .gitlab-ci.yml racine ne fait qu'ajouter le stage orchestrate et un include, tout le reste du travail est concentré dans ci/orchestration.yml et le script de génération.

📄 Voir le fichier .gitlab-ci.yml complet
stages:
- lint
- test
- orchestrate
- build
- deploy
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "push"
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_TAG
default:
interruptible: true
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.pip-cache"
include:
- local: ci/lint.yml
- local: ci/test.yml
- local: ci/build.yml
- local: ci/deploy.yml
- local: ci/orchestration.yml
📄 Voir le fichier ci/orchestration.yml complet
generate-child-pipeline:
stage: orchestrate
image: alpine:3.20@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc
before_script:
- apk add --no-cache bash git
script:
- chmod +x scripts/generate-child-pipeline.sh
- ./scripts/generate-child-pipeline.sh
artifacts:
paths:
- child-pipeline.yml
expire_in: 1 day
run-child-pipeline:
stage: orchestrate
needs:
- generate-child-pipeline
trigger:
include:
- artifact: child-pipeline.yml
job: generate-child-pipeline
strategy: depend
rules:
- if: $CI_PIPELINE_SOURCE == "push"
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
📄 Voir le fichier scripts/generate-child-pipeline.sh complet
#!/usr/bin/env bash
set -euo pipefail
# Dynamic child pipeline used in Lab 16.
# It adapts jobs according to branch context.
cat > child-pipeline.yml <<'YAML'
stages:
- verify
child-smoke:
stage: verify
image: alpine:3.20@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc
script:
- echo "Smoke check in child pipeline"
YAML
if [[ "${CI_COMMIT_BRANCH:-}" == "${CI_DEFAULT_BRANCH:-}" ]]; then
cat >> child-pipeline.yml <<'YAML'
child-default-branch-check:
stage: verify
image: alpine:3.20@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc
script:
- echo "Extra checks on default branch"
YAML
fi
cat child-pipeline.yml

Le lab est réussi quand vous voyez deux pipelines dans l'interface, le parent avec un job run-child-pipeline marqué comme déclencheur, et l'enfant avec ses propres jobs. Le dernier point de la liste est le plus discriminant : poussez une fois sur starter/lab-16 et une fois sur la branche par défaut, et comparez le nombre de jobs du pipeline enfant. S'il est identique, c'est que la condition sur CI_COMMIT_BRANCH n'a pas été évaluée comme prévu.

  • ci/orchestration.yml existe et est inclus dans le pipeline racine
  • child-pipeline.yml est généré puis consommé via artifact
  • Le child pipeline se déclenche correctement
  • Le comportement varie selon le contexte défini

Un child pipeline échoue souvent pour une raison simple : YAML généré invalide. Ajoutez un cat child-pipeline.yml dans le job de génération pour faciliter le debug.

Autre point important : sans strategy: depend, le parent peut se terminer sans attendre le résultat réel du child.

  • Le parent-enfant sépare orchestration et exécution métier
  • Un script versionné permet une logique dynamique contrôlée
  • Les artifacts servent de transport de configuration entre jobs
  • Un pipeline dynamique reste auditable s'il est lisible et traçable
  • Multi-projet : Étendre la logique de déclenchement au-delà du dépôt, vers des pipelines d'autres projets.
  • Workflows CI/CD : Choisir quel pipeline enfant doit être généré selon la branche, la merge request ou le tag.
  • Lab 17, workflows branches et MR : Éviter le pipeline en double sur une merge request quand la génération est dynamique.

Ce site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn