
Votre équipe a une API Python, des tests, un Dockerfile — mais aucun pipeline CI/CD. Les développeurs lancent pytest à la main (quand ils y pensent), personne ne lint le code, et le docker build ne tourne que sur la machine de celui qui déploie. Résultat : des bugs détectés en production, du code inconsistant, et un Dockerfile cassé que personne ne remarque pendant des semaines. Dans ce premier lab, vous allez écrire un .gitlab-ci.yml qui automatise ces trois vérifications dans un pipeline GitLab.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Écrire un
.gitlab-ci.ymlavec des stages, des jobs et une image Docker - Lancer du lint, des tests et un build Docker dans un pipeline automatisé
- Naviguer dans l’interface GitLab pour voir le pipeline, les jobs et les logs
- Comprendre ce qui se passe quand GitLab exécute un job (runner, conteneur, script)
Dans quel contexte ?
Section intitulée « Dans quel contexte ? »En entreprise, la plupart des projets commencent sans CI/CD. Quelqu’un crée un dépôt Git, l’équipe pousse du code, et les vérifications se font « à la main » — quand elles se font. Le jour où un bug passe en production parce que personne n’a lancé les tests, on se dit qu’il faudrait automatiser. Ce lab vous met exactement dans cette situation.
Situations réelles où ce lab vous aide :
- Vous rejoignez un projet qui n’a aucun pipeline et on vous demande d’en créer un
- Votre équipe perd du temps à lancer
pytestetruffmanuellement avant chaque merge - Le
docker buildcasse régulièrement mais personne ne s’en rend compte avant la mise en production - Vous voulez comprendre ce qu’il y a derrière le bouton « Pipelines » de GitLab avant d’aller plus loin
Prérequis
Section intitulée « Prérequis »- Un compte gitlab.com (gratuit)
- Connaître les bases de Git (clone, commit, push)
- Savoir lire du YAML (indentation, clés-valeurs)
- Avoir lu Premiers pas avec GitLab CI/CD (conseillé)
Point de départ
Section intitulée « Point de départ »-
Forkez le dépôt (une seule fois)
Un fork, c’est une copie complète d’un projet GitLab sur votre propre compte. Vous obtenez votre propre version du dépôt, avec vos propres pipelines — sans risque de modifier le projet original.
Rendez-vous sur gitlab.com/Bob74/pipeline-craft et cliquez sur Fork en haut à droite. Gardez les paramètres par défaut et confirmez. Vous obtenez votre copie personnelle à l’adresse
gitlab.com/<votre-pseudo>/pipeline-craft. -
Clonez votre fork sur votre machine (une seule fois)
Fenêtre de terminal # Remplacez <votre-pseudo> par votre nom d'utilisateur GitLabgit clone https://gitlab.com/<votre-pseudo>/pipeline-craft.gitcd pipeline-craftVous avez maintenant le projet en local. Toutes les branches des labs sont incluses.
-
Passez sur la branche de départ de ce lab
Fenêtre de terminal git checkout starter/lab-01Cette branche contient le code Python complet (l’API, les tests, le Dockerfile) mais aucun fichier
.gitlab-ci.yml. C’est vous qui allez le créer. -
Vérifiez sur GitLab
Dans votre fork sur gitlab.com, allez dans Build > Pipelines. La page est vide — aucun pipeline ne s’est jamais exécuté. Normal : sans
.gitlab-ci.yml, GitLab ne sait pas quoi faire.
Le problème
Section intitulée « Le problème »Sans fichier .gitlab-ci.yml, GitLab ne sait pas quoi faire de votre code. Vous pouvez pousser autant de commits que vous voulez — rien ne sera vérifié automatiquement :
- Le code pourrait contenir des erreurs de style que
ruffdétecterait - Les tests pourraient échouer sans que personne ne le sache
- Le Dockerfile pourrait être cassé depuis des semaines
L’objectif : écrire un pipeline qui lance automatiquement le lint, les tests et le build Docker à chaque push.
L’exercice
Section intitulée « L’exercice »Vous allez créer un fichier .gitlab-ci.yml à la racine du projet avec 3 stages et 3 jobs.
Comprendre la structure
Section intitulée « Comprendre la structure »Un pipeline GitLab est défini par un fichier YAML qui décrit :
| Concept | Rôle | Exemple |
|---|---|---|
| stage | Étape du pipeline — les stages s’exécutent dans l’ordre | lint, test, build |
| job | Tâche concrète — tourne dans un conteneur Docker | ruff-lint, pytest, docker-build |
| image | Image Docker utilisée pour exécuter le job | python:3.12-slim |
| script | Commandes exécutées dans le job | pip install, pytest |
Pipeline├── Stage: lint│ └── Job: ruff-lint (image: python:3.12-slim)├── Stage: test│ └── Job: pytest (image: python:3.12-slim)└── Stage: build └── Job: docker-build (image: docker:27)Écrire le pipeline
Section intitulée « Écrire le pipeline »-
Créez le fichier
.gitlab-ci.ymlà la racine du projetstages:- lint- test- buildCette première section déclare les 3 étapes du pipeline, dans l’ordre d’exécution. Tous les jobs du stage
lints’exécutent d’abord, puis ceux detest, puisbuild. -
Ajoutez le job de lint
ruff-lint:stage: lintimage: python:3.12-slimbefore_script:- pip install ruffscript:- ruff check app/ tests/Ce job :
- S’exécute dans le stage
lint - Utilise l’image Docker
python:3.12-slim(légère, ~150 Mo) - Installe
ruffvia pip avant d’exécuter le script - Lance
ruff checksur le code source et les tests
- S’exécute dans le stage
-
Ajoutez le job de tests
pytest:stage: testimage: python:3.12-slimbefore_script:- pip install -r requirements-dev.txtscript:- pytest -vCe job installe toutes les dépendances de développement (qui incluent
pytest,httpxetruff), puis lance les 6 tests du projet. -
Ajoutez le job de build Docker
docker-build:stage: buildimage: docker:27services:- docker:27-dindvariables:DOCKER_TLS_CERTDIR: "/certs"script:- docker build -t pipeline-craft:test .Ce job est différent des deux précédents et mérite une explication.
Chaque job GitLab CI tourne dans un conteneur Docker. Or, ce job doit lui-même construire une image Docker avec
docker build. On se retrouve donc à lancer Docker… à l’intérieur d’un conteneur Docker. C’est ce qu’on appelle Docker-in-Docker (DinD).Concrètement, voici ce qui se passe :
- L’image
docker:27fournit le client Docker (la commandedocker) - Le service
docker:27-dinddémarre un daemon Docker séparé dans un conteneur annexe — c’est lui qui exécute réellement le build - Le client communique avec ce daemon via un réseau interne sécurisé par TLS (d’où la variable
DOCKER_TLS_CERTDIR)
Vous n’avez pas besoin de maîtriser le fonctionnement interne de DinD pour l’utiliser. Retenez simplement que ces trois lignes (
image,services,variables) forment un bloc indissociable quand vous voulez construire des images Docker dans un pipeline GitLab. - L’image
-
Committez et poussez
Fenêtre de terminal git add .gitlab-ci.ymlgit commit -m "ci: add initial pipeline with lint, test and build"git push origin starter/lab-01
Le fichier complet
Section intitulée « Le fichier complet »Voici le .gitlab-ci.yml complet que vous devez obtenir :
stages: - lint - test - build
ruff-lint: stage: lint image: python:3.12-slim before_script: - pip install ruff script: - ruff check app/ tests/
pytest: stage: test image: python:3.12-slim before_script: - pip install -r requirements-dev.txt script: - pytest -v
docker-build: stage: build image: docker:27 services: - docker:27-dind variables: DOCKER_TLS_CERTDIR: "/certs" script: - docker build -t pipeline-craft:test .Vérification
Section intitulée « Vérification »Après le push, allez dans Build > Pipelines sur GitLab. Vous devez voir :
- Un pipeline avec 3 stages visibles dans le graphe
- Le job
ruff-lintau vert dans le stagelint - Le job
pytestau vert dans le stagetest— les 6 tests passent - Le job
docker-buildau vert dans le stagebuild - Le pipeline global affiche un badge vert ✅
Cliquez sur chaque job pour voir ses logs :
- ruff-lint : doit afficher
All checks passed! - pytest : doit afficher
6 passed - docker-build : doit afficher
Successfully builtà la fin
Ce qui a changé
Section intitulée « Ce qui a changé »Un seul fichier a été ajouté :
.gitlab-ci.yml (nouveau — 30 lignes)Ce fichier suffit pour que GitLab exécute automatiquement le lint, les tests et le build à chaque push sur n’importe quelle branche.
Ce qui se passe sous le capot
Section intitulée « Ce qui se passe sous le capot »Quand vous poussez du code, GitLab :
- Détecte le
.gitlab-ci.ymlà la racine du projet - Parse le YAML et crée les jobs dans l’ordre des stages
- Assigne chaque job à un runner disponible (sur gitlab.com, ce sont des runners SaaS partagés)
- Le runner tire l’image Docker spécifiée (
python:3.12-slimoudocker:27) - Il lance un conteneur à partir de cette image
- Il exécute le
before_scriptpuis lescriptdans ce conteneur - Si toutes les commandes retournent un exit code 0, le job est vert
- Si une commande échoue (exit code ≠ 0), le job est rouge et le pipeline s’arrête
Push → GitLab lit .gitlab-ci.yml → crée 3 jobs ↓Runner prend le job "ruff-lint" → pull python:3.12-slim → crée un conteneur → pip install ruff → ruff check app/ tests/ → exit 0 → ✅ ↓Runner prend le job "pytest" → pull python:3.12-slim → crée un conteneur → pip install -r requirements-dev.txt → pytest -v → exit 0 → ✅ ↓Runner prend le job "docker-build" → pull docker:27 + docker:27-dind → crée un conteneur avec le service DinD → docker build -t pipeline-craft:test . → exit 0 → ✅ ↓Pipeline vert ✅Pièges fréquents
Section intitulée « Pièges fréquents »| Symptôme | Cause | Solution |
|---|---|---|
yaml syntax error immédiat | Indentation incorrecte, tabulations | Vérifier avec l’éditeur CI/CD de GitLab (Build > Pipeline editor) |
ruff: command not found | before_script manquant ou mal indenté | Vérifier que before_script: est au bon niveau d’indentation |
pytest: command not found | pip install absent ou requirements-dev.txt mal orthographié | Vérifier le nom du fichier et le before_script |
Cannot connect to the Docker daemon | Service docker:27-dind absent ou DOCKER_TLS_CERTDIR manquant | Ajouter services: et la variable DOCKER_TLS_CERTDIR |
| Pipeline jamais déclenché | Fichier .gitlab-ci.yml mal nommé ou pas à la racine | Le fichier doit s’appeler exactement .gitlab-ci.yml à la racine du dépôt |
Job pending pendant longtemps | Runner partagé occupé (gitlab.com) | Patience — les runners SaaS Free peuvent avoir une file d’attente |
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Validez votre YAML avant de pousser : utilisez le Pipeline Editor intégré à GitLab (Build > Pipeline editor). Il vérifie la syntaxe et montre une visualisation du pipeline. Voir Valider un .gitlab-ci.yml.
- Explorez les variables prédéfinies : GitLab injecte automatiquement des variables comme
$CI_COMMIT_SHA,$CI_PROJECT_NAME,$CI_PIPELINE_ID. Ajoutezenv | grep CI_dans unscript:pour les voir. - Comparez avec
solution/lab-01: si votre pipeline ne fonctionne pas, regardez la branchesolution/lab-01pour comparer avec la solution attendue.
À retenir
Section intitulée « À retenir »- Un fichier
.gitlab-ci.ymlà la racine suffit pour activer la CI/CD sur un projet GitLab - Un pipeline est découpé en stages (ordre séquentiel) contenant des jobs (tâches concrètes)
- Chaque job s’exécute dans un conteneur Docker isolé — rien n’est partagé entre les jobs
before_scriptprépare l’environnement,scriptexécute la tâche- Le build Docker nécessite Docker-in-Docker (
docker:27-dinden service) sur les runners SaaS - Ce pipeline est fonctionnel mais pas optimisé : chaque job réinstalle ses dépendances, les images sont lourdes, et rien n’est mis en cache — ce sera l’objet des prochains labs