Date de publication : 6 mai 2026
Temps de lecture : 16 min
Découvrez comment faire évoluer votre approche CI/CD avec des modèles composables pour les monorepos, les microservices, les environnements et la gouvernance.

La plupart des outils CI/CD savent exécuter un build et lancer un déploiement. La différence se fait lorsque vos besoins de livraison deviennent concrets : un monorepo avec une dizaine de services, des microservices répartis sur plusieurs dépôts, des déploiements vers des dizaines d'environnements, ou une équipe plateforme qui cherche à appliquer des normes sans devenir un goulot d'étranglement.
Le modèle d'exécution de pipelines de GitLab a été conçu pour cette complexité. Les pipelines parent-enfant, l'exécution du graphe orienté acyclique (DAG), la génération dynamique de pipelines, les déclencheurs multi-projets, les pipelines de merge request avec résultats fusionnés et les composants CI/CD répondent chacun à une catégorie distincte de problèmes. Parce qu'ils se combinent entre eux, la compréhension du modèle complet offre bien plus qu'une accélération du pipeline. Dans cet article, vous découvrirez cinq modèles dans lesquels les pipelines se distinguent, chacun associé à un scénario d'ingénierie concret avec la configuration correspondante.
Les configurations ci-dessous sont fournies à titre illustratif. Les scripts utilisent des commandes echo pour maintenir un rapport signal/bruit faible. Remplacez-les par vos véritables étapes de build, de test et de déploiement pour qu'elles soient prêtes à l'emploi.
Le problème : votre monorepo contient un frontend, un backend et un site de documentation. Chaque commit déclenche une reconstruction complète de l'ensemble, même lorsque seul un fichier README a été modifié.
GitLab résout ce problème grâce à deux fonctionnalités complémentaires : les pipelines parent-enfant (qui permettent à un pipeline de niveau supérieur de créer des sous-pipelines isolés) et l'exécution du DAG via needs (qui rompt le classement rigide étape par étape et permet aux jobs de démarrer dès que leurs dépendances sont terminées).
Un pipeline parent détecte les modifications et ne déclenche que les pipelines enfants concernés :
# .gitlab-ci.yml
stages:
- trigger
trigger-services:
stage: trigger
trigger:
include:
- local: '.gitlab/ci/api-service.yml'
- local: '.gitlab/ci/web-service.yml'
- local: '.gitlab/ci/worker-service.yml'
strategy: depend
Chaque pipeline enfant est entièrement indépendant avec ses propres étapes, jobs et artefacts. Le pipeline parent attend la fin de l'ensemble via strategy: depend, ce qui vous donne un signal vert/rouge unique au niveau supérieur, avec une vue détaillée de chaque pipeline de service. Cette séparation organisationnelle est le gain le plus important pour les grandes équipes : chaque service est propriétaire de sa configuration de pipeline, les modifications d'une configuration n'entraînent pas l'échec d'une autre, et la complexité reste gérable à mesure que le dépôt grandit.
Un point important : lorsque vous transmettez plusieurs fichiers à un même trigger: include:, GitLab les fusionne dans une seule configuration de pipeline enfant. Cela signifie que les jobs définis dans ces fichiers partagent le même contexte de pipeline et peuvent se référencer mutuellement avec needs:, ce qui rend l'optimisation du DAG possible. Si vous les séparez dans des jobs de déclenchement distincts, chaque fichier constituerait son propre pipeline isolé, et les références needs: entre fichiers ne fonctionneraient pas.
Combinez cette approche avec needs: à l'intérieur de chaque pipeline enfant pour exécuter le DAG. Vos tests d'intégration peuvent démarrer dès que le build est terminé, sans attendre les autres jobs de la même étape.
# .gitlab/ci/api-service.yml
stages:
- build
- test
build-api:
stage: build
script:
- echo "Building API service"
test-api:
stage: test
needs: [build-api]
script:
- echo "Running API tests"
Pourquoi c'est important : les équipes qui disposent de monorepos volumineux constatent généralement des réductions significatives du temps d'exécution des pipelines après le passage à l'exécution du DAG, car les jobs n'attendent plus des tâches sans rapport dans la même étape. Les pipelines parent-enfant constituent la couche organisationnelle qui facilite la gestion de la configuration à mesure que le dépôt et l'équipe grandissent.
Pipelines downstream locaux
Le problème : votre frontend se trouve dans un dépôt, et votre backend dans un autre. Lorsque l'équipe frontend livre une modification, elle n'a aucune visibilité sur les éventuelles défaillances du backend, et inversement.
Les pipelines multi-projets de GitLab permettent à un projet de déclencher un pipeline dans un projet totalement distinct et d'en attendre le résultat. Le projet déclencheur obtient un pipeline downstream lié directement dans sa propre vue de pipeline.
Le pipeline frontend construit un artefact de contrat d'API et le publie, puis déclenche le pipeline backend. Le backend récupère cet artefact directement via l'API Jobs et le valide avant de poursuivre. Si une modification incompatible est détectée, le pipeline backend échoue, tout comme le pipeline frontend.
# frontend repo: .gitlab-ci.yml
stages:
- build
- test
- trigger-backend
build-frontend:
stage: build
script:
- echo "Building frontend and generating API contract..."
- mkdir -p dist
- |
echo '{
"api_version": "v2",
"breaking_changes": false
}' > dist/api-contract.json
- cat dist/api-contract.json
artifacts:
paths:
- dist/api-contract.json
expire_in: 1 hour
test-frontend:
stage: test
script:
- echo "All frontend tests passed!"
trigger-backend-pipeline:
stage: trigger-backend
trigger:
project: my-org/backend-service
branch: main
strategy: depend
rules:
- if: $CI_COMMIT_BRANCH == "main"
# backend repo: .gitlab-ci.yml
stages:
- build
- test
build-backend:
stage: build
script:
- echo "All backend tests passed!"
integration-test:
stage: test
rules:
- if: $CI_PIPELINE_SOURCE == "pipeline"
script:
- echo "Fetching API contract from frontend..."
- |
curl --silent --fail \
--header "JOB-TOKEN: $CI_JOB_TOKEN" \
--output api-contract.json \
"${CI_API_V4_URL}/projects/${FRONTEND_PROJECT_ID}/jobs/artifacts/main/raw/dist/api-contract.json?job=build-frontend"
- cat api-contract.json
- |
if grep -q '"breaking_changes": true' api-contract.json; then
echo "FAIL: Breaking API changes detected - backend integration blocked!"
exit 1
fi
echo "PASS: API contract is compatible!"
Quelques points à noter dans cette configuration. Le job integration-test utilise $CI_PIPELINE_SOURCE == "pipeline" pour s'assurer qu'il ne s'exécute que lorsqu'il est déclenché par un pipeline amont, et non lors d'un push direct sur le dépôt backend. L'identifiant du projet frontend est référencé via $FRONTEND_PROJECT_ID, qui doit être défini comme variable CI/CD dans les paramètres du projet backend afin d'éviter de le coder en dur.
Pourquoi c'est important : les échecs inter-services qui ne se manifestaient auparavant qu'en production sont désormais détectés dans le pipeline. La dépendance entre services, auparavant invisible, devient visible, traçable et corrigeable.
Pipelines multi-projets
Le problème : vous déployez la même application vers 15 environnements clients, trois régions cloud ou encore des environnements de développement/préproduction/production. Mettre à jour une étape de déploiement sur l'ensemble de ces environnements un par un entraîne une dérive de configuration, tandis que créer un pipeline distinct pour chaque environnement est impossible à maintenir.
Les pipelines enfants dynamiques de GitLab permettent de générer un pipeline au moment de l'exécution. Un job exécute un script qui produit un fichier YAML, qui devient le pipeline de l'étape suivante. La structure même du pipeline devient une donnée.
# .gitlab-ci.yml
stages:
- generate
- trigger-environments
generate-config:
stage: generate
script:
- |
# ENVIRONMENTS can be passed as a CI variable or read from a config file.
# Default to dev, staging, prod if not set.
ENVIRONMENTS=${ENVIRONMENTS:-"dev staging prod"}
for ENV in $ENVIRONMENTS; do
cat > ${ENV}-pipeline.yml << EOF
stages:
- deploy
- verify
deploy-${ENV}:
stage: deploy
script:
- echo "Deploying to ${ENV} environment"
verify-${ENV}:
stage: verify
script:
- echo "Running smoke tests on ${ENV}"
EOF
done
artifacts:
paths:
- "*.yml"
exclude:
- ".gitlab-ci.yml"
.trigger-template:
stage: trigger-environments
trigger:
strategy: depend
trigger-dev:
extends: .trigger-template
trigger:
include:
- artifact: dev-pipeline.yml
job: generate-config
trigger-staging:
extends: .trigger-template
needs: [trigger-dev]
trigger:
include:
- artifact: staging-pipeline.yml
job: generate-config
trigger-prod:
extends: .trigger-template
needs: [trigger-staging]
trigger:
include:
- artifact: prod-pipeline.yml
job: generate-config
when: manual
Le script de génération parcourt une variable ENVIRONMENTS plutôt que de coder en dur chaque environnement séparément. Transmettez une liste différente via une variable CI ou lisez-la depuis un fichier de configuration, et le pipeline s'adapte sans toucher au fichier YAML. Les jobs de déclenchement utilisent extends: pour hériter de la configuration partagée de .trigger-template, de sorte que strategy: depend est défini une seule fois au lieu d'être répété sur chaque job de déclenchement. Pour ajouter un nouvel environnement, il suffit de mettre à jour la variable, sans dupliquer la configuration du pipeline. Ajoutez when: manual au déclencheur de production pour obtenir une porte de validation intégrée directement dans le graphe du pipeline.
Pourquoi c'est important : les entreprises SaaS et les équipes plateforme utilisent ce modèle pour gérer des dizaines d'environnements sans dupliquer la logique de pipeline. La structure du pipeline elle-même reste simple à mesure que la matrice de déploiement évolue.
Pipeline dynamique
Le problème : votre pipeline s'exécute à chaque push sur chaque branche. Des tests coûteux s'exécutent sur des branches de fonctionnalité qui ne seront jamais fusionnées. Parallèlement, vous n'avez aucune garantie que ce que vous avez testé correspond réellement à ce qui arrivera sur la branche main après le merge.
GitLab propose trois fonctionnalités imbriquées qui résolvent ensemble ce problème :
$CI_OPEN_MERGE_REQUESTS ci-dessous empêche le déclenchement simultané de pipelines en double pour une branche et sa merge request ouverte.Avec ces trois fonctionnalités combinées, voici à quoi ressemble un pipeline à niveaux :
# .gitlab-ci.yml
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
- if: $CI_COMMIT_BRANCH
- if: $CI_PIPELINE_SOURCE == "schedule"
stages:
- fast-checks
- expensive-tests
- deploy
lint-code:
stage: fast-checks
script:
- echo "Running linter"
rules:
- if: $CI_PIPELINE_SOURCE == "push"
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
unit-tests:
stage: fast-checks
script:
- echo "Running unit tests"
rules:
- if: $CI_PIPELINE_SOURCE == "push"
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
integration-tests:
stage: expensive-tests
script:
- echo "Running integration tests (15 min)"
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
e2e-tests:
stage: expensive-tests
script:
- echo "Running E2E tests (30 min)"
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
nightly-comprehensive-scan:
stage: expensive-tests
script:
- echo "Running full nightly suite (2 hours)"
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
deploy-production:
stage: deploy
script:
- echo "Deploying to production"
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual
Avec cette configuration, le pipeline se comporte différemment selon le contexte. Un push vers une branche de fonctionnalité sans merge request ouverte n'exécute que l’analyse du code et les tests unitaires. Dès qu'une merge request est ouverte, les règles de workflow passent d'un pipeline de branche à un pipeline de merge request, et la suite complète d'intégration et de tests de bout en bout s'exécute sur le résultat fusionné. Le merge vers la branche main met en file d'attente un déploiement en production manuel. Une planification nocturne exécute le scan complet une seule fois, et non à chaque commit.
Pourquoi c'est important : les équipes réduisent leurs coûts CI de manière significative avec ce modèle, non pas en exécutant moins de tests, mais en exécutant les bons tests au bon moment. Les pipelines à résultats fusionnés détectent les bogues qui n'apparaissent qu'après un merge, avant même qu'ils n'atteignent la branche main.
Pipelines conditionnels (dans une branche sans merge request)
Pipelines conditionnels (dans une merge request)
Pipelines conditionnels (branche principale)
Le problème : votre équipe plateforme a défini la bonne manière de compiler, tester et déployer. Mais chaque équipe possède son propre fichier .gitlab-ci.yml avec des variations subtiles. Les scans de sécurité sont ignorés. Les normes de déploiement subissent des dérives de configuration. Les audits deviennent trop complexes.
Les composants CI/CD de GitLab permettent aux équipes plateforme de publier des composants de pipeline versionnés et réutilisables. Les équipes applicatives les utilisent avec une seule ligne include: et des paramètres facultatifs : pas de copier-coller, pas de dérive. Les composants sont consultables via le catalogue CI/CD, ce qui permet aux équipes de trouver et d'adopter des composants approuvés sans avoir à passer par l'équipe plateforme.
Voici la définition d'un composant issu d'une bibliothèque partagée :
# templates/deploy.yml
spec:
inputs:
stage:
default: deploy
environment:
default: production
---
deploy-job:
stage: $[[ inputs.stage ]]
script:
- echo "Deploying $APP_NAME to $[[ inputs.environment ]]"
- echo "Deploy URL: $DEPLOY_URL"
environment:
name: $[[ inputs.environment ]]
Et voici comment une équipe applicative l'utilise :
# Application repo: .gitlab-ci.yml
variables:
APP_NAME: "my-awesome-app"
DEPLOY_URL: "https://api.example.com"
include:
- component: gitlab.com/my-org/component-library/[email protected]
- component: gitlab.com/my-org/component-library/[email protected]
- component: gitlab.com/my-org/component-library/[email protected]
inputs:
environment: staging
stages:
- build
- test
- deploy
Trois lignes include: remplacent des centaines de lignes de fichier YAML dupliqué. L'équipe plateforme peut déployer un correctif de sécurité dans la version v1.0.7 et les équipes l'adoptent à leur propre rythme, ou l'équipe plateforme peut imposer une version minimale à tous. Dans les deux cas, une seule modification se propage partout au lieu de devoir être appliquée dépôt par dépôt.
Associez cette approche aux groupes de ressources pour empêcher les déploiements simultanés vers le même environnement, et aux environnements protégés pour appliquer des portes d'approbation, et vous obtenez une plateforme de livraison gouvernée où la conformité est la norme, et non l'exception.
Pourquoi c'est important : c'est le modèle qui permet à GitLab CI/CD d'évoluer pour être appliqué par des centaines d'équipes. Les équipes d'ingénierie de plateforme appliquent la conformité sans devenir un goulot d'étranglement. Les équipes applicatives obtiennent un chemin rapide vers un pipeline fonctionnel sans avoir à tout recommencer.
Pipeline avec composants (jobs importés)
Aucune de ces fonctionnalités n'existe de manière isolée. L'intérêt du modèle de pipeline de GitLab réside dans le fait que ces éléments fondamentaux se combinent entre eux :
La plupart des équipes découvrent l'une de ces fonctionnalités lorsqu'elles rencontrent un point de friction spécifique. Celles qui investissent dans la compréhension du modèle complet obtiennent un système de livraison qui reflète réellement le fonctionnement de leur organisation d'ingénierie, et non un pipeline qui le freine.
Les cinq modèles ci-dessus couvrent les points de friction structurels les plus courants, mais le modèle de pipeline de GitLab va plus loin. Voici quelques pistes supplémentaires à mesure que vos besoins évoluent :
cache: autour des fichiers de verrouillage des dépendances et faire preuve de rigueur sur ce qui est transmis entre les jobs avec artefacts: peut faire une différence significative sans modifier la forme de votre pipeline.$CI_PIPELINE_SOURCE qui achemine les bons jobs selon le contexte.La livraison logicielle moderne est complexe. Les équipes gèrent des monorepos avec des dizaines de services, coordonnent leurs efforts entre plusieurs dépôts, déploient vers de nombreux environnements simultanément et cherchent à maintenir la cohérence des normes à mesure que les organisations évoluent. Le modèle de pipeline de GitLab a été conçu avec tous ces enjeux à l'esprit.
Il vaut la peine d'investir dans le modèle de pipeline de GitLab, car ses différents éléments s'articulent particulièrement bien entre eux. Les pipelines parent-enfant apportent une certaine structure aux codes sources volumineux. Les pipelines multi-projets donnent davantage de visibilité aux dépendances inter-équipes et permettent de les tester. Les pipelines dynamiques transforment la gestion des environnements en un processus aisément évolutif. La livraison axée sur les merge requests avec résultats fusionnés garantit la confiance à chaque étape du processus de revue. Et les composants CI/CD offrent aux équipes plateforme un moyen de partager les bonnes pratiques dans toute l'organisation sans devenir un goulot d'étranglement.
Chacune de ces fonctionnalités est puissante individuellement, et encore plus lorsqu'elles sont combinées. GitLab vous fournit les composants nécessaires pour concevoir un système de livraison adapté au fonctionnement réel de votre équipe, et qui évolue avec vos besoins.
Démarrez un essai gratuit de GitLab Ultimate pour exploiter la logique des pipelines dès aujourd'hui.
Cet article de blog vous a plu ? Vous avez des questions ou des retours à nous faire ? Donnez votre avis en créant un nouveau sujet sur le forum de la communauté GitLab.
Faites-nous part de vos commentaires