CI/CD : automatiser tests, builds et déploiements
Quitter

Leçon 1 sur 10 · Principes et GitHub Actions

Intégration et déploiement continus : principes, pipeline, environnements

40 min Node.js 22 (Debian, git, npm, python3)

Objectif

Comprendre pourquoi les équipes automatisent leurs tests et leurs mises en production, ce que recouvrent exactement les sigles CI et CD, comment se découpe un pipeline, et à quoi servent les environnements. Vous écrirez ensuite votre premier pipeline… en simple shell, pour bien voir ce qu'un outil comme GitHub Actions ou GitLab CI automatise.

L'essentiel

  • Intégration continue (CI) : chaque modification poussée est construite et testée automatiquement, plusieurs fois par jour, pour détecter les problèmes tout de suite.
  • Livraison continue (continuous delivery) : chaque version qui passe la CI est prête à partir en production ; la mise en production reste un clic humain.
  • Déploiement continu (continuous deployment) : chaque version qui passe tous les contrôles part automatiquement en production.
  • Un pipeline enchaîne des étapes (lint, tests, build, déploiement) ; la première qui échoue arrête tout.
  • Les environnements (développement, recette/staging, production) permettent de valider une version avant qu'elle n'atteigne les clients.
  • Principe central : on construit une seule fois et on déploie le même artefact partout.

1. Le problème : « ça marche sur mon poste »

À l'agence Atlas Web (Casablanca), avant l'automatisation, une mise en production ressemblait à ceci :

  • le vendredi soir, Youssef fusionne trois semaines de travail de quatre personnes ;
  • personne n'a lancé tous les tests : certains ne passent plus depuis dix jours ;
  • il construit le site sur son poste (avec sa version de Node.js), puis copie les fichiers en FTP sur le serveur ;
  • le site d'un client tombe le samedi ; personne ne sait quelle modification est en cause.

L'intégration et le déploiement continus règlent ces problèmes par trois idées :

Idée En pratique
Intégrer souvent des branches courtes fusionnées chaque jour : les conflits restent petits
Tout vérifier automatiquement une machine neutre lance lint, tests et build à chaque push
Déployer comme on teste le déploiement est un script versionné, identique à chaque fois, et réversible

2. CI, livraison continue, déploiement continu

                         Intégration continue (CI)
            ┌──────────────────────────────────────────────┐
  push  →   │ récupérer le code → lint → tests → build      │ → artefact
            └──────────────────────────────────────────────┘
                                                              │
     Livraison continue : déploiement en recette automatique, │
     en production sur décision humaine (bouton)  ────────────┤
                                                              │
     Déploiement continu : tout est automatique jusqu'à la    │
     production, si tous les contrôles sont verts  ───────────┘
Intégration continue Livraison continue Déploiement continu
Build et tests à chaque push oui oui oui
Artefact prêt à déployer parfois toujours toujours
Mise en production manuelle, hors pipeline un clic dans le pipeline automatique
Prérequis des tests automatisés + des déploiements scriptés + une grande confiance dans les tests et la supervision

Dans la pratique, on dit souvent « CI/CD » pour l'ensemble. Une agence comme Atlas Web fait typiquement de la livraison continue : chaque fusion dans main part automatiquement en recette, et le chef de projet déclenche la production après validation du client.

3. Anatomie d'un pipeline

Un pipeline est découpé en étapes (stages) qui contiennent des jobs. Les jobs d'une même étape peuvent tourner en parallèle ; les étapes s'enchaînent dans l'ordre.

  étape « vérifier »      étape « tester »        étape « construire »    étape « déployer »
  ┌──────────┐            ┌──────────────┐        ┌──────────────┐        ┌──────────────┐
  │ lint     │            │ tests Node 20│        │ image Docker │        │ recette      │
  │ format   │   ───→     │ tests Node 22│  ───→  │ archive      │  ───→  │ production   │
  └──────────┘            └──────────────┘        └──────────────┘        │ (manuel)     │
                                                                          └──────────────┘
Étape Rôle Exemples
Lint / format vérifier le style et les erreurs évidentes, en quelques secondes ESLint, Prettier, shellcheck, php -l
Tests prouver que le code fait ce qu'il doit tests unitaires, d'intégration, de bout en bout
Sécurité repérer dépendances vulnérables et secrets npm audit, analyse de code, détection de secrets
Build produire l'artefact à déployer archive, image Docker, binaire, application mobile
Déploiement installer l'artefact sur un environnement SSH vers un VPS, Kubernetes, hébergeur

