revision.devops

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.

  • rules décide si le job est créé. L'apply n'existe que sur la branche par défaut, et attend un clic.

  • needs crée une dépendance directe : le job démarre dès que plan est 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_group empêche deux applies de tourner en même temps.

  • environment trace 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

ArtifactsCache
RôleTransmettre des résultats entre jobs et les garderAccélérer en réutilisant des dépendances
ExemplesPlan Terraform, binaire compilé, rapport de testsnode_modules, .pip-cache, .terraform/providers
GarantieOui, disponibles pour les jobs suivantsNon, peut être absent (autre runner, expiré)
TéléchargeableOui, depuis l'interfaceNon

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 staging et une pour production.

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.
  • extends hérite d'un template, en fusionnant les clés.
  • include importe 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+machine ou 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 needs et stages ?
  • 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 ? (include d'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.
Faire le QCMExercicesBash →