TP11 : GitLab CI/CD et runner auto-hébergé

Après Jenkins (TP9) et GitHub Actions (TP3, TP10), ce TP fait découvrir le troisième grand outil de CI/CD : GitLab CI/CD. La forge, la CI, le registre de conteneurs et les scanners de sécurité y sont intégrés dans un même produit. Vous exécutez le pipeline sur votre propre runner, installé sur la VM de lab, pour comprendre comment fonctionnent les runners auto-hébergés et comment les sécuriser.


Fichiers de départ : gitlab-ci-starter.zip

1. Objectifs pédagogiques

À l’issue du TP, vous serez capable de :

  • lire et écrire un .gitlab-ci.yml : stages, jobs, needs, rules, cache, artifacts, variables ;
  • installer et enregistrer un GitLab Runner auto-hébergé (executor Docker) et expliquer son modèle pull ;
  • utiliser les variables prédéfinies et les variables CI/CD protégées et masquées ;
  • intégrer les templates de sécurité GitLab (SAST, Secret Detection) ;
  • publier une image dans le registre de conteneurs GitLab ;
  • comparer Jenkins, GitHub Actions et GitLab CI/CD sur des critères objectifs.

Les images de cette page sont des schémas explicatifs, pas des captures d’écran.

2. Environnement du TP

  • Un compte gitlab.com (offre gratuite). GitLab peut demander une vérification d’identité pour utiliser ses runners partagés : ce TP n’en a pas besoin, puisque vous utilisez votre propre runner.
  • VM de lab Ubuntu Server 26.04 avec Docker.
  • Le projet contact-api du TP8, avec son Dockerfile, importé dans un nouveau projet GitLab (New project → Import project → Repository by URL, ou git remote add gitlab … puis git push).
  • Settings → CI/CD → Runners : désactiver les instance runners du projet, afin que seuls vos runners exécutent les jobs.

GitLab.com et runner auto-hébergé : le runner tire les jobs GitLab.com et runner auto-hébergé : le runner tire les jobs

Terme Signification
Pipeline Ensemble des jobs déclenchés par un push, une merge request, un tag ou une planification.
Stage / Job Étape logique / unité de travail exécutée par un runner dans un conteneur.
Runner Agent qui interroge GitLab, récupère les jobs et les exécute (executor shell, Docker, Kubernetes…).
Tags Étiquettes qui associent un job aux runners capables de l’exécuter.
needs Dépendance explicite entre jobs : un job démarre dès que ses dépendances sont finies (graphe orienté).
Artefact / cache Fichiers transmis aux jobs suivants (artefact) / réutilisés entre pipelines (cache).

3. Partie 1 : Installer et enregistrer le runner

  • Installer GitLab Runner depuis le dépôt officiel :

    curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
    sudo apt install -y gitlab-runner
    sudo usermod -aG docker gitlab-runner
    gitlab-runner --version

    Si le dépôt ne propose pas encore de paquet pour Ubuntu 26.04, utilisez le paquet noble ou le binaire officiel (/usr/local/bin/gitlab-runner).

  • Dans le projet : Settings → CI/CD → Runners → New project runner, tag lab, cocher Run untagged jobs (nécessaire aux templates de sécurité), puis copier le jeton glrt-….

  • Enregistrer le runner avec l’executor Docker :

    sudo gitlab-runner register --non-interactive --url https://gitlab.com \
      --token glrt-XXXXXXXX --executor docker --docker-image node:24-alpine --description lab-runner
    sudo gitlab-runner verify
    sudo systemctl status gitlab-runner
  • Comparer le fichier /etc/gitlab-runner/config.toml avec runner-config.toml.example et ajouter le montage du socket Docker. Lire l’avertissement : quel risque prend-on ?

  • Le runner apparaît-il en vert dans GitLab ? Expliquer pourquoi aucun port n’a dû être ouvert sur la VM.

4. Partie 2 : Premier pipeline