Le pipeline tourne sur un runner (ou exécuteur) : une machine, souvent une machine virtuelle ou un conteneur neuf, fournie par GitHub ou GitLab, ou installée sur vos propres serveurs. Comme elle part de zéro à chaque fois, le « ça marche sur mon poste » disparaît.

Les bonnes propriétés d'un pipeline

  • Rapide : moins de 10 minutes pour le retour principal ; au-delà, les développeurs n'attendent plus le résultat.
  • Fiable : un test qui échoue au hasard (flaky) détruit la confiance ; on le répare ou on le retire.
  • Versionné : le pipeline est un fichier dans le dépôt (.github/workflows/*.yml, .gitlab-ci.yml), relu en pull request comme le code.
  • Rouge = priorité : quand main est cassé, l'équipe répare avant de continuer.

4. Les environnements

Environnement Rôle Qui l'utilise Données
Développement (local) écrire et essayer le développeur fictives
Revue (review app) voir une pull request en ligne relecteurs, designers fictives
Recette / staging valider une version dans des conditions proches de la production chef de projet, client copie anonymisée ou jeu de test
Production servir les vrais clients tout le monde réelles

Règles qui évitent les catastrophes :

  • Le même artefact passe de la recette à la production : on ne reconstruit pas entre les deux, sinon ce qu'on a validé n'est pas ce qu'on déploie.
  • Seule la configuration change d'un environnement à l'autre (adresse de la base, clés d'API), via des variables et des secrets propres à chaque environnement.
  • La production est protégée : déploiement réservé à certaines branches, approbation obligatoire, secrets inaccessibles aux autres jobs.
  • On sait toujours revenir en arrière (rollback) vers la version précédente (leçon 3.2).

5. Le paysage des outils

Outil Où vit le pipeline Particularité
GitHub Actions .github/workflows/*.yml intégré à GitHub, immense catalogue d'actions réutilisables
GitLab CI/CD .gitlab-ci.yml intégré à GitLab, runners installables partout, très utilisé en entreprise
Jenkins Jenkinsfile historique, auto-hébergé, extensible par plugins
Autres Azure Pipelines, Bitbucket Pipelines, CircleCI, Drone/Woodpecker… même logique : un fichier YAML, des étapes, des runners

Les niveaux 1 et 2 de cette formation couvrent GitHub Actions puis GitLab CI. Une fois les principes compris, passer de l'un à l'autre est surtout une affaire de vocabulaire.

6. Un pipeline à la main, pour comprendre

Avant de confier le travail à une plateforme, écrivons le même enchaînement en shell. C'est exactement ce que fera un runner : des commandes, dans l'ordre, avec arrêt à la première erreur.

#!/bin/sh
# scripts/pipeline.sh — pipeline local de la vitrine Atlas
set -e                      # s'arrêter à la première commande qui échoue

echo "== lint"
npm run lint

echo "== tests"
npm test

echo "== build"
mkdir -p dist
tar -czf dist/vitrine.tar.gz package.json src
echo "Artefact prêt : dist/vitrine.tar.gz"
chmod +x scripts/pipeline.sh
./scripts/pipeline.sh
echo "code : $?"            # 0 = pipeline vert ; autre chose = rouge

set -e est la clé : sans lui, le script continuerait après un test en échec et produirait un artefact cassé. Les plateformes de CI appliquent la même règle : une commande qui renvoie un code non nul fait échouer le job.

Vous pouvez même brancher ce pipeline sur Git avec un hook pre-push (formation Git, leçon 3.2) : le push est refusé si le pipeline échoue. C'est utile, mais cela reste sur votre poste et se contourne avec --no-verify. La vraie CI tourne sur le serveur, pour tout le monde, à chaque push.

7. Mesurer : les quatre indicateurs

Pour savoir si votre chaîne s'améliore, les équipes suivent souvent quatre indicateurs (dits « DORA ») :

Indicateur Question
Fréquence de déploiement combien de mises en production par semaine ?
Délai de mise en production combien de temps entre un commit et sa mise en ligne ?
Taux d'échec des changements quelle part des déploiements provoque un incident ?
Temps de restauration combien de temps pour revenir à un service normal après un incident ?

Une bonne CI/CD fait monter les deux premiers et baisser les deux derniers en même temps : on livre plus souvent et plus sûrement, parce que chaque livraison est petite.

8. Par où commencer dans une équipe existante

Inutile de tout automatiser d'un coup. Voici le plan suivi par Atlas Web, sur environ un mois :

Semaine Objectif Résultat visible
1 lint + tests existants lancés à chaque pull request une coche verte ou une croix rouge sur chaque PR
2 main protégée : CI verte et une revue obligatoires plus de push direct, plus de « ça marchait chez moi »
3 build de l'artefact par la CI, déploiement automatique en recette le client voit chaque fusion en ligne le jour même
4 déploiement en production en un clic, avec retour arrière documenté fini les copies FTP du vendredi soir

Ensuite seulement viennent l'optimisation (cache, parallélisme), la sécurité avancée (OIDC, signatures, niveau 4) et, si l'équipe le souhaite, le déploiement continu complet.

Deux conseils pour réussir ce passage :

  • Mesurez avant et après : durée moyenne d'une mise en production, nombre d'incidents par mois. Ces chiffres convainquent mieux qu'un discours.
  • Gardez le pipeline simple et lisible : un fichier YAML que toute l'équipe comprend vaut mieux qu'une usine à gaz que seule une personne sait réparer.

Pièges fréquents

  • Automatiser le chaos : sans tests automatisés, un pipeline ne fait que déployer plus vite des bugs. Commencez par quelques tests sur les fonctions critiques (calcul des prix, paiement).
  • Reconstruire pour la production ce qui a été validé en recette : ce n'est plus le même artefact.
  • Pipeline de 40 minutes : les développeurs poussent moins souvent et contournent la CI. Parallélisez, mettez en cache (leçon 1.3).
  • Ignorer un pipeline rouge « parce que ce test échoue toujours » : réparez-le ou supprimez-le, mais ne vous habituez pas au rouge.

Lab

Dans le projet Node.js /root/vitrine (déjà dans Git, avec un test et un lint), vous construisez un pipeline local :

  1. scripts/pipeline.sh : lint puis tests, arrêt à la première erreur ;
  2. une étape build qui produit l'artefact dist/vitrine.tar.gz, seulement si tout est vert ;
  3. le commit du script, sans l'artefact ;
  4. un hook pre-push qui lance le pipeline avant chaque push.

Les vérifications cassent volontairement un test dans une copie du projet pour s'assurer que votre pipeline devient bien rouge.

Quiz

  1. Quelle différence entre livraison continue et déploiement continu ?
  2. Pourquoi un pipeline s'arrête-t-il à la première étape en échec ?
  3. Qu'est-ce qu'un runner, et pourquoi part-il d'une machine neuve ?
  4. Pourquoi faut-il déployer en production le même artefact que celui validé en recette ?
  5. Que fait set -e dans un script de pipeline ?
Réponses
  1. En livraison continue, chaque version validée est prête et la mise en production se déclenche par une décision humaine ; en déploiement continu, elle part automatiquement en production si tous les contrôles passent.
  2. Pour ne jamais construire ni déployer un code dont on sait qu'il est défectueux, et pour donner un retour rapide sur la cause de l'échec.
  3. C'est la machine (ou le conteneur) qui exécute les jobs du pipeline. Elle part d'un état propre pour que le résultat ne dépende pas de ce qui traîne sur un poste particulier.
  4. Parce que reconstruire peut produire un résultat différent (dépendances mises à jour, autre environnement) : ce qu'on déploierait ne serait plus ce qu'on a testé.
  5. Il arrête le script dès qu'une commande renvoie un code non nul, et le script se termine lui-même en échec.

Sources de référence : GitHub Docs (CC BY 4.0) et GitLab Docs (CC BY-SA 4.0). Texte original MasterLinux.

Exercices pratiques

À réaliser sur Node.js 22 (Debian, git, npm, python3)

Le terminal en ligne ouvre bientôt. En attendant, réalisez ces tâches sur votre machine Linux, une machine virtuelle ou WSL.

  1. Dans /root/vitrine, écrivez le script exécutable scripts/pipeline.sh qui lance d'abord npm run lint, puis npm test, et qui s'ARRÊTE avec un code non nul dès qu'une étape échoue.
    Afficher un indicePremière ligne #!/bin/sh, puis set -e (le script s'arrête à la première commande en échec), puis npm run lint et npm test. chmod +x.
    Voir la solution
    mkdir -p /root/vitrine/scripts && printf '%s\n' '#!/bin/sh' 'set -e' 'echo "== lint"' 'npm run lint' 'echo "== tests"' 'npm test' > /root/vitrine/scripts/pipeline.sh && chmod +x /root/vitrine/scripts/pipeline.sh

    Vérification : cd /root/vitrine && test -x scripts/pipeline.sh && ./scripts/pipeline.sh >/dev/null 2>&1 && d=$(mktemp -d) && cp -r /root/vitrine/. "$d" && echo 'test("casse", () => { throw new Error("casse"); });' >> "$d/test/prix.test.js" && ! (cd "$d" && ./scripts/pipeline.sh >/dev/null 2>&1)

  2. Ajoutez une étape build à la fin du pipeline : elle produit l'archive dist/vitrine.tar.gz contenant package.json et le dossier src/. L'archive ne doit être produite QUE si le lint et les tests ont réussi.
    Afficher un indiceAprès npm test : mkdir -p dist && tar -czf dist/vitrine.tar.gz package.json src. Grâce à set -e, cette ligne n'est jamais atteinte si une étape précédente échoue.
    Voir la solution
    printf '%s\n' '#!/bin/sh' 'set -e' 'echo "== lint"' 'npm run lint' 'echo "== tests"' 'npm test' 'echo "== build"' 'mkdir -p dist' 'tar -czf dist/vitrine.tar.gz package.json src' > /root/vitrine/scripts/pipeline.sh && chmod +x /root/vitrine/scripts/pipeline.sh

    Vérification : cd /root/vitrine && rm -rf dist && ./scripts/pipeline.sh >/dev/null 2>&1 && tar -tzf dist/vitrine.tar.gz | grep -q "src/prix.js" && d=$(mktemp -d) && cp -r /root/vitrine/. "$d" && rm -rf "$d/dist" && echo 'test("casse", () => { throw new Error("casse"); });' >> "$d/test/prix.test.js" && ! (cd "$d" && ./scripts/pipeline.sh >/dev/null 2>&1) && ! test -f "$d/dist/vitrine.tar.gz"

  3. Committez scripts/pipeline.sh. L'archive dist/ ne doit pas être suivie par Git, et le dépôt doit être propre (git status sans rien à signaler).
    Afficher un indicedist/ est déjà dans .gitignore : git add scripts/pipeline.sh puis git commit -m "ci: ajoute le pipeline local"
    Voir la solution
    cd /root/vitrine && git add scripts/pipeline.sh && git commit -qm "ci: ajoute le pipeline local"

    Vérification : cd /root/vitrine && git ls-files | grep -qx scripts/pipeline.sh && ! git ls-files | grep -q "^dist/" && test -z "$(git status --porcelain)"

  4. Faites lancer ce pipeline automatiquement avant chaque git push : créez le hook exécutable .git/hooks/pre-push qui appelle scripts/pipeline.sh (un push sera refusé si le pipeline échoue).
    Afficher un indiceprintf '%s\n' '#!/bin/sh' 'exec ./scripts/pipeline.sh' > .git/hooks/pre-push && chmod +x .git/hooks/pre-push (le hook est lancé depuis la racine du dépôt)
    Voir la solution
    cd /root/vitrine && printf '%s\n' '#!/bin/sh' '# Le push est refuse si le pipeline echoue' 'exec ./scripts/pipeline.sh' > .git/hooks/pre-push && chmod +x .git/hooks/pre-push

    Vérification : cd /root/vitrine && test -x .git/hooks/pre-push && grep -q "pipeline.sh" .git/hooks/pre-push && d=$(mktemp -d) && git init -q --bare "$d/r.git" && git push -q "$d/r.git" HEAD:refs/heads/main >/dev/null 2>&1

Références officielles consultées : GitHub Docs — Intégration continue — https://docs.github.com/fr/actions/get-started/continuous-integration ; GitHub Docs — Déploiement continu — https://docs.github.com/fr/actions/get-started/continuous-deployment ; GitLab Docs — Get started with GitLab CI/CD — https://docs.gitlab.com/ci/ ; GitLab Docs — CI/CD pipelines — https://docs.gitlab.com/ci/pipelines/ ; GitLab Docs — Environments — https://docs.gitlab.com/ci/environments/. Texte original MasterLinux.