Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

🚀 GitLab CI/CD – Pipelines, Runners & DĂ©ploiement

Guide complet IDEO‑Lab sur l'automatisation CI/CD (.gitlab-ci.yml, Runners, Stages, Variables).

1.1 Facile

Concept : CI/CD Intégré

CI/CD intégré à GitLab, .gitlab-ci.yml.

CI/CD YAML
1.2 Facile

Architecture

GitLab (Controller) -> Runner (Agent) -> Job.

Runner Job
1.3 Moyen

Concept : Runners

Shared vs Specific vs Group. Executors (Shell, Docker).

Shared Runner Specific Runner
1.4 Moyen

Installation (GitLab Runner)

apt/dnf, gitlab-runner register, Docker executor.

Install Register
2.1 Facile

.gitlab-ci.yml (Syntaxe)

image, stages, job_name, stage, script.

.gitlab-ci.yml YAML
2.2 Moyen

Directives : script

before_script, script, after_script.

script before_script
2.3 Moyen

Exemple: Test Django (Base)

image: python, services: [postgres].

Django services
3.1 Moyen

Variables

variables: (YAML) vs "CI/CD Variables" (Secrets).

variables: Secrets
3.2 Moyen

Variables Prédéfinies

$CI_COMMIT_BRANCH, $CI_PROJECT_DIR.

{$}CI_COMMIT_BRANCH
3.3 Avancé

Cache vs Artifacts

cache: (vitesse) vs artifacts: (résultats).

cache artifacts
3.4 Avancé

rules (ContrĂŽle)

rules: if:, when, allow_failure.

rules when
4.1 Moyen

Environnements

environment: name:, url, on_stop.

environment staging
4.2 Moyen

Déploiement Manuel

when: manual, allow_failure: false.

when: manual prod
4.3 Avancé

Build Docker (DinD)

Docker-in-Docker, image: docker:dind, services.

Docker-in-Docker docker build
4.4 Avancé

Exemple: Pipeline Django

Test (Bdd), Build (Docker), Deploy (SSH).

Django Pipeline
4.5 Facile

GitLab Pages

Job pages, public/, artifacts.

GitLab Pages Static Site
5.1 Moyen

Cheat-sheet .gitlab-ci.yml

Mots-clés YML (stages, script, rules, cache...).

cheat .gitlab-ci.yml
1.1 Concept : CI/CD Intégré
L'automatisation intégrée à Git

GitLab CI/CD est la fonctionnalité d'Intégration Continue et de Déploiement Continu (CI/CD) **intégrée** à la plateforme GitLab.

Contrairement à Jenkins (un outil externe), GitLab CI est piloté par un seul fichier .gitlab-ci.yml que vous placez à la racine de votre dépÎt Git.

DÚs que vous "pushez" (git push) du code, GitLab détecte ce fichier et lance automatiquement un Pipeline (une série de tùches).

Flux de CI/CD
  1. Dev "push" vers une branche "feature".
  2. GitLab reçoit le push et lit .gitlab-ci.yml.
  3. GitLab trouve un "Runner" (un agent) disponible.
  4. Le Runner exécute les "Jobs" (tùches) définis (ex: Test).
  5. Le Runner rapporte le succÚs/échec à GitLab.
  6. Le Dev "merge" dans "main".
  7. GitLab lance un nouveau pipeline (Test, Build, Deploy).
GitLab CI vs. Jenkins
CritĂšreGitLab CI/CDJenkins
ConfigurationYAML (.gitlab-ci.yml). "Pipeline as Code".Groovy (Jenkinsfile) ou UI (Freestyle).
IntégrationParfaite. Intégrée à Git, Merge Requests, Registre.Externe. Nécessite des plugins pour tout (Git, UI...).
Agents (Workers)Runners (Shared ou auto-hébergés).Agents (Statiques ou dynamiques).
Courbe d'apprentissageFacile Ă  Moyenne (YAML).ÉlevĂ©e (Groovy, UI, Plugins, Java).
ÉcosystĂšmeLimitĂ© Ă  l'Ă©cosystĂšme GitLab.IllimitĂ© (des milliers de plugins).

Conclusion : GitLab CI est plus simple, plus moderne et mieux intégré si vous utilisez déjà GitLab. Jenkins est plus puissant et flexible (mais plus lourd) si vous avez des besoins complexes ou multi-VCS.

