
Votre YAML est plus propre depuis le lab précédent, mais il reste concentré dans un seul fichier. Dès que plusieurs équipes ou projets doivent partager la même base CI, cette approche atteint ses limites. Dans ce lab, vous passez d’un pipeline DRY local à une structure modulaire avec include: local.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Structurer un pipeline en plusieurs fichiers CI cohérents
- Utiliser
include: localpour charger des templates internes au repo - Réduire la taille du fichier racine sans perdre en lisibilité
- Préparer une future mutualisation vers
include: project
Dans quel contexte ?
Section intitulée « Dans quel contexte ? »Ce refactoring intervient quand un pipeline devient une base partagée. Tant que vous êtes seul sur un projet, un gros .gitlab-ci.yml reste gérable. Quand plusieurs services veulent réutiliser les mêmes patterns (lint, test, build, deploy), le fichier unique devient un goulot de maintenance.
Ce lab sert dans des situations concrètes :
- vous maintenez plusieurs microservices avec une CI très proche ;
- votre équipe veut isoler les responsabilités par fichier ;
- vous préparez une industrialisation vers un dépôt de templates commun.
Prérequis
Section intitulée « Prérequis »- Lab 13 — Éliminer le copier-coller YAML terminé
- Avoir lu Templates CI/CD
Point de départ
Section intitulée « Point de départ »-
Basculez sur la branche de travail
Fenêtre de terminal cd pipeline-craftgit checkout starter/lab-14 -
Ouvrez le pipeline racine
Vérifiez que la majorité des jobs est encore dans
.gitlab-ci.yml. -
Lancez un run baseline
Fenêtre de terminal git push origin starter/lab-14
Le problème
Section intitulée « Le problème »Un fichier unique rallonge les reviews, augmente le risque de conflit Git et rend la réutilisation difficile. Vous devez découper sans casser la logique d’exécution.
L’exercice
Section intitulée « L’exercice »Étape 1 — Créer les fichiers de templates
Section intitulée « Étape 1 — Créer les fichiers de templates »-
Créez le dossier CI si nécessaire
Fenêtre de terminal mkdir -p ci -
Créez les fichiers de base
Fenêtre de terminal touch ci/lint.yml ci/test.yml ci/build.yml ci/deploy.yml -
Déplacez les jobs vers leur fichier logique
Indice : gardez les jobs Python ensemble, et les jobs Docker/deploy dans leurs fichiers dédiés.
👉 Vérifier votre solution (Étape 1)
1️⃣ Répartition des jobs par fichier
Section intitulée « 1️⃣ Répartition des jobs par fichier »Répartition attendue :
ci/lint.yml:.python-baseetruff-lintci/test.yml:pytestci/build.yml:.docker-varsetdocker-buildci/deploy.yml:deploy-stagingetdeploy-production
Extrait clé pour ci/lint.yml :
.python-base: image: python:3.12-slim cache: key: files: - requirements-dev.txt paths: - .pip-cache/
ruff-lint: extends: .python-base stage: lint cache: policy: pull before_script: - pip install ruff script: - ruff check app/ tests/Étape 2 — Transformer le fichier racine en orchestrateur
Section intitulée « Étape 2 — Transformer le fichier racine en orchestrateur »-
Gardez uniquement le squelette global
Indice : conservez
stages,workflow,default,variables. -
Ajoutez les includes locaux
Indice : un include par fichier, avec des chemins relatifs à la racine du dépôt.
-
Conservez les blocs globaux pertinents
Par exemple
workflow,default,variables.
👉 Vérifier votre solution (Étape 2)
1️⃣ .gitlab-ci.yml devient l’orchestrateur
Section intitulée « 1️⃣ .gitlab-ci.yml devient l’orchestrateur »Le fichier racine final ne contient plus les jobs, uniquement l’orchestration globale et les includes.
stages: - lint - test - 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Étape 3 — Valider puis pousser
Section intitulée « Étape 3 — Valider puis pousser »-
Validez la configuration
Fenêtre de terminal glab ci lint .gitlab-ci.yml -
Committez les fichiers extraits
Fenêtre de terminal git add .gitlab-ci.yml ci/git commit -m "ci: split monolithic pipeline into local templates"git push origin starter/lab-14 -
Vérifiez que le pipeline reste vert
Le résultat fonctionnel doit être identique à la baseline.
👉 Vérifier votre solution (Étape 3)
1️⃣ Contrôles de non-régression
Section intitulée « 1️⃣ Contrôles de non-régression »Après découpage, vous devez conserver :
- les mêmes stages (
lint,test,build,deploy) ; - les mêmes scripts de jobs ;
- les mêmes règles de déploiement (
default branch,manualpour prod) ; - les mêmes artefacts de test (
report.xml).
Si le pipeline change de comportement, le découpage n’est pas encore fidèle.
Le fichier complet
Section intitulée « Le fichier complet »📄 Voir le fichier .gitlab-ci.yml complet
stages: - lint - test - 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📄 Voir le fichier ci/lint.yml complet
.python-base: image: python:3.12-slim cache: key: files: - requirements-dev.txt paths: - .pip-cache/
ruff-lint: extends: .python-base stage: lint cache: policy: pull before_script: - pip install ruff script: - ruff check app/ tests/📄 Voir le fichier ci/test.yml complet
pytest: extends: .python-base stage: test needs: [] before_script: - pip install -r requirements-dev.txt script: - pytest -v --junitxml=report.xml --cov=app --cov-report=term-missing coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/' artifacts: when: always paths: - report.xml reports: junit: report.xml expire_in: 7 days📄 Voir le fichier ci/build.yml complet
.docker-vars: &docker_vars DOCKER_TLS_CERTDIR: "/certs"
docker-build: stage: build image: docker:27 services: - docker:27-dind variables: <<: *docker_vars script: - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA . - docker build -t $CI_REGISTRY_IMAGE:latest . - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA - docker push $CI_REGISTRY_IMAGE:latest📄 Voir le fichier ci/deploy.yml complet
deploy-staging: stage: deploy image: alpine:3.20 script: - echo "Deploying $CI_COMMIT_SHORT_SHA to staging..." - ./scripts/deploy-demo.sh staging rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
deploy-production: stage: deploy image: alpine:3.20 script: - echo "Deploying $CI_COMMIT_SHORT_SHA to production..." - ./scripts/deploy-demo.sh production rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH when: manualVérification
Section intitulée « Vérification »-
.gitlab-ci.ymlest un orchestrateur lisible - Les jobs sont répartis dans
ci/lint.yml,ci/test.yml,ci/build.yml,ci/deploy.yml - Les includes locaux se résolvent sans erreur
- Le pipeline garde le même comportement global
Pièges fréquents
Section intitulée « Pièges fréquents »L’erreur la plus courante est un mauvais chemin dans include: local:. Le chemin est relatif à la racine du dépôt, pas au fichier courant.
Autre piège : déplacer des anchors YAML vers un autre fichier en supposant qu’elles restent visibles partout. Les anchors sont souvent limitées au contexte du fichier évalué.
À retenir
Section intitulée « À retenir »- Un pipeline modulaire est plus simple à maintenir qu’un monolithe YAML
include: localest la première étape vers la réutilisation multi-projets- Le fichier racine doit rester un point d’orchestration, pas un dump de jobs
- Découper ne doit pas changer le comportement métier du pipeline