Chapitre 13.1 — Pourquoi le CI/CD
⏱️ TL;DR — Déployer à la main, c’est répéter une checklist mentale (SSH,
git pull, build, redémarrer, vérifier) sans jamais en oublier une étape — un pari qu’on perd tôt ou tard. Le CI/CD remplace ce rituel par une machine. La CI (intégration continue) build et teste ton code à chaque push : elle attrape les régressions avant qu’elles arrivent en prod. La CD (déploiement continu) prend le relais et déploie automatiquement ce qui a passé les tests. Le pipeline idéal est une chaîne :push → lint → test → build → déploiement → healthcheck. Objectif : un déploiement répétable, testé, sans intervention humaine — donc plus fréquent, plus fiable, avec un historique et un rollback rapide. On pose ici le décor ; les chapitres suivants construisent chaque maillon.
🎯 Objectifs
- Nommer précisément pourquoi le déploiement manuel produit des erreurs.
- Distinguer CI (intégration continue) et CD (déploiement continu / livraison continue).
- Décrire le pipeline idéal étape par étape et le rôle de chaque maillon.
- Comprendre ce qu’on gagne : fréquence, fiabilité, rollback, historique.
- Situer où le cours va construire chaque brique (13.2 à 13.5).
Le déploiement manuel : un piège qui se referme lentement
Aujourd’hui, livrer une nouvelle version de FormaCampus ressemble à ça :
ssh deploy@formacampus.fr # 1. se connecter au serveur
cd /var/www/formacampus # 2. aller dans le bon dossier
git pull origin main # 3. récupérer le nouveau code
npm ci # 4. installer les dépendances
npm run build # 5. builder la version de prod
sudo systemctl restart formacampus-web # 6. redémarrer le service
curl -I https://formacampus.fr # 7. vérifier que ça répondSept étapes. Tant que tu es concentré et reposé, ça passe. Le problème n’est pas une exécution : ce sont les cent suivantes. Le déploiement manuel échoue parce qu’il est humain, et l’humain :
- oublie des étapes — tu
git pullet tu redémarres, mais tu oubliesnpm ci: la prod tourne avec d’anciennes dépendances, et un bug surgit « sans raison » ; - oublie l’ordre — tu redémarres le service avant que le build soit fini, et tu sers une version à moitié buildée ;
- oublie les à-côtés — la migration de base qui devait accompagner le déploiement passe à la trappe, et l’app plante sur une colonne qui n’existe pas ;
- ne teste pas — rien ne garantit que le code poussé passe les tests ; tu le découvres en prod, chez tes utilisateurs ;
- ne laisse pas de trace — qui a déployé quoi, quand, à partir de quel commit ? Personne ne sait. Impossible de comprendre un incident a posteriori.
⚠️ Piège — « Ça marchait sur ma machine. » C’est la phrase-symptôme du déploiement non reproductible. Ton poste a une version de Node différente, des variables d’environnement traînantes, des dépendances installées « à la main » il y a six mois. Le serveur, lui, part de zéro. Un build testé dans un environnement propre (la CI) élimine cette classe entière de bugs : si ça build et teste vert dans la CI, ça buildera pareil partout.
💡 Réflexe — Si une opération de déploiement tient dans ta tête sous forme de « checklist à ne pas oublier », c’est qu’elle devrait être un script. Et si c’est déjà un script, il devrait être déclenché automatiquement. La règle : tout ce qu’un humain fait deux fois de la même manière, une machine doit le faire à sa place — sans se tromper, sans se fatiguer, sans oublier.
CI et CD : deux moitiés d’une même chaîne
On parle de « CI/CD » d’un bloc, mais ce sont deux idées distinctes qu’on empile.
CI — l’intégration continue
La CI (Continuous Integration) répond à une question : « le code qu’on vient de pousser est-il sain ? ». À chaque push (ou chaque pull request), un serveur automatique récupère le code dans un environnement propre et neuf, et vérifie :
- que les dépendances s’installent (
npm ci) ; - que le code respecte les règles de style (lint) ;
- que les tests passent (unitaires, d’intégration) ;
- que le projet build (
next build, compilation, typecheck).
Si une seule de ces étapes échoue, la CI crie (badge rouge, e-mail, notification) avant que le code n’aille en prod. La CI, c’est le filet de sécurité qui attrape les régressions au plus tôt — quand elles coûtent le moins cher à corriger.
CD — le déploiement continu
La CD prend le relais quand la CI est verte. Deux nuances de sens que tu croiseras :
- Livraison continue (Continuous Delivery) : le code testé est prêt à être déployé en un clic, mais un humain déclenche la mise en prod.
- Déploiement continu (Continuous Deployment) : la mise en prod est entièrement automatique dès que la CI passe — pas de clic humain.
Dans ce cours, on vise le déploiement continu sur main : un merge validé et testé part en prod tout seul. Rien n’empêche, sur des projets plus sensibles, de garder une approbation manuelle avant la bascule (livraison continue) — c’est une question de curseur, pas de nature.
| CI — intégration continue | CD — déploiement continu | |
|---|---|---|
| Question | « Le code est-il sain ? » | « Le code sain part-il en prod ? » |
| Déclencheur | chaque push / PR | CI verte sur la branche de prod |
| Étapes | install, lint, test, build | déploiement, migration, healthcheck |
| Échec = | on ne merge pas | on ne déploie pas (ou on rollback) |
| Gain | régressions attrapées tôt | livraison rapide et répétable |
💡 Réflexe — CI sans CD est déjà énorme : même si tu déploies encore à la main, avoir une CI qui teste chaque PR t’évite la moitié des incidents. Commence par la CI (elle ne touche pas à ta prod, donc zéro risque à la mettre en place), puis branche la CD une fois que tu lui fais confiance.
Le pipeline idéal
Mis bout à bout, CI et CD forment une chaîne de montage. Chaque maillon ne se déclenche que si le précédent a réussi.
Lisons la chaîne :
- Push — tu merges sur
main. C’est le seul geste humain. Tout le reste est automatique. - Lint — le code respecte-t-il les conventions ? Rapide, ça élimine les fautes de style et certaines erreurs bêtes.
- Tests — la logique est-elle correcte ? Les tests qui échouent arrêtent la chaîne ici : rien ne partira en prod.
- Build — le projet compile-t-il en version de production ? On produit l’artefact (le build figé) qui sera déployé.
- Déploiement — l’artefact est envoyé sur le VPS et activé (on verra comment, par releases + symlink, au 13.4).
- Healthcheck — le site répond-il vraiment après la bascule ? On teste une URL de santé. Si elle échoue, on revient en arrière automatiquement.
- En ligne — la nouvelle version sert le trafic. Trace complète : quel commit, quand, par qui.
L’idée-force tient en trois mots : répétable, testé, sans intervention humaine. Répétable parce que c’est un script, pas une mémoire faillible. Testé parce que rien ne passe sans être vert. Sans intervention parce que la seule action manuelle, c’est le git push — le reste est une réaction en chaîne déterministe.
⚠️ Piège — Un build qui casse la prod parce qu’il a lieu sur le serveur, en direct, sans filet. Si tu fais
git pull && npm run buildsur le VPS et que le build échoue à moitié (mémoire insuffisante, erreur de compilation), tu te retrouves avec un dossier de build corrompu que le service essaie de servir. Le pipeline idéal build avant de toucher à la prod, et ne bascule que sur un artefact entier et validé.
Ce qu’on gagne concrètement
Automatiser n’est pas un caprice d’ingénieur. Les bénéfices sont mesurables :
- Fréquence — quand déployer coûte cinq minutes de rituel stressant, on déploie rarement, on accumule les changements, et chaque livraison devient un gros bloc risqué. Quand déployer, c’est merger, on déploie souvent, par petits incréments faciles à déboguer.
- Fiabilité — la machine ne saute pas d’étape et ne se trompe pas d’ordre. Les incidents de déploiement chutent.
- Rollback rapide — un problème en prod ? On revient à la version précédente en quelques secondes (repointer un symlink, 13.4) au lieu de réparer à chaud sous stress.
- Historique — chaque déploiement laisse une trace (quel commit, quel workflow, quels tests). En cas d’incident, on sait exactement ce qui a changé et on corrèle avec le moment où ça a cassé.
🔒 Sécurité — Automatiser le déploiement, c’est aussi retirer des mains des développeurs les accès SSH de prod. Au lieu que chacun se connecte au serveur avec ses droits pour déployer, c’est la CI qui déploie, via une clé dédiée à portée limitée (on le voit au 13.5). Moins de personnes touchent la prod directement = moins de surface d’erreur et de compromission. Le pipeline devient le seul chemin vers la production, donc le seul à sécuriser.
🧭 Sur FormaCampus — Avant ce chantier, l’équipe FormaCampus déployait « quand quelqu’un avait le temps » : un dev se connectait en SSH, tirait le code, buildait sur le VPS Ubuntu, redémarrait le service. Résultat : des déploiements rares (donc gros et risqués), des « ça marchait chez moi », et un incident mémorable où une migration oubliée a mis l’API Symfony à genoux un vendredi. La cible : chaque merge sur
maindéclenche build + tests + déploiement par releases, avec rollback en un clic. Déployer redevient banal — et c’est justement le but : un déploiement ne doit rien avoir d’un événement.
📚 La doc — Les concepts CI/CD sont indépendants de l’outil. La documentation de GitHub Actions (qu’on utilisera au 13.3) est une bonne porte d’entrée, mais les mêmes idées existent chez GitLab CI, Forgejo/Woodpecker, Jenkins ou Drone. On apprend le modèle mental ; l’outil est interchangeable.
Ce qu’il faut retenir
Le déploiement manuel n’est pas « plus simple » : il est plus fragile, parce qu’il dépend d’un humain qui n’oublie rien, jamais. La CI teste chaque changement dans un environnement propre ; la CD déploie ce qui est vert. Le pipeline idéal enchaîne push → lint → test → build → déploiement → healthcheck, chaque maillon conditionné au précédent. On y gagne des déploiements fréquents, fiables, tracés et réversibles. Les chapitres suivants construisent cette chaîne : le script de base (13.2), son automatisation (13.3), le déploiement sans coupure (13.4) et la gestion des secrets (13.5).
✏️ Exercices
Exercice 1 — Nomme les failles. Un collègue déploie ainsi : il git pull sur le serveur, puis sudo systemctl restart le service, sans rien d’autre. Cite trois problèmes concrets que cette méthode peut causer, et dis pour chacun ce que le pipeline idéal apporterait.
✅ Solution
Par exemple : (1) Dépendances non installées — il oublie npm ci, donc la prod tourne avec d’anciennes dépendances ; le pipeline exécute toujours l’installation, dans le bon ordre. (2) Aucun test — un bug part directement chez les utilisateurs ; la CI aurait arrêté la chaîne avant le déploiement. (3) Pas de build ou build à moitié — il redémarre sur un build périmé ou corrompu ; le pipeline build un artefact complet et validé avant de basculer. On accepte aussi : migration de base oubliée, aucune trace de ce qui a été déployé, aucun rollback possible.
Exercice 2 — CI ou CD ? Classe chacune de ces étapes en CI ou CD : (A) lancer les tests unitaires à chaque pull request ; (B) copier l’artefact buildé sur le VPS et basculer le symlink ; (C) vérifier que next build réussit ; (D) faire un curl sur l’URL de santé après la bascule ; (E) lancer le linter.
✅ Solution
CI (le code est-il sain ?) : A (tests), C (build), E (lint). CD (le code sain part-il en prod ?) : B (déploiement/bascule), D (healthcheck post-déploiement). Repère : tout ce qui valide le code sans toucher à la prod est de la CI ; tout ce qui agit sur le serveur de production est de la CD.
🧠 Quiz de révision
1. Quelle est la différence entre CI et CD ?
La CI (intégration continue) build et teste le code à chaque push, dans un environnement propre, pour attraper les régressions tôt — elle ne touche pas à la prod. La CD (déploiement/livraison continue) déploie en production ce qui a passé la CI. CI = « le code est-il sain ? » ; CD = « le code sain part-il en prod ? ».
2. Cite les étapes du pipeline idéal, dans l’ordre.
push → lint → test → build → déploiement → healthcheck (puis « en ligne », ou rollback si le healthcheck échoue). Chaque maillon ne se déclenche que si le précédent a réussi : un test rouge arrête la chaîne avant tout déploiement.
3. Pourquoi « ça marchait sur ma machine » disparaît-il avec une CI ?
Parce que la CI build et teste dans un environnement propre et neuf, identique à chaque fois, sans les particularités de ton poste (version de Node, variables traînantes, dépendances installées à la main). Si ça passe en CI, ça passera pareil ailleurs. La CI supprime la dépendance à l’environnement local.
4. Cite trois bénéfices concrets de l’automatisation du déploiement.
Au choix parmi : fréquence (on déploie souvent, par petits incréments faciles à déboguer), fiabilité (la machine ne saute pas d’étape), rollback rapide (retour à la version précédente en secondes), historique (trace de quel commit a été déployé, quand, pour corréler un incident).
5. Pourquoi vaut-il mieux builder dans la CI que directement sur le serveur de prod ?
Parce que builder sur le serveur en direct peut casser la prod : si le build échoue à moitié (mémoire, erreur de compilation), le service se retrouve avec un dossier de build corrompu. Builder dans la CI produit un artefact complet et validé ; on ne bascule la prod que sur cet artefact entier, sans jamais la laisser dans un état intermédiaire.
Chapitre suivant : 13.2 — Déployer par git — la brique manuelle qu’on va automatiser : un script deploy.sh robuste, lancé en SSH, et les git hooks pour un git push qui déploie.