GitLab CI
Le pipeline est défini dans .gitlab-ci.yml à la racine du dépôt. Il est exécuté par des runners.
Vocabulaire
- Pipeline : l'ensemble des jobs déclenchés par un événement (push, merge request, tag, planification, déclenchement manuel).
- Stage : une étape. Les stages s'enchaînent dans l'ordre.
- Job : une tâche dans un stage. Les jobs d'un même stage tournent en parallèle.
- Runner : l'agent qui exécute les jobs.
Un pipeline d'infra complet
stages:
- validate
- plan
- apply
default:
image:
name: hashicorp/terraform:1.9
entrypoint: [""]
before_script:
- cd terraform/envs/$TF_ENV
- terraform init -input=false
variables:
TF_ENV: prod
fmt:
stage: validate
before_script: []
script:
- terraform fmt -check -recursive terraform/
validate:
stage: validate
script:
- terraform validate
checkov:
stage: validate
image:
name: bridgecrew/checkov:3
entrypoint: [""]
before_script: []
script:
- checkov -d terraform/
allow_failure: true
plan:
stage: plan
script:
- terraform plan -out=tfplan -input=false
artifacts:
paths:
- terraform/envs/$TF_ENV/tfplan
expire_in: 1 week
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
apply:
stage: apply
script:
- terraform apply -input=false tfplan
needs: [plan]
environment:
name: production
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual
resource_group: terraform-prod
Ce qu'il faut savoir expliquer :
-
entrypoint: [""]: les images Terraform et Checkov ont la commande comme point d'entrée. Sans cette ligne, GitLab ne peut pas lancer son shell dedans. -
rulesdécide si le job est créé. L'apply n'existe que sur la branche par défaut, et attend un clic. -
needscrée une dépendance directe : le job démarre dès queplanest fini, sans attendre tout le stage précédent. Ça forme un graphe (DAG) au lieu d'une suite stricte. -
Le plan est passé en artifact à l'apply : on applique exactement ce qui a été relu.
-
resource_groupempêche deux applies de tourner en même temps. -
environmenttrace les déploiements et permet de protéger l'environnement.
rules
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH == "main"
changes:
- terraform/**/*
- when: never
Les règles sont évaluées dans l'ordre, la première qui correspond gagne. changes lance le job seulement si certains fichiers ont changé. only/except est l'ancienne syntaxe, à remplacer par rules.
Variables prédéfinies utiles : $CI_COMMIT_BRANCH, $CI_COMMIT_TAG, $CI_PIPELINE_SOURCE, $CI_DEFAULT_BRANCH, $CI_COMMIT_SHORT_SHA, $CI_PROJECT_DIR, $CI_REGISTRY_IMAGE, $CI_JOB_TOKEN.
Artifacts et cache
| Artifacts | Cache | |
|---|---|---|
| Rôle | Transmettre des résultats entre jobs et les garder | Accélérer en réutilisant des dépendances |
| Exemples | Plan Terraform, binaire compilé, rapport de tests | node_modules, .pip-cache, .terraform/providers |
| Garantie | Oui, disponibles pour les jobs suivants | Non, peut être absent (autre runner, expiré) |
| Téléchargeable | Oui, depuis l'interface | Non |
Un job ne doit jamais dépendre du cache pour fonctionner, seulement aller plus vite grâce à lui.
cache:
key:
files:
- package-lock.json
paths:
- node_modules/
Variables
Définies dans .gitlab-ci.yml (non sensibles) ou dans Settings > CI/CD > Variables (sensibles).
- Masked : remplacée par
[MASKED]dans les logs. - Protected : injectée seulement dans les pipelines des branches et tags protégés. Une branche de feature ne la voit pas.
- Type File : GitLab écrit la valeur dans un fichier temporaire et la variable contient le chemin. Pratique pour un kubeconfig ou un certificat.
- Portée par environnement : une même variable avec une valeur pour
staginget une pourproduction.
Réutiliser la configuration
include:
- project: infra/ci-templates
ref: v2.1.0
file: /terraform.yml
- template: Jobs/Secret-Detection.gitlab-ci.yml
.terraform_base:
image:
name: hashicorp/terraform:1.9
entrypoint: [""]
before_script:
- terraform init
plan-dev:
extends: .terraform_base
script: terraform plan
- Un job dont le nom commence par
.est un template caché, jamais exécuté directement. extendshérite d'un template, en fusionnant les clés.includeimporte des fichiers d'un autre projet. En entreprise, une équipe plateforme maintient souvent des templates communs.- Les ancres YAML (
&base,<<: *base) existent aussi, mais ne fonctionnent pas entre fichiers inclus.
Runners
- Shared (instance), group ou project : à qui ils sont disponibles.
- Tags : un job avec
tags: [gcp-prod]ne tourne que sur un runner portant ce tag. On réserve ainsi un runner, avec ses droits, à la prod. - Executors :
docker: chaque job dans un conteneur propre, le plus courant ;shell: directement sur la machine, simple mais les jobs se polluent entre eux ;kubernetes: un pod par job, s'adapte à la charge ;docker+machineou autoscaler : crée des VM à la demande.
- Le mode
privileged(Docker-in-Docker) donne beaucoup de droits sur l'hôte. À éviter sur un runner partagé. Alternatives pour construire des images : Kaniko, Buildah.
Environnements et déploiement
deploy-prod:
stage: deploy
script: ./deploy.sh
environment:
name: production
url: https://app.example.com
rules:
- if: $CI_COMMIT_TAG
when: manual
Dans Settings > CI/CD > Protected environments, on restreint qui peut déployer en production, et on peut exiger des approbations.
Autres mots-clés utiles
parallel: matrix:: lancer le même job avec plusieurs combinaisons de variables (plusieurs environnements, plusieurs régions).retry: 2: relancer un job instable (à ne pas utiliser pour masquer un vrai problème).timeout: 30m.interruptible: true: un nouveau pipeline sur la même branche annule l'ancien.trigger:: déclencher un pipeline enfant ou celui d'un autre projet.workflow: rules:: décider si le pipeline entier doit être créé (éviter les doublons branche + MR).
Déboguer un pipeline
- Lire le log du job depuis le début, pas seulement la dernière ligne.
- Ajouter
CI_DEBUG_TRACE: "true"en variable, avec prudence : ça affiche aussi les secrets. - Valider la syntaxe dans l'éditeur de pipeline de GitLab (onglet CI Lint).
- Reproduire en local avec la même image Docker.
Questions d'entretien à préparer
- Différence entre cache et artifacts ?
- Différence entre
needsetstages? - Comment empêcher un déploiement en prod depuis une branche de feature ?
- Variable masked et variable protected, quelle différence ?
- Comment réutiliser la même config CI dans 50 projets ? (
included'un projet de templates) - Quel executor choisirais-tu et pourquoi ?
- Décris le pipeline d'infra que tu as mis en place sur ton projet Penpot.