Pipeline GitLab du TP : install, test, security, build, push Pipeline GitLab du TP : install, test, security, build, push

  • Copier .gitlab-ci.yml à la racine du projet, puis commiter et pousser.
  • Build → Pipelines : ouvrir le pipeline, consulter le graphe des jobs et les logs. Sur quel runner chaque job s’est-il exécuté ?
  • Valider la syntaxe avec l’éditeur de pipeline (Build → Pipeline editor → Validate) et afficher la configuration fusionnée (Full configuration).

5. Partie 3 : Cache, artefacts, rules et registre

  • Compléter les TODO de la partie 3 :
    • cache de .npm/ avec key: files: [package-lock.json] ;
    • artifacts : node_modules/ (1 h) et le rapport JUnit (reports: junit:, when: always) ;
    • rules : build-image sur les merge requests et la branche par défaut ; push-image uniquement sur la branche par défaut ;
    • docker login avec CI_REGISTRY_USER / CI_REGISTRY_PASSWORD, puis docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA".
  • Mesurer la durée du job install avant et après le cache.
  • Ouvrir une merge request depuis une branche feature/… : vérifier que push-image n’apparaît pas dans son pipeline et que l’onglet Tests affiche le rapport JUnit.
  • Après le merge, vérifier l’image dans Deploy → Container Registry.
  • Créer une variable CI/CD DEMO_TOKEN (Settings → CI/CD → Variables) masquée et protégée, l’utiliser dans un job (echo "longueur: ${#DEMO_TOKEN}") et observer :
    • qu’elle est masquée dans les logs ;
    • qu’elle est absente des pipelines des branches non protégées.

6. Partie 4 : Sécurité intégrée

  • Décommenter l’include des templates SAST et Secret Detection, pousser, et observer les nouveaux jobs (semgrep-sast, secret_detection…).

  • Télécharger les artefacts gl-sast-report.json et gl-secret-detection-report.json, puis comparer avec Semgrep et Gitleaks du TP10 : sur quels moteurs s’appuie GitLab ?

    Dans l’offre gratuite, les rapports sont disponibles sous forme d’artefacts JSON. Le tableau de bord de vulnérabilités, le widget de merge request et le Dependency Scanning demandent l’offre Ultimate : c’est pourquoi le contrôle des dépendances est fait ici avec npm audit.

  • Ajouter un faux secret dans une branche et vérifier qu’il est détecté.

  • Settings → Repository → Protected branches : interdire le push direct sur main. Settings → Merge requests : exiger un pipeline réussi avant le merge.

7. Partie 5 : Comparaison des trois outils

  • Compléter le tableau à partir de votre expérience des TP9, TP10 et TP11 :
Critère Jenkins GitHub Actions GitLab CI/CD
Configuration
Runners / agents
Secrets
Sécurité intégrée
Maintenance
Intégration Git
  • Rédiger une recommandation argumentée (10 lignes) pour une PME qui démarre son usine logicielle.

Défi

  1. Remplacer le montage du socket Docker par une construction d’image sans privilège (BuildKit rootless, Buildah ou Kaniko) et retirer le socket du config.toml.
  2. Après le TP14, déployer un runner dans Kubernetes (chart Helm gitlab/gitlab-runner, executor Kubernetes) dans un namespace dédié, avec un ServiceAccount limité : c’est le moindre privilège appliqué aux runners.

8. Livrables

Captures à déposer dans captures/ :

Fichier Contenu attendu
runner-online.png Runner lab-runner en ligne dans GitLab et gitlab-runner verify
pipeline-graph.png Graphe du pipeline avec les needs
cache.png Durée du job install avant / après le cache
mr-pipeline.png Pipeline de merge request sans push-image, onglet Tests
container-registry.png Image :<short-sha> dans le registre GitLab
security-reports.png Jobs SAST et Secret Detection, extrait des rapports

Ainsi que le .gitlab-ci.yml final et le tableau comparatif. Jamais le jeton du runner.