Tout pipeline GitLab part d’un fichier : .gitlab-ci.yml à la racine de ton repo. Un seul fichier, et GitLab sait quoi faire à chaque push — build, tests, déploiement. Contrairement à GitHub Actions et ses dizaines de fichiers de workflow, GitLab centralise tout. Ce chapitre te donne les clés pour écrire un pipeline complet et fonctionnel, pas un hello world.
Anatomie d’un pipeline
Un pipeline, c’est des stages qui s’exécutent dans l’ordre, et des jobs dans chaque stage qui tournent en parallèle. Si un stage échoue, les suivants ne démarrent pas.
stages:
- build
- test
- deploy
build-app:
stage: build
image: node:20-alpine
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 hour
test-unit:
stage: test
image: node:20-alpine
script:
- npm ci
- npm test
artifacts:
reports:
junit: junit.xml
deploy-staging:
stage: deploy
script:
- ./scripts/deploy.sh staging
rules:
- if: $CI_COMMIT_BRANCH == "main"
Chaque job a un nom (la clé YAML), un stage, un script, et des options. Le default permet de factoriser les paramètres communs (image, before_script). Les artifacts de build sont automatiquement disponibles dans test et deploy.
💡 Attention aux noms réservés : stages, variables, include, default, workflow, image, cache, pages ne peuvent pas être des noms de jobs. GitLab les interprète comme des directives, pas des jobs — ça crée des bugs subtils.
Variables et secrets
GitLab injecte des dizaines de variables automatiquement. Les plus utiles au quotidien :
script:
- echo $CI_COMMIT_SHORT_SHA # Hash court du commit
- echo $CI_COMMIT_REF_NAME # Branche ou tag
- echo $CI_PIPELINE_SOURCE # push, merge_request_event, schedule...
- echo $CI_REGISTRY_IMAGE # registry.gitlab.com/user/project
Tu peux définir tes propres variables au niveau pipeline (global) ou job (override). Les secrets (tokens, passwords) vont dans Settings > CI/CD > Variables — jamais dans le YAML. Options clés : Protected (branches protégées uniquement), Masked (masqué dans les logs).
variables:
APP_NAME: "mon-app"
deploy:
variables:
DEPLOY_ENV: "staging" # Override local
script:
# $DEPLOY_TOKEN vient de l'UI GitLab, pas du YAML
- curl -H "Authorization: Bearer $DEPLOY_TOKEN" https://api.example.com/deploy
⚠️ Un secret dans le YAML, c’est un secret dans l’historique Git. Et l’historique Git, c’est permanent. Même si tu supprimes le commit, quelqu’un peut le retrouver. Variables sensibles = toujours dans l’UI.
Artifacts vs cache
Deux mécanismes pour persister des fichiers, deux usages complètement différents :
Les artifacts passent des fichiers entre jobs/stages au sein d’un même pipeline. C’est garanti — si le job produit l’artifact, le job suivant l’aura. Usage typique : dist/, rapports de tests, binaires.
Le cache persiste des fichiers entre exécutions de pipeline. C’est best-effort — le cache peut être vidé à tout moment. Usage typique : node_modules/, .cache/pip, .venv/.
install:
stage: install
script:
- npm ci
cache:
key:
files:
- package-lock.json # Nouvelle cache si le lockfile change
paths:
- node_modules/
policy: pull-push # Lit et écrit (défaut)
artifacts:
paths:
- node_modules/
expire_in: 1 hour
test:
stage: test
dependencies:
- install # Ne récupère que les artifacts de "install"
cache:
key:
files:
- package-lock.json
paths:
- node_modules/
policy: pull # Lit seulement (plus rapide)
script:
- npm test
Le policy: pull sur les jobs qui ne modifient pas les dépendances accélère le pipeline — pas besoin de réécrire le cache à chaque fois.
🔥 Le combo cache + fallback évite les cold starts sur les nouvelles branches :
cache:
key: "npm-${CI_COMMIT_REF_SLUG}"
paths:
- node_modules/
fallback_keys:
- "npm-main"
Si pas de cache pour ta branche feature, GitLab utilise le cache de main. Ça économise des minutes à chaque nouveau push.
Services et intégration
Les services sont des conteneurs compagnons qui tournent à côté de ton job. L’usage classique : une base de données pour les tests d’intégration.
test-integration:
stage: test
image: python:3.12-slim
services:
- name: postgres:16
alias: db
variables:
POSTGRES_DB: test_db
POSTGRES_USER: test
POSTGRES_PASSWORD: test
- name: redis:7-alpine
alias: cache
variables:
DATABASE_URL: "postgresql://test:test@db:5432/test_db"
REDIS_URL: "redis://cache:6379"
script:
- pip install -r requirements.txt
- pytest tests/integration/
L’alias définit le hostname pour accéder au service. Sans alias, le hostname est dérivé du nom de l’image avec des tirets — peu lisible.
Contrôler l’exécution avec rules
rules (qui remplace l’ancien only/except) définit quand un job s’exécute :
deploy-production:
stage: deploy
script:
- ./deploy.sh production
environment:
name: production
url: https://example.com
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual
allow_failure: false # Le pipeline attend le clic
- when: never
test:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
lint:
rules:
- changes:
- "**/*.py" # Seulement si des .py changent
when: on_success
- when: never
Le when: manual + allow_failure: false crée un mécanisme d’approbation : le pipeline se met en pause jusqu’au clic. C’est ton gate de déploiement production.
Les valeurs de when : on_success (défaut), on_failure (rollback), always (cleanup), manual, delayed (avec start_in), never.
🎯 Cas concret en entreprise : pipeline typique — tests auto sur toutes les branches, build Docker sur main, deploy staging automatique, deploy prod en manual. Le rules + environment te donne le contrôle complet du workflow.
Pièges fréquents et ce qu’il faut retenir
L’indentation YAML. C’est la source d’erreur numéro 1. Un espace en trop ou en moins et ton pipeline est cassé. Utilise le linter intégré : CI/CD > Editor dans l’UI GitLab, ou l’extension VS Code GitLab Workflow.
before_script hérité. Le before_script du default s’applique à tous les jobs. Si un job utilise une image différente (Docker-in-Docker par exemple), il faut l’override explicitement avec before_script: [].
Artifacts qui manquent. Par défaut, un job récupère les artifacts de tous les jobs précédents. Utilise dependencies pour contrôler ça — surtout si tes artifacts sont volumineux.
Cache non garanti. Le cache est best-effort. Ne construis jamais un pipeline qui plante si le cache est vide. Le cache accélère, il ne remplace pas un npm ci.
Variables secrètes visibles. Si ta variable n’est pas marquée Masked, elle apparaît dans les logs. Un echo $TOKEN dans un script expose ton secret à tous ceux qui lisent les logs du pipeline.
💡 Debug rapide : avant de push, valide ton YAML dans l’UI GitLab (CI/CD > Editor). Si ton pipeline échoue mystérieusement, ajoute un job debug avec HOME=/Users/admin LOGNAME=admin NODE_EXTRA_CA_CERTS=/etc/ssl/cert.pem NODE_NO_WARNINGS=1 NODE_USE_SYSTEM_CA=1 OLDPWD=/Users/admin/.openclaw/workspace OPENCLAW_GATEWAY_PORT=18789 OPENCLAW_LAUNCHD_LABEL=ai.openclaw.gateway OPENCLAW_PATH_BOOTSTRAPPED=1 OPENCLAW_SERVICE_KIND=gateway OPENCLAW_SERVICE_MARKER=openclaw OPENCLAW_SERVICE_VERSION=2026.3.13 OPENCLAW_SHELL=exec OPENCLAW_SYSTEMD_UNIT=openclaw-gateway.service OPENCLAW_WINDOWS_TASK_NAME=OpenClaw Gateway OSLogRateLimit=64 PATH=/opt/homebrew/bin:/usr/bin:/bin:/Users/admin/.local/bin:/Users/admin/.npm-global/bin:/Users/admin/bin:/Users/admin/.volta/bin:/Users/admin/.asdf/shims:/Users/admin/.bun/bin:/Users/admin/Library/Application Support/fnm/aliases/default/bin:/Users/admin/.fnm/aliases/default/bin:/Users/admin/Library/pnpm:/Users/admin/.local/share/pnpm:/usr/local/bin PWD=/Users/admin/.openclaw/workspace SHELL=/bin/zsh SHLVL=1 SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.4ofA9hQy2O/Listeners TMPDIR=/var/folders/cd/0b3vsx616nsgvht47xbpk8380000gn/T/ USER=admin VIPSHOME=/Users/runner/work/sharp-libvips/sharp-libvips/target XPC_FLAGS=0x0 XPC_SERVICE_NAME=0 _=/usr/bin/env __CF_USER_TEXT_ENCODING=0x1F5:0x0:0x0 pour voir toutes les variables disponibles. Et vérifie l’espace disque du runner avec Filesystem Size Used Avail Capacity iused ifree %iused Mounted on /dev/disk3s3s1 460Gi 12Gi 405Gi 3% 455k 4.2G 0% / devfs 202Ki 202Ki 0Bi 100% 700 0 100% /dev /dev/disk3s6 460Gi 20Ki 405Gi 1% 0 4.2G 0% /System/Volumes/VM /dev/disk3s4 460Gi 8.2Gi 405Gi 2% 1.8k 4.2G 0% /System/Volumes/Preboot /dev/disk3s2 460Gi 43Mi 405Gi 1% 62 4.2G 0% /System/Volumes/Update /dev/disk2s2 500Mi 6.0Mi 483Mi 2% 4 4.9M 0% /System/Volumes/xarts /dev/disk2s1 500Mi 5.7Mi 483Mi 2% 31 4.9M 0% /System/Volumes/iSCPreboot /dev/disk2s3 500Mi 656Ki 483Mi 1% 33 4.9M 0% /System/Volumes/Hardware /dev/disk3s1 460Gi 34Gi 405Gi 8% 374k 4.2G 0% /System/Volumes/Data map auto_home 0Bi 0Bi 0Bi 100% 0 0 - /System/Volumes/Data/home — un runner plein, c’est des builds qui échouent sans message clair.
Le pipeline GitLab est puissant parce qu’il est déclaratif : tu décris ce que tu veux (stages, conditions, artifacts), et GitLab orchestre l’exécution. La clé c’est de commencer simple — 3 stages, quelques jobs — et d’ajouter de la complexité au fur et à mesure. Un pipeline lisible vaut mieux qu’un pipeline clever.
Dans le prochain chapitre, on plonge dans les runners : Docker executor vs Kubernetes, shared vs specific, et comment optimiser les performances.
🖥️ Pratique sur ton propre serveur
Pour suivre GitLab CI/CD en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.
Contenu réservé aux abonnés
Ce chapitre fait partie de la formation complète. Abonne-toi pour débloquer tous les contenus.
Débloquer pour 29 CHF/moisLe chapitre 1 de chaque formation est gratuit.
Série pas encore débloquée
Termine la série prérequise d'abord pour accéder à ce contenu.
Aller à la série prérequiseSérie : GitLab CI/CD
2 / 6- GitLab CI/CD : comprendre la plateforme avant de pipeline
- 2 Ton premier pipeline GitLab CI/CD
- 3 Runners GitLab : Docker, Kubernetes et autoscaling
- 4 GitLab CI avancé : templates, includes, DAG et rules
- 5 Sécurité dans GitLab CI : SAST, DAST et scanning
- 6 GitLab CI en production : environments, review apps et feature flags
Sur cette page
Articles liés
GitLab CI/CD : comprendre la plateforme avant de pipeline
GitLab vs GitHub Actions, l'architecture interne, les runners, le modèle DevOps intégré. Tout ce qu'il faut comprendre avant d'écrire ta première ligne de YAML.
Runners GitLab : Docker, Kubernetes et autoscaling
Comprends les executors Docker et Kubernetes, configure des runners shared et specific, maîtrise le tagging et l'autoscaling pour des pipelines rapides.
GitLab CI avancé : templates, includes, DAG et rules
Maîtrise les techniques avancées de GitLab CI : templates réutilisables, includes, pipelines parent-child, DAG pour la parallélisation, et rules complexes.