Cours 3 · Intégration et livraison continuesLeçon 2 sur 2
Livraison et déploiement continus
7 h de lecture9 sections Version PDF
Livraison contre déploiement, environnements, stratégies bleu-vert, canari et progressive, retour arrière, gestion des versions et portes de validation.
Dans beaucoup d'organisations, la mise en production est un événement. Elle a une date, une réunion de préparation, une liste de vérifications, et elle a lieu un jeudi soir pour laisser le vendredi aux réparations. Quelqu'un veille. Personne n'aime ça.
Dans les organisations dont parlait le chapitre 1, c'est un non-événement. Cela arrive plusieurs fois par jour, personne ne le remarque, et si quelque chose se passe mal, on revient en arrière en quelques secondes.
La différence n'est pas le courage des équipes : c'est le dispositif. Ce chapitre le construit.
Livraison n'est pas déploiement
Deux termes portent les mêmes initiales et désignent deux engagements différents.
La livraison continue garantit que la branche principale est toujours déployable : à tout instant, un artefact validé existe et pourrait partir en production. La décision de partir reste humaine.
Le déploiement continu va au bout : toute modification qui passe le pipeline part en production automatiquement, sans intervention.
commit → construction → tests → artefact → [recette] → ⏸ décision → production │ livraison continue ─┘ déploiement continu : pas de pauseLe second n'est pas « mieux » : c'est un choix qui dépend du contexte. Un service en ligne interne y gagne. Un logiciel embarqué dans un dispositif médical, un système bancaire soumis à une validation réglementaire, ou un produit installé chez des clients ne peuvent pas s'y conformer — et n'ont pas à le faire.
Mais la livraison continue, elle, est toujours souhaitable, y compris pour ces cas-là : savoir qu'on pourrait déployer à tout instant est ce qui rend le choix de ne pas le faire délibéré plutôt que subi.
Les environnements, et la règle qui les gouverne
développement → recette (staging) → productionChacun sert à une chose différente : le développement à écrire, la recette à valider dans des conditions proches du réel, la production à servir les utilisateurs.
La règle qui compte tient en une phrase : le même artefact traverse les environnements. L'image construite par le pipeline du chapitre 5 est déployée en recette, validée, puis promue en production — pas reconstruite.
Reconstruire par environnement ruine la garantie centrale du bloc : ce qui a été testé n'est alors plus exactement ce qui tourne. Une version de dépendance a bougé entre les deux constructions, une couche de base a été mise à jour, et le bogue n'apparaît qu'en production.
Ce qui change d'un environnement à l'autre, c'est donc uniquement la configuration — variables d'environnement, secrets, adresses de services — injectée au démarrage, comme au chapitre 3.
Deux conséquences pratiques. L'artefact est immuable et porte un identifiant unique, qui permet de remonter du conteneur en production au commit exact qui l'a produit. Et la recette doit ressembler à la production : mêmes versions, mêmes volumes de données autant que possible — une recette avec cent enregistrements ne dit rien du comportement sur dix millions.
Quatre stratégies de déploiement
C'est le cœur pratique du chapitre, et le choix se fait sur trois critères : exposition en cas de bogue, vitesse de retour arrière, coût en ressources.
| Stratégie | Principe | Exposition | Retour arrière | Coût |
|---|---|---|---|---|
| Recréation | arrêter, remplacer, redémarrer | 100 % | redéployer l'ancienne | nul |
| Bleu-vert | deux environnements complets, bascule du routage | 100 % à la bascule | instantané | double |
| Progressif | remplacer les exemplaires un à un | croissante | progressif | faible |
| Canari | router une petite part du trafic vers la nouvelle version | 5 % puis paliers | instantané | faible |
La recréation est la seule qui provoque une interruption de service : elle reste acceptable pour un outil interne, jamais pour un service public.
Le bleu-vert maintient deux environnements complets. On déploie sur l'inactif, on le teste en conditions réelles sans trafic, puis on bascule le routage. Le retour arrière est le même geste en sens inverse : quelques secondes. Le prix est de payer deux environnements.
Le déploiement progressif remplace les exemplaires un par un, en maintenant un nombre minimal d'exemplaires disponibles. C'est le comportement par défaut de Kubernetes, au chapitre 9.
Le canari est le plus prudent : la nouvelle version reçoit d'abord une petite fraction du trafic, on mesure, et l'on progresse par paliers.
La version 1 sert l'intégralité du trafic, avec un taux d'erreur de référence de 0,1 %. C'est ce chiffre qui servira de comparant : sans ligne de base mesurée, aucune stratégie progressive n'a de sens.
Ce que l'animation montre, et qui est le point du chapitre : le canari n'empêche pas la panne. Le bogue était là, il est parti en production, et des utilisateurs l'ont subi. Ce que le dispositif a changé, c'est son ampleur — un quart du trafic au lieu de la totalité — et sa durée — quatre minutes au lieu du temps nécessaire pour s'apercevoir du problème puis reconstruire une version.
C'est le renversement conceptuel du bloc : on ne cherche plus à empêcher tout incident, ce qui est hors d'atteinte, mais à réduire le rayon d'impact et le temps de rétablissement. Les deux derniers indicateurs DORA du chapitre 1 mesurent exactement cela.
Une condition, toutefois, sans laquelle le canari ne sert à rien : il faut des mesures et un seuil décidé à l'avance. Faire du canari sans supervision, c'est exposer 5 % des utilisateurs et attendre qu'ils se plaignent — le chapitre 10 fournit ce qui manque.
Le retour arrière
C'est la capacité la plus importante du chapitre, et la plus souvent négligée.
Un retour arrière doit être testé. Un mécanisme jamais exécuté ne fonctionne pas le jour où l'on en a besoin — et ce jour-là, personne n'est en état de le déboguer. Les équipes sérieuses en déclenchent régulièrement, hors incident.
Il doit être plus rapide que la réparation. Face à un incident, la tentation est de corriger en avant : trouver le bogue, écrire le correctif, le faire passer dans le pipeline, déployer. Cela prend au minimum une demi-heure, souvent plus, et sous pression. Revenir à la version précédente prend quelques secondes, et on diagnostique ensuite, à froid.
Le point dur est la base de données. Le code revient en arrière ; les données, non. Une migration qui a supprimé une colonne rend l'ancienne version incapable de fonctionner. La parade est la migration compatible en avant, en plusieurs étapes :
étape 1 ajouter la nouvelle colonne, écrire dans les DEUXétape 2 déployer le code qui lit la nouvelleétape 3 plus tard, quand le retour arrière n'est plus envisagé, cesser d'écrire dans l'ancienne, puis la supprimerC'est plus long à écrire, et c'est ce qui rend le retour arrière possible à tout moment. La règle qui en découle : jamais de suppression ni de renommage destructif dans le même déploiement que le code qui en dépend.
Versions, artefacts, et portes manuelles
La version sémantique — MAJEUR.MINEUR.CORRECTIF — communique la nature d'un changement :
un MAJEUR incrémenté annonce une rupture de compatibilité. Elle est indispensable pour une
bibliothèque publiée ; pour un service déployé en continu, on lui préfère souvent une simple
étiquette horodatée ou l'empreinte du commit, qui donne la traçabilité : de l'incident au
conteneur, du conteneur à l'artefact, de l'artefact au commit.
Restent les portes de validation manuelles. Elles sont légitimes dans trois cas : une exigence réglementaire, une fenêtre de déploiement contrainte par le métier, ou une décision commerciale sur la date de mise à disposition d'une fonctionnalité.
Elles sont du théâtre dans un cas, très fréquent : quand la personne qui valide n'a pas les moyens de décider. Cliquer « approuver » sans lire un tableau de bord ni disposer d'un critère explicite ne réduit aucun risque ; cela ajoute un délai et une signature. Si la porte est là pour rassurer, il vaut mieux se demander ce qui manque au dispositif pour qu'on n'ait plus besoin d'être rassuré — c'est presque toujours de la mesure.
Une équipe reconstruit son image à chaque environnement : une pour la recette, une pour la production. Où est le problème ?
Un déploiement introduit un bogue. L'équipe cherche la cause pour corriger en avant. Que dit ce chapitre ?
À vous
L'exercice met les quatre stratégies sur le même incident et calcule ce qui compte vraiment.
On injecte un bogue qui produit un taux d'erreur donné, et le programme calcule pour chaque stratégie le nombre d'utilisateurs touchés et la durée d'exposition, en tenant compte du délai de détection. Vous verrez que le classement dépend du délai de détection : sans supervision, le canari perd une grande partie de son intérêt — ce qui prépare le chapitre 10.
La seconde partie porte sur la migration de base de données. Vous exécuterez un scénario de retour arrière après une migration destructive — l'ancienne version ne démarre plus — puis vous réécrirez la migration en trois étapes compatibles en avant, et vous vérifierez que le retour arrière redevient possible à chaque étape.
Chiffrez l'impact des quatre stratégies selon le délai de détection, puis rendez une migration réversible.
// ── 1. Quatre stratégies face au même bogue ─────────────────────────────── const TRAFIC = 1000; // requêtes par minute const TAUX_ERREUR = 0.30; // 30 % des requêtes servies par v2 échouent // paliers : [part du trafic, durée du palier en minutes] const STRATEGIES = { "recréation": { paliers: [[1.0, Infinity]], interruption: 2, retour: 8 }, "bleu-vert": { paliers: [[1.0, Infinity]], interruption: 0, retour: 0.2 }, "progressif": { paliers: [[0.2, 2], [0.4, 2], [0.6, 2], [0.8, 2], [1.0, Infinity]], interruption: 0, retour: 3 }, "canari": { paliers: [[0.05, 10], [0.25, 10], [0.5, 10], [1.0, Infinity]], interruption: 0, retour: 0.2 }, }; // detection : combien de minutes avant que quelqu'un s'en aperçoive. function impact(strategie, detection) { let t = 0, requetesRatees = 0; for (const [part, duree] of strategie.paliers) { const restant = detection - t; if (restant <= 0) break; const passe = Math.min(duree, restant); // ← à écrire : requêtes ratées pendant ce palier t += passe; } // Puis le retour arrière, pendant lequel la part courante continue. return { requetesRatees: Math.round(requetesRatees), duree: detection + strategie.retour }; } // ── 2. Migration de base et retour arrière ──────────────────────────────── // Un schéma, deux versions de code, et la question : peut-on revenir ? const SCHEMA = { colonnes: ["id", "nom_complet"] }; const MIGRATION_DESTRUCTIVE = [ { nom: "v2 : renommer nom_complet en nom", appliquer: (s) => ({ colonnes: s.colonnes.map((c) => (c === "nom_complet" ? "nom" : c)) }) }, ]; const CODE = { v1: { lit: ["id", "nom_complet"], ecrit: ["nom_complet"] }, v2: { lit: ["id", "nom"], ecrit: ["nom"] }, }; function peutTourner(version, schema) { const besoins = [...CODE[version].lit, ...CODE[version].ecrit]; return besoins.every((c) => schema.colonnes.includes(c)); } // ── À VOUS ──────────────────────────────────────────────────────────────── // 1. Écrivez impact(). Comparez les quatre stratégies avec une détection à // 2 min (supervision), puis à 45 min (une plainte utilisateur). // 2. Appliquez la migration destructive, déployez v2, puis tentez le retour // à v1 : que se passe-t-il ? // 3. Réécrivez la migration en TROIS étapes compatibles en avant, et // vérifiez qu'après chacune, les DEUX versions peuvent tourner. console.log(JSON.stringify(impact(STRATEGIES["canari"], 2)));
En travaux pratiques
Bleu-vert, canari, retour arrière
Déployer l'artefact du TP 5 selon deux stratégies, mesurer ce que chacune expose en cas de bogue, et rendre une migration de base réversible.
- L'image publiée par le pipeline du TP 5, étiquetée par empreinte de commit
- La pile Compose du TP 4
- Un outil de charge simple (ab, hey, ou une boucle curl)
- 1. Monter le routage
Placez un répartiteur devant l'application. Faites tourner DEUX exemplaires de la pile, en version 1.0, et vérifiez que le trafic se répartit sur les deux.
- 2. Déployer en bleu-vert
Construisez une version 1.1, déployez-la à côté sans lui envoyer de trafic, testez-la directement, puis basculez le routage d'un coup. Chronométrez la bascule et le retour arrière.
- 3. Fabriquer un bogue
Produisez une version 1.2 qui renvoie une erreur sur 30 % des requêtes. Déployez-la en bleu-vert pendant qu'une charge tourne, et comptez les requêtes en erreur avant que vous ne réagissiez.
- 4. Recommencer en canari
Même version fautive, mais en n'envoyant d'abord que 5 % du trafic, puis 25 %. Comptez à nouveau les requêtes en erreur, et comparez à l'étape précédente.
- 5. Décider automatiquement
Écrivez un script qui interroge le taux d'erreur toutes les dix secondes et déclenche le retour arrière au-delà d'un seuil que vous fixez d'avance. Relancez le scénario sans intervenir.
- 6. La migration destructive
Version 1.3 : renommez une colonne de la base et adaptez le code. Déployez, puis tentez un retour arrière vers 1.2. Constatez ce qui se passe.
- 7. La migration en trois étapes
Refaites la même évolution en la découpant, de sorte qu'à chaque étape les DEUX versions puissent tourner. Vérifiez le retour arrière après chacune.
- Le retour arrière prend moins de cinq secondes et ne reconstruit rien
- Le canari expose au moins quatre fois moins de requêtes que le bleu-vert sur le même bogue
- Le script déclenche le retour arrière sans vous
- Après chaque étape de la migration découpée, l'ancienne version démarre encore
Ce que la suite en fait
Le bloc IV pose la question laissée de côté : sur quoi déploie-t-on ? Les serveurs, réseaux et bases de ce chapitre ont été supposés existants ; le chapitre 7 les décrit dans des fichiers versionnés, ce qui permet de reconstruire un environnement de recette identique à la production — condition de la règle posée plus haut.
Et le chapitre 10 fournira ce qui manque au canari : sans métriques et sans seuil décidé à l'avance, la décision de progresser ou de revenir n'a aucune base.
À retenir
Vous avez parcouru les 9 sections.
Marquez-la terminée pour faire avancer votre parcours, ou revenez sur un point avant de passer à la suite.