1.2 Architecture : GitLab, Runner, Job
Les 3 Composants Clés
  1. GitLab (Serveur / Controller) : C'est l'instance principale (gitlab.com ou votre propre serveur). Elle gÚre l'UI, le dépÎt Git, et le planificateur de CI/CD. C'est le "cerveau".
  2. GitLab Runner (Agent) : C'est l'exécutant (le "worker"). Un programme (écrit en Go) que vous installez sur un serveur (Linux, Windows, K8s). Il contacte le serveur GitLab et demande "Y a-t-il du travail ?".
  3. Job (Tùche) : Le "travail" (une étape, ex: `test_job`) défini dans votre .gitlab-ci.yml, que le Runner exécute.
Schéma de flux (git push)

(1. git push)
      |
      ▌
+-----------------------+
| GitLab (Serveur)      |
| (lit .gitlab-ci.yml)  |
| (Crée un "Pipeline")  |
+-----------------------+
      |
      | 2. (Place Job 'test' dans la file d'attente)
      |
      | 3. (Ping: "Qui peut faire ce job ?")
      |
      â–Č
      | 4. (Polling: "J'ai du temps libre")
      |
+-----------------------+
| GitLab Runner (Agent) |
| (Ex: Serveur Linux)   |
| (Tags: 'docker')      |
+-----------------------+
      |
      | 5. (GitLab envoie le Job au Runner)
      |
      ▌
(Runner exécute le Job:
 'docker run python:3.11 ...')
      |
      | 6. (Renvoie le log/statut Ă  GitLab)
      ▌
+-----------------------+
| GitLab (Serveur)      |
| (Met à jour l'UI: ✓ OK) |
+-----------------------+
1.3 Concept : Runners (Shared vs Specific)
Types de Runners (OĂč s'exĂ©cute le Job ?)

(Settings -> CI/CD -> Runners)

TypePropriétaireUsageTemps/Coût
Shared (Partagé)GitLab (ex: gitlab.com)Jobs publics, standards, sans besoins spécifiques.Limité (Quotas de CI, ex: 400 min/mois).
Specific (Spécifique)Vous (Auto-hébergé)Production. Jobs privés, déploiements, besoins spécifiques (ex: GPU, Docker-in-Docker).Illimité (votre propre serveur).
GroupVous (Auto-hébergé)Runner partagé pour un groupe de projets.Illimité.
Tags (Étiquettes)

Les "Tags" sont la clé. Vous "taguez" votre Runner (ex: docker, linux, prod-deploy).
Dans .gitlab-ci.yml, vous spécifiez les tags: dont le job a besoin.

Executors (Comment le Job s'exécute ?)

Quand vous enregistrez un Runner (voir 1.4), vous devez choisir son "Executor" (méthode d'exécution).

ExecutorDescriptionUsage
dockerRecommandé. Lance le job dans un conteneur Docker (propre, isolé).Standard (Test, Build).
shellExécute les scripts directement sur la machine hÎte.Déploiement. (ex: `ssh`, `rsync` sur le serveur de prod).
docker-machine(Avancé) Crée des VMs à la volée pour les builds (auto-scaling).Infrastructure CI/CD large.
kubernetes(Avancé) Lance le job comme un Pod Kubernetes.CI/CD Cloud-Native.
1.4 Installation & Enregistrement d'un Runner
1. Installation (sur votre VPS/serveur)
Ubuntu / Debian
# 1. Ajouter le dépÎt
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash

# 2. Installer
sudo apt-get install gitlab-runner
RHEL / Rocky / AlmaLinux
# 1. Ajouter le dépÎt
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | sudo bash

# 2. Installer
sudo dnf install gitlab-runner
2. Enregistrement (Lier le Runner Ă  GitLab)

Allez dans GitLab -> Settings -> CI/CD -> Runners et récupérez l'URL et le Token d'enregistrement.

# Lancer l'assistant interactif
sudo gitlab-runner register

L'assistant va demander :

  • GitLab instance URL : (ex: https://gitlab.com)
  • Registration token : (ex: glrt-AbC...)
  • Description : (ex: "Mon runner docker prod")
  • Tags : (ex: docker,linux,prod-deploy) (SĂ©parez par des virgules !)
  • Executor : (ex: docker)
  • Default Docker image : (ex: alpine:latest) (si executor=docker)

Le runner est maintenant enregistré dans /etc/gitlab-runner/config.toml et démarré.

2.1 Syntaxe : .gitlab-ci.yml (Anatomie)
Anatomie de base

C'est un fichier YAML. Les noms à gauche sont des **Jobs** (ex: build_job). Les mots-clés (image, stage, script) sont des directives.

# (1) Définir l'image Docker par défaut
default:
  image: node:18-alpine

# (2) Définir l'ordre des étapes
stages:
  - build
  - test
  - deploy

# (3) Définir le Job "build"
build_job:
  stage: build  # (Lien vers 'stages')
  script:
    - echo "Building..."
    - npm install
    - npm run build

# (4) Définir le Job "test"
test_job:
  stage: test
  script:
    - echo "Testing..."
    - npm test
Concepts
  • default: image: : L'image Docker que le Runner utilisera (sauf si surchargĂ©e).
  • stages: [...] : (Crucial) DĂ©finit l'ordre d'exĂ©cution des Ă©tapes. Tous les jobs d'un "stage" (ex: "test") s'exĂ©cutent en parallĂšle. Le stage suivant (ex: "deploy") ne dĂ©marre que si *tous* les jobs du stage prĂ©cĂ©dent ont rĂ©ussi.
  • [nom_job]: : (ex: build_job) C'est votre tĂąche.
  • stage: build : Lie le job au stage "build".
  • script: [...] : La (ou les) commande(s) shell Ă  exĂ©cuter.
2.2 Directives : script, before_script, after_script
Ordre d'exécution

before_script (pour le setup), script (le travail), after_script (le cleanup).

default:
  before_script:
    - echo "Global: S'exécute avant CHAQUE job"
    
my_job:
  stage: test
  
  before_script:
    - echo "Local: Surcharge le 'default:before_script'"
    - apt-get update
  
  script:
    - echo "Le travail principal (tests)"
    - npm test
    
  after_script:
    - echo "Cleanup (s'exĂ©cute mĂȘme si 'script' Ă©choue)"
    - rm -rf node_modules/
YAML (Listes vs Blocs)

Les scripts sont des listes YAML (-) ou des blocs (|).

Liste (-)
script:
  - commande 1
  - commande 2
Bloc (|) (Plus lisible)
script: |
  commande 1
  commande 2
  if [ "$VAR" == "true" ]; then
    echo "Multi-lignes"
  fi
2.3 Exemple : Test Django (avec BDD)

Comment tester un projet Django qui a besoin d'une BDD (ex: PostgreSQL) ? On utilise la directive services.

default:
  image: python:3.11-slim

stages:
  - test

# Job de test
test_django_app:
  stage: test
  
  # 1. 'services' (lance un 2Ăšme conteneur 'postgres'
  #    et le lie au conteneur principal)
  services:
    - name: postgres:15-alpine
      alias: postgres-db
      
  # 2. Variables (pour configurer Django/Postgres)
  variables:
    # (Remplace le .env pour les tests)
    POSTGRES_DB: test_db
    POSTGRES_USER: test_user
    POSTGRES_PASSWORD: "test_password"
    # (Dit Ă  Django oĂč trouver la BDD)
    DATABASE_URL: "postgres://test_user:test_password@postgres-db:5432/test_db"
  
  before_script:
    - apt-get update && apt-get install -y postgresql-client
    - pip install -r requirements.txt
    
  script:
    # (Attendre que le service Postgres soit prĂȘt)
    - PGPASSWORD=$POSTGRES_PASSWORD psql -h postgres-db -U $POSTGRES_USER -d $POSTGRES_DB -c "SELECT 1"
    
    # (Lancer les tests)
    - python manage.py migrate
    - python manage.py test
3.1 Variables (YML vs Secrets)
Variables (Non-sensibles)

Définies dans .gitlab-ci.yml. Visibles dans Git.

# 1. Variable Globale
variables:
  PYTHON_VERSION: "3.11"
  NODE_VERSION: "18"

stages:
  - test
  
test_job:
  stage: test
  # 2. Variable de Job (Surcharge)
  variables:
    NODE_VERSION: "20"
  script:
    - echo "Python: ${PYTHON_VERSION}" # Affiche 3.11
    - echo "Node: ${NODE_VERSION}"   # Affiche 20
Variables CI/CD (Secrets / Masquées)

⚠ Ne **jamais** commiter de secrets (mots de passe, tokens, clĂ©s SSH) dans .gitlab-ci.yml.

Utilisez l'UI de GitLab :
Settings -> CI/CD -> Variables -> Expand

Création (UI GitLab)
  • Key : PROD_SSH_KEY
  • Value : -----BEGIN RSA PRIVATE KEY...
  • Flags :
    • ☑ Protect variable : (RecommandĂ©) N'est disponible que sur les branches/tags protĂ©gĂ©s (ex: main).
    • ☑ Mask variable : (RecommandĂ©) Cache la valeur dans les logs du job.

Cette variable sera disponible en tant que {{ $PROD_SSH_KEY }} dans vos scripts.

3.2 Variables Prédéfinies ($CI_...)

GitLab injecte des centaines de variables d'environnement dans chaque job. Voici les plus utiles.

VariableDescription (Exemple)
{$}CI_COMMIT_BRANCHNom de la branche (ex: feature/login ou main). (Si when: manual, main).
{$}CI_COMMIT_TAGLe nom du tag (si le pipeline tourne sur un tag).
{$}CI_PIPELINE_SOURCEComment le pipeline a démarré (push, web, schedule, trigger).
{$}CI_JOB_STAGELe stage du job (ex: test, deploy).
{$}CI_PROJECT_DIRLe chemin absolu du workspace (ex: /builds/user/projet).
{$}CI_REGISTRY_IMAGEL'URL du registre Docker intégré à GitLab.
{$}CI_REGISTRY_USERLogin pour le registre Docker (gitlab-ci-token).
{$}CI_JOB_TOKENToken d'authentification (temporaire) pour ce job.
3.3 cache (Vitesse) vs artifacts (Résultats)

C'est une confusion trÚs fréquente chez les débutants.

CritĂšrecache: (Cache)artifacts: (Artefacts)
ButAccélérer les builds (ré-utiliser les fichiers).Stocker les résultats d'un job (ex: un binaire, un .jar).
PartageEntre les jobs d'un mĂȘme pipeline.Entre les stages (le job 'deploy' rĂ©cupĂšre l'artifact de 'build').
ExpirationNon garanti (Best-effort).Garanti (expire_in:).
Usagenode_modules/, .venv/, .m2/ (Maven).dist/, target/*.jar, report.xml.
Exemple
# (Mise en cache de 'node_modules' si 'package-lock.json' n'a pas changé)
cache:
  key:
    files:
      - package-lock.json
  paths:
    - node_modules/

build_job:
  stage: build
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - dist/ # (Le résultat du build)
    expire_in: 1 day # (Garde l'artifact 1 jour)

deploy_job:
  stage: deploy
  script:
    - echo "Déploiement du dossier 'dist/'..."
    - ls dist/
  dependencies:
    - build_job # (Télécharge automatiquement l'artifact 'dist/' de 'build_job')
3.4 ContrĂŽle de Flux (rules:)
ContrÎle d'exécution des Jobs

rules: est la méthode moderne (remplace only/except) pour décider *si* un job doit s'exécuter.

deploy_job:
  stage: deploy
  script:
    - echo "Déploiement..."
  rules:
    # 1. (Condition IF)
    - if: '$CI_COMMIT_BRANCH == "main"'
      # (Le job ne s'exécute QUE si on est sur 'main')
    
    # 2. (Condition IF AND)
    - if: '$CI_COMMIT_BRANCH == "dev" && $CI_PIPELINE_SOURCE == "schedule"'
    
    # 3. (Condition IF Fichier modifié)
    - if: '$CI_COMMIT_BRANCH == "main"'
      changes:
        - Dockerfile
        - src/**/*
        
    # 4. Bloquer
    - when: never
when (Quand exécuter)
when:Description
on_success(Défaut) S'exécute si les stages précédents réussissent.
on_failureS'exécute si un stage précédent échoue (ex: Notif Slack).
alwaysS'exécute toujours (pour le cleanup).
manual(Crucial) N's'exĂ©cute pas. Affiche un bouton "Play" (▶) dans l'UI GitLab.
allow_failure (Autoriser l'échec)

Permet à un job (ex: "linting") d'échouer sans bloquer le pipeline.

lint_job:
  stage: test
  script:
    - npm run lint
  allow_failure: true
4.1 Environnements & Déploiement

La directive environment: (environnement) permet à GitLab de "suivre" vos déploiements (Operations -> Environments).

deploy_staging:
  stage: deploy
  script:
    - echo "Déploiement Staging..."
    # (script de déploiement)
  rules:
    - if: '$CI_COMMIT_BRANCH == "dev"'
  
  environment:
    name: staging
    url: https://staging.ideolab.com
    
deploy_prod:
  stage: deploy
  script:
    - echo "Déploiement PRODUCTION..."
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
    
  environment:
    name: production
    url: https://ideolab.com
4.2 Déploiement Manuel (when: manual)

Il est dangereux de déployer en production automatiquement à chaque 'push' sur 'main'. On utilise when: manual pour forcer une action manuelle.

deploy_prod:
  stage: deploy
  script:
    - echo "Déploiement PRODUCTION (SSH, rsync...)"
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      # 1. Le job ne s'exécute pas auto
      when: manual
      # 2. (Optionnel) Si 'manual', le pipeline
      #    est considéré comme "bloqué".
      #    'false' le met en "succĂšs" (jaune).
      allow_failure: false
      
  environment:
    name: production
    url: https://ideolab.com

Dans l'UI GitLab, un bouton (▶) apparaĂźtra. Le dĂ©ploiement ne dĂ©marre que si un humain clique dessus.

4.3 Build Docker (Docker-in-Docker)

Pour *construire* une image Docker (docker build) dans un job, le Runner a besoin d'un accĂšs Docker. On utilise "Docker-in-Docker" (DinD).

# Job pour builder et pusher une image
build_docker_image:
  stage: build
  
  # 1. Utiliser l'image 'docker' (client)
  image: docker:24.0
  
  # 2. Lancer le 'daemon' docker (dind)
  #    en tant que service lié.
  services:
    - docker:24.0-dind
    
  # 3. (Requis) Dire au client de ne pas utiliser TLS
  variables:
    DOCKER_TLS_CERTDIR: ""
    DOCKER_HOST: tcp://docker:2375

  before_script:
    # 4. Login au registre GitLab
    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER $CI_REGISTRY --password-stdin
    
  script:
    # 5. Build & Push
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
4.4 Exemple: Pipeline Django (Test & Deploy)
stages:
  - test
  - deploy_staging
  - deploy_prod

# Job de Test (cf 2.3)
test_django:
  image: python:3.11
  stage: test
  services:
    - postgres:15
  variables:
    POSTGRES_DB: test_db
    POSTGRES_USER: test_user
    POSTGRES_PASSWORD: "test_password"
    DATABASE_URL: "postgres://test_user:test_password@postgres:5432/test_db"
  script:
    - pip install -r requirements.txt
    - python manage.py migrate
    - python manage.py test

# Job de Déploiement (Staging)
deploy_staging:
  image: alpine:latest
  stage: deploy_staging
  
  before_script:
    # (Installer SSH & Clé privée)
    - apk add --no-cache openssh-client rsync
    - eval $(ssh-agent -s)
    - echo "$STAGING_SSH_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - ssh-keyscan -H $STAGING_SERVER_IP >> ~/.ssh/known_hosts
    
  script:
    - echo "Déploiement Staging..."
    # (Ex: rsync -avz . ideo_user@$STAGING_SERVER_IP:/opt/ideo_project/)
    # (Ex: ssh ideo_user@$STAGING_SERVER_IP "cd /opt/ideo_project && ./deploy.sh")
    
  environment:
    name: staging
    url: http://staging.ideolab.com
  rules:
    - if: '$CI_COMMIT_BRANCH == "dev"'
    
# Job de Déploiement (Production)
deploy_prod:
  # (Copie de 'deploy_staging', mais avec $PROD_SSH_KEY)
  stage: deploy_prod
  script:
    - echo "Déploiement PRODUCTION..."
  environment:
    name: production
    url: http://ideolab.com
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual # (Protection)
4.5 GitLab Pages (Sites Statiques)

GitLab CI peut héberger des sites statiques (HTML/CSS/JS) gratuitement, si le job s'appelle pages et que l'artifact est un dossier public/.

# (Exemple: Déployer un site React/Vite)

# 1. Nom de job spécial
pages:
  stage: deploy
  image: node:18-alpine
  
  script:
    - npm install
    - npm run build # (Crée le dossier 'dist')
    # 2. Renommer 'dist' en 'public'
    - mv dist public
    
  # 3. L'artifact DOIT ĂȘtre 'public'
  artifacts:
    paths:
      - public
      
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

Le site sera disponible sur https://[username].gitlab.io/[projectname].

5.1 Cheat-sheet .gitlab-ci.yml
Structure Globale
# (Image Docker par défaut)
default:
  image: python:3.11
  
# (Ordre d'exécution)
stages:
  - build
  - test
  - deploy
  
# (Variables non-secrĂštes)
variables:
  MY_VAR: "valeur"
  
# (Mise en cache)
cache:
  key:
    files:
      - requirements.txt
  paths:
    - .venv/
Structure d'un Job
mon_job:
  image: node:18 # (Surcharge 'default')
  stage: test
  
  services:
    - postgres:15
    
  tags:
    - docker # (Runner requis)
    
  script:
    - echo "Exécution"
    
  artifacts:
    paths:
      - dist/
    expire_in: 1 week
    
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual
    - if: '$CI_COMMIT_BRANCH == "dev"'