
Vous avez travaillé les 11 modules du Volet 2 séparément — templates, DAG, components, services, matrices, pipelines enfants, multi-projet, workflows, fiabilité. Maintenant, assemblez-les. Ce capstone vous plonge dans un scénario réaliste : industrialiser le pipeline d’une équipe qui gère trois microservices, un frontend SPA et une bibliothèque partagée.
L’objectif n’est pas d’apprendre des nouvelles directives, mais de vérifier que toutes les techniques avancées s’imbriquent. Chaque décision renvoie au module concerné.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Combiner templates, DAG, components et matrices dans un pipeline industriel
- Orchestrer des builds multi-services avec pipelines enfants et multi-projet
- Appliquer un workflow adapté (MR + tags) avec fiabilité intégrée
- Diagnostiquer les problèmes d’un pipeline complexe
- Évaluer la maturité industrielle avec une grille de critères
Dans quel contexte ?
Section intitulée « Dans quel contexte ? »Vous êtes DevOps dans une équipe qui gère un produit composé de :
- api-gateway : Go — point d’entrée, routage
- api-users : Python — gestion des utilisateurs
- api-orders : Node.js — gestion des commandes
- frontend : React SPA consommant les 3 APIs
- shared-lib : bibliothèque interne de validation, utilisée par les 3 APIs
Le pipeline actuel ? Un .gitlab-ci.yml de 400 lignes sans templates, tout dupliqué, 25 minutes d’exécution, aucun retry. Votre mission : industrialiser.
Architecture cible
Section intitulée « Architecture cible »Le pipeline cible utilise plusieurs niveaux d’orchestration :
shared-lib (multi-projet) ↓ déclenche les pipelines des consommateursapi-gateway ──┐api-users ────┼── pipeline parent → enfants par serviceapi-orders ───┘frontend ──────── pipeline dédié (déclenché par tag)Principes de conception
Section intitulée « Principes de conception »| Décision | Technique | Module |
|---|---|---|
| Factoriser les jobs communs | Templates + Components | V2-01, V2-03 |
| Paralléliser lint/test/build | DAG (needs:) | V2-02 |
| Tester sur 3 OS / 3 versions | Matrices | V2-04 |
| Builder chaque service séparément | Pipelines enfants | V2-07 |
| Déclencher quand shared-lib change | Multi-projet | V2-09 |
| Exécuter uniquement sur MR + tags | Workflows | V2-10 |
| Absorber les erreurs transitoires | Fiabilité | V2-11 |
Étape 1 — Le component réutilisable
Section intitulée « Étape 1 — Le component réutilisable »Commencez par créer un CI/CD Component pour le pattern commun à tous les services : lint → test → build Docker → push.
spec: inputs: service_name: type: string language: type: string test_command: type: string default: "make test" docker_context: type: string default: "."
---
.lint-$[[ inputs.service_name ]]: stage: lint image: $[[ inputs.language ]]:latest script: - make lint needs: []
.test-$[[ inputs.service_name ]]: stage: test image: $[[ inputs.language ]]:latest services: - postgres:16-alpine variables: POSTGRES_DB: test POSTGRES_USER: test POSTGRES_PASSWORD: test script: - $[[ inputs.test_command ]] needs: [] retry: max: 1 when: - runner_system_failure - stuck_or_timeout_failure
.build-$[[ inputs.service_name ]]: stage: build image: docker:27 services: - docker:27-dind script: - docker build -t $CI_REGISTRY_IMAGE/$[[ inputs.service_name ]]:$CI_COMMIT_SHA -f $[[ inputs.docker_context ]]/Dockerfile $[[ inputs.docker_context ]] - docker push $CI_REGISTRY_IMAGE/$[[ inputs.service_name ]]:$CI_COMMIT_SHA needs: - .test-$[[ inputs.service_name ]] retry: max: 2 when: - runner_system_failure - stuck_or_timeout_failure - unknown_failureLien : V2-03 — Components & Catalog pour la syntaxe spec:inputs et la publication.
Étape 2 — Le pipeline parent
Section intitulée « Étape 2 — Le pipeline parent »Le pipeline parent orchestre : il lance un pipeline enfant par service, en parallèle.
workflow: rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - if: $CI_COMMIT_TAG =~ /^v\d+/
default: interruptible: true retry: max: 1 when: - runner_system_failure - stuck_or_timeout_failure
stages: - trigger - deploy
# ── Pipelines enfants (V2-07) ──────────────────────────────────trigger:api-gateway: stage: trigger trigger: include: services/api-gateway/.gitlab-ci.yml strategy: depend rules: - changes: - services/api-gateway/**/* - shared-lib/**/*
trigger:api-users: stage: trigger trigger: include: services/api-users/.gitlab-ci.yml strategy: depend rules: - changes: - services/api-users/**/* - shared-lib/**/*
trigger:api-orders: stage: trigger trigger: include: services/api-orders/.gitlab-ci.yml strategy: depend rules: - changes: - services/api-orders/**/* - shared-lib/**/*
trigger:frontend: stage: trigger trigger: include: frontend/.gitlab-ci.yml strategy: depend rules: - changes: - frontend/**/*
# ── Déploiement global (après succès des enfants) ──────────────deploy:staging: stage: deploy interruptible: false script: ./deploy.sh staging resource_group: staging environment: name: staging url: https://staging.example.com needs: - trigger:api-gateway - trigger:api-users - trigger:api-orders - trigger:frontend rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
deploy:production: stage: deploy interruptible: false script: ./deploy.sh production --atomic resource_group: production environment: name: production url: https://app.example.com needs: - trigger:api-gateway - trigger:api-users - trigger:api-orders - trigger:frontend rules: - if: $CI_COMMIT_TAG =~ /^v\d+/ when: manualLiens :
trigger: include:avecstrategy: depend→ V2-07 — Parent-enfantrules: changes:→ V2-10 — Workflowsresource_group+interruptible: false→ V2-11 — Fiabilité
Étape 3 — Le pipeline enfant d’un service
Section intitulée « Étape 3 — Le pipeline enfant d’un service »Chaque service a son propre .gitlab-ci.yml qui utilise le component :
include: - component: $CI_SERVER_FQDN/myorg/ci-components/service-pipeline@1.0.0 inputs: service_name: api-users language: python test_command: "pytest --reruns 2" docker_context: "."
stages: - lint - test - build
# Matrice de tests multi-version (V2-04)test:matrix: extends: .test-api-users parallel: matrix: - PYTHON_VERSION: ["3.11", "3.12", "3.13"] image: python:$PYTHON_VERSION timeout: 15 minutes
# Services CI pour les tests d'intégration (V2-06)test:integration: stage: test image: python:3.12 services: - name: postgres:16-alpine alias: db - name: redis:7-alpine alias: cache variables: DATABASE_URL: "postgresql://test:test@db:5432/test" REDIS_URL: "redis://cache:6379" script: - pytest tests/integration/ --reruns 1 needs: [] retry: max: 1 when: - stuck_or_timeout_failureLiens :
- Matrices → V2-04 — Matrices
- Services CI → V2-06 — Services & Cache
Étape 4 — Le déclencheur multi-projet
Section intitulée « Étape 4 — Le déclencheur multi-projet »Quand shared-lib est modifiée, elle doit déclencher le pipeline des services qui l’utilisent :
stages: - test - publish - notify
test: stage: test script: make test
publish: stage: publish script: - make build - twine upload dist/* rules: - if: $CI_COMMIT_TAG =~ /^v\d+/
# ── Déclenchement multi-projet (V2-09) ─────────────────────────notify:api-gateway: stage: notify trigger: project: myorg/api-gateway branch: main strategy: depend variables: SHARED_LIB_VERSION: $CI_COMMIT_TAG rules: - if: $CI_COMMIT_TAG =~ /^v\d+/
notify:api-users: stage: notify trigger: project: myorg/api-users branch: main strategy: depend variables: SHARED_LIB_VERSION: $CI_COMMIT_TAG rules: - if: $CI_COMMIT_TAG =~ /^v\d+/
notify:api-orders: stage: notify trigger: project: myorg/api-orders branch: main strategy: depend variables: SHARED_LIB_VERSION: $CI_COMMIT_TAG rules: - if: $CI_COMMIT_TAG =~ /^v\d+/Lien : V2-09 — Multi-projet pour trigger:project et la propagation de variables.
Étape 5 — Configuration de fiabilité
Section intitulée « Étape 5 — Configuration de fiabilité »Revoyez chaque job avec la grille de fiabilité :
| Vérification | Appliqué ? |
|---|---|
retry:when ciblé (pas always) → V2-11 | ✅ |
| timeout adapté à chaque type de job | ✅ |
| interruptible: true par défaut, false sur deploy | ✅ |
| resource_group sur les déploiements | ✅ |
| Retry framework (pytest —reruns) pour les tests | ✅ |
| Jobs idempotents (noms basés sur $CI_COMMIT_SHA) | ✅ |
| allow_failure sur les scans non bloquants | À ajouter |
Exercice : diagnostiquer un pipeline cassé
Section intitulée « Exercice : diagnostiquer un pipeline cassé »Votre pipeline du capstone échoue. Voici les symptômes — trouvez la cause et la solution pour chacun.
Cas 1 — Le pipeline enfant n’est pas déclenché
Section intitulée « Cas 1 — Le pipeline enfant n’est pas déclenché »trigger:api-users → skippedIndice
Vérifiez la section rules: changes:. Le chemin du fichier modifié correspond-il au pattern ?
Solution
Le fichier modifié est dans services/api-users/src/ mais la règle changes: pointe vers services/api-users/**/*. Vérifiez que le glob couvre bien les sous-dossiers. Si votre commit ne touche que shared-lib/, le trigger api-users ne se lance que si shared-lib/**/* est dans ses changes:.
Cas 2 — La matrice de tests échoue sur une seule version
Section intitulée « Cas 2 — La matrice de tests échoue sur une seule version »test:matrix 3/3 (Python 3.13) → failed (script_failure)test:matrix 1/3 (Python 3.11) → passedtest:matrix 2/3 (Python 3.12) → passedIndice
Ce n’est pas un problème de CI. C’est un problème de compatibilité.
Solution
Vérifiez les dépendances dans requirements.txt : une bibliothèque peut ne pas encore supporter Python 3.13. Utilisez allow_failure temporairement sur cette version pendant la migration :
test:matrix: parallel: matrix: - PYTHON_VERSION: ["3.11", "3.12"] - PYTHON_VERSION: "3.13" ALLOW_FAIL: "true" allow_failure: exit_codes: [1] rules: - if: $ALLOW_FAIL == "true" allow_failure: true - when: on_successCas 3 — Le deploy staging se lance avant la fin des enfants
Section intitulée « Cas 3 — Le deploy staging se lance avant la fin des enfants »deploy:staging → running (alors que trigger:api-orders est encore en cours)Indice
Vérifiez la directive needs: du job de déploiement.
Solution
Sans strategy: depend sur les triggers, le job parent se termine dès que le pipeline enfant est déclenché, pas quand il est terminé. Ajoutez strategy: depend à chaque trigger, et assurez-vous que le deploy a bien needs: sur tous les triggers.
Grille de maturité industrielle
Section intitulée « Grille de maturité industrielle »Évaluez votre pipeline avec cette grille. Chaque critère correspond à un module du Volet 2 :
| Critère | Score | Module |
|---|---|---|
| Templates factorisent au moins 60 % du YAML | /2 | V2-01 |
| DAG activé, durée réduite vs stages linéaires | /2 | V2-02 |
| Au moins 1 CI/CD Component publié | /1 | V2-03 |
| Matrice de tests sur ≥ 2 versions | /1 | V2-04 |
| Services CI avec healthcheck | /1 | V2-06 |
| Pipeline enfant par service (monorepo) | /2 | V2-07 |
| Trigger multi-projet pour les libs partagées | /1 | V2-09 |
| Workflow:rules avec MR + tags | /2 | V2-10 |
| Retry ciblé + timeouts + interruptible | /2 | V2-11 |
| Jobs de deploy idempotents + resource_group | /1 | V2-11 |
Interprétation :
- 12–15 : Pipeline industriel solide, prêt pour la production
- 8–11 : Bonne base, quelques optimisations manquantes
- < 8 : Revoyez les modules où vous avez 0
Auto-évaluation
Section intitulée « Auto-évaluation »Répondez sans regarder les modules. Si vous bloquez, le lien vous renvoie au bon guide.
- Quelle directive remplace
include:pour les composants réutilisables ? (V2-03) - Comment exécuter un job dès que ses dépendances sont finies, sans attendre le stage ? (V2-02)
- Quelle directive empêche deux déploiements de tourner en parallèle ? (V2-11)
- Comment déclencher le pipeline d’un autre projet quand shared-lib change ? (V2-09)
- Quelle section du
.gitlab-ci.ymlempêche les pipelines en double (branche + MR) ? (V2-10) - Quel keyword permet de ne builder que les services dont le code a changé ? (V2-07)
- Comment faire tourner PostgreSQL et Redis comme services dans un job de test ? (V2-06)
- Quel type d’erreur ne devrait jamais être dans
retry:whenpour un job de tests ? (V2-11)
À retenir
Section intitulée « À retenir »- Un pipeline industriel n’est pas un gros fichier — c’est un ensemble orchestré de pipelines factorisés
- Components > templates > copier-coller : factorisez dans cet ordre de préférence
- Les pipelines enfants isolent chaque service : échec local, pas global
- Le multi-projet connecte les dépendances : quand la lib change, les consommateurs re-testent
- La fiabilité se configure partout : retry ciblé, timeout adapté, interruptible sélectif
- Les workflows évitent les doublons :
workflow:rulesest votre garde global - Mesurez la maturité : la grille de critères donne un score objectif
- Le but final : un pipeline qui échoue vite, récupère seul, et déploie en confiance