Be Software Architecture Wise
Be Wise Apps

Read in English · Leer en español · Auf Deutsch lesen

Section 10.5 sur 10.8 · Intermédiaire · 22 min de lecture

Pipelines CI/CD et stratégies de déploiement

Leçon vidéo

5 min · narré en anglais, avec sous-titres
Écouter seulement (audio)
Lire la transcription

À quelle vitesse, et avec quelle sécurité, votre équipe peut-elle changer quoi que ce soit ? C’est le pipeline de déploiement qui en décide. Dans cette leçon, vous allez suivre un changement du commit à la production, et découvrir les stratégies qui limitent les dégâts qu’une mauvaise version peut causer.

Pensez à une chaîne de boulangeries qui lance un nouveau pain. Elle cuit une fournée d’essai, et la vérifie dans sa propre cuisine. Puis elle le vend dans une seule boutique pendant une matinée, avant de l’envoyer dans toutes les boutiques. Si des clients se plaignent, une seule boutique a été touchée, et l’ancien pain est toujours en rayon. Un pipeline, c’est cette routine, automatisée : chaque changement est construit une fois, vérifié par étapes, essayé sur quelques utilisateurs, et diffusé seulement quand les éléments recueillis sont bons. Et un interrupteur distinct décide du moment où les clients voient une nouvelle fonctionnalité.

Le pipeline de déploiement, décrit par Jez Humble et David Farley en 2010, fait passer chaque commit par des étapes automatisées, les plus rapides d’abord. L’étape de commit compile, exécute les tests unitaires et les contrôles, et devrait prendre moins de dix minutes. L’étape d’empaquetage construit une seule image de conteneur, avec une nomenclature logicielle, la signe et la pousse vers le dépôt d’artefacts, une seule fois. Les tests d’acceptation, le staging et la production déploient ensuite tous exactement cette même image. Un changement n’avance vers la droite que si l’étape précédente a réussi. C’est le principe build once, deploy many. Seule la configuration diffère d’un environnement à l’autre. Si vous reconstruisez pour la production, ce que vous avez testé n’est pas ce que vous livrez. Et tout échec arrête la chaîne et revient directement à l’auteur, pendant que le changement est encore frais dans son esprit.

Une stratégie de déploiement décide combien d’utilisateurs une mauvaise version peut toucher avant d’être arrêtée. La recréation arrête toutes les anciennes instances, puis démarre les nouvelles : c’est simple, mais il y a une interruption, et tout le monde rencontre une mauvaise version en même temps. Le déploiement progressif remplace les instances quelques-unes à la fois, et c’est le comportement par défaut de Kubernetes. Revenir en arrière prend autant de temps que le déploiement. Le bleu-vert fait tourner un nouvel environnement complet à côté de l’environnement actif, le teste, puis bascule tout le trafic au niveau du routeur. Le retour arrière est rapide, mais il vous faut jusqu’au double de capacité pendant la bascule. Un canari envoie une petite part du trafic, disons un à cinq pour cent, vers la nouvelle version, compare ses métriques, puis élargit par paliers. Un déploiement fantôme copie les vraies requêtes vers la nouvelle version mais ne renvoie jamais ses réponses : les effets de bord comme les paiements doivent donc être supprimés. Chaque fois que deux versions tournent en même temps, elles doivent être compatibles avec les données et les messages l’une de l’autre.

Voici un canari avec analyse automatisée. Les utilisateurs atteignent un routeur de trafic : un équilibreur de charge ou un service mesh. Quatre-vingt-dix pour cent du trafic va vers le parc de production, qui exécute la version un. Cinq pour cent va vers une référence neuve de la version un, et cinq pour cent vers le canari, la version deux. Comparer à une référence neuve élimine les différences dues uniquement aux caches chauds et à une longue durée de fonctionnement. Une étape d’analyse compare les erreurs, la latence et la saturation, puis élargit le canari à vingt-cinq pour cent, ou l’annule. C’est le système qui décide, pas une personne qui surveille des tableaux de bord. C’est la livraison progressive.

Le déploiement installe une nouvelle version dans un environnement. La mise en production rend un comportement accessible aux utilisateurs. Les feature flags les séparent : le code est déployé désactivé, et mis en production plus tard, progressivement et de façon réversible. Chaque flag a un coût de possession : donnez donc aux flags des dates d’expiration, et supprimez-les une fois la décision arrêtée. Et comme les données ne peuvent pas revenir en arrière comme le code, les changements de schéma doivent être rétrocompatibles : d’abord l’expansion, et la contraction seulement dans une version ultérieure.

Assemblons tout cela. Le service de commandes change sa façon de calculer les frais de livraison. Le nouveau calculateur se trouve derrière un flag de mise en production, désactivé, et une migration d’expansion seule ajoute une nouvelle colonne. Le changement est fusionné à dix heures deux. Le lint, les tests unitaires et les analyses prennent six minutes, et une image signée est poussée à dix heures neuf. La migration additive s’exécute comme une étape à part à dix heures et quart. La version en cours d’exécution ignore la nouvelle colonne, donc rien ne casse. Puis la même image réussit les tests de staging. À dix heures trente-cinq, cinq pour cent du trafic de production va vers la nouvelle version, flag toujours désactivé. Vingt minutes d’analyse par rapport à une référence neuve : réussite. Le trafic passe à vingt-cinq, cinquante puis cent pour cent par paliers de quinze minutes, et l’opération se termine à onze heures quarante. Le déploiement est terminé, et pourtant aucun client n’a vu les nouveaux frais. Le lendemain, la responsable produit active le flag pour dix pour cent des clients d’une ville, puis l’élargit à toutes les villes en une semaine. Le risque de déploiement et le risque de mise en production ont été traités séparément, chacun avec un petit rayon d’impact.

La section complète traite du développement basé sur le tronc, des quatre types de feature flags, et du choix entre retour arrière et roll forward. Ensuite, dans la section dix point six, nous verrons comment fonctionner sur plusieurs régions. À très vite.

Ce qu’il faut savoir

Du commit à la production : à quoi sert un pipeline

La section 0.8 (comment les logiciels sont construits) a présenté l’intégration continue (chaque changement est fusionné et vérifié automatiquement), la livraison continue (la branche principale peut toujours être mise en production) et le déploiement continu (chaque changement qui passe les contrôles va en production sans décision humaine). Cette section les traite comme de l’architecture : la conception du chemin que suit un changement, et les stratégies qui l’amènent en production sans nuire aux utilisateurs.

L’idée centrale est le pipeline de déploiement, décrit par Jez Humble et David Farley dans Continuous Delivery (2010). Chaque commit déclenche une séquence automatisée d’étapes. Les premières étapes sont rapides et peu coûteuses, et détectent la plupart des problèmes ; les suivantes sont plus lentes, plus réalistes et plus coûteuses. Un changement ne passe à l’étape suivante que si la précédente a réussi : plus un build avance, plus il a gagné la confiance. Un échec, où qu’il se produise, arrête ce build et revient directement à la personne qui a fait le changement, pendant qu’elle l’a encore bien en tête.

Le pipeline compte pour les architectes pour trois raisons. D’abord, c’est là que la déployabilité, un attribut de qualité vu en section 2.6, est réellement obtenue ou perdue. Ensuite, sa vitesse limite la rapidité avec laquelle l’organisation peut réagir à une évolution du marché ou à une vulnérabilité de sécurité : si un correctif d’une ligne met deux jours à atteindre la production, l’architecture a deux jours de retard, quel que soit l’aspect du code. Enfin, la forme du système contraint la forme du pipeline : des services déployables indépendamment peuvent avoir des pipelines indépendants, mais un monolithe distribué impose des mises en production coordonnées, aussi astucieux que soient les outils.

Les étapes d’un pipeline typique

Un pipeline de déploiement : commit, build, empaquetage, tests d’acceptation, staging et production, avec un artefact poussé une fois dans un dépôt et récupéré par chaque étape suivanteCommitpush sur mainou fusion de PRBuildcompiler, testsunit., lintPaquetimage + SBOMsigner, pushAcceptationtests APIet de contratStagingdéployer, smoketestsProductioncanari, puisgénéralisationChaque étape est automatisée ; un changement n’avance que si l’étape précédente a réussiDépôt d’artefactsune image immuable par commit, adressée par son digestpush uniquepull de la même imageTout échec arrête la chaîne et avertit l’auteur en quelques minutes
Un artefact est construit et poussé une seule fois ; chaque étape suivante déploie exactement cet artefact, et tout échec arrête la chaîne.

Ce que fait chaque étape et combien de temps elle devrait prendre

  1. Étape de commit (objectif : moins de 10 minutes)Compiler, exécuter les tests unitaires, les linters, l’analyse statique et l’analyse des vulnérabilités des dépendances. C’est l’étape que les développeurs attendent, elle doit donc être rapide ; les tests lents viennent plus tard.
  2. EmpaquetageConstruire l’artefact déployable (généralement une image de conteneur), générer une nomenclature logicielle (SBOM), la signer et la pousser vers le dépôt d’artefacts. Les contrôles de la chaîne d’approvisionnement sont traités en section 8.6.
  3. Acceptation et intégrationDéployer l’artefact dans un environnement de test temporaire ou partagé et exécuter des tests d’API, des tests de contrat pilotés par le consommateur et quelques parcours de bout en bout. Les tests de performances et de sécurité peuvent s’exécuter ici en parallèle ou selon un calendrier.
  4. StagingDéployer dans un environnement configuré comme la production, appliquer les migrations de base de données, exécuter les smoke tests. Sa valeur dépend de sa ressemblance avec la production en matière de configuration, de forme des données et de dépendances.
  5. ProductionDéployer avec une stratégie qui limite l’exposition (progressive, bleu-vert ou canari), vérifier avec de vraies métriques par rapport aux objectifs de niveau de service, puis terminer ou revenir en arrière automatiquement.

Build once, deploy many, et le dépôt d’artefacts

Une règle de Continuous Delivery encore enfreinte étonnamment souvent est build once, deploy many (construire une fois, déployer partout) : compiler et empaqueter chaque changement exactement une fois, puis promouvoir ce même artefact dans chaque environnement. Si une équipe reconstruit pour le staging, puis à nouveau pour la production, ce qu’elle a testé n’est pas ce qu’elle a livré. Un correctif différent du compilateur, une dépendance résolue pendant la nuit vers une version plus récente ou une image de base modifiée peuvent faire diverger les deux builds, et les tests ne prouvent rien sur le second.

Ce qui diffère d’un environnement à l’autre, c’est la configuration, fournie au moment du déploiement ou du démarrage (adresses de bases de données, identifiants, réglages des feature flags), jamais intégrée à l’artefact. C’est le facteur de configuration de l’application douze facteurs. Une image de conteneur étiquetée orders:4f1c2ab (le hash du commit) est déployée en test, en staging et en production ; seuls ses variables d’environnement et ses secrets montés changent.

Le dépôt d’artefacts est le stockage entre le build et le déploiement : un registre de conteneurs (Amazon ECR, Azure Container Registry, Google Artifact Registry, GitHub Container Registry, Harbor) ou un dépôt universel comme JFrog Artifactory ou Sonatype Nexus pour les paquets et les binaires. Traitez-le comme une infrastructure critique. Déployez par digest immuable (sha256:...) plutôt que par un tag modifiable comme latest, qui peut être déplacé pour pointer vers une autre image ; conservez les artefacts qui sont ou ont été en production aussi longtemps que vous pourriez avoir besoin d’y revenir ou de les examiner ; et enregistrez la provenance, c’est-à-dire le commit, l’exécution du pipeline et les dépendances qui ont produit chaque artefact.

Développement basé sur le tronc et petits lots

La façon dont le code est réparti en branches détermine la fréquence à laquelle il est réellement intégré. Dans le développement basé sur le tronc, chacun intègre de petits changements dans une seule branche principale (le tronc) au moins une fois par jour, soit en faisant des commits directement, soit par des branches de courte durée et des pull requests qui vivent quelques heures, pas des semaines. Le programme de recherche DORA a associé à plusieurs reprises les branches de courte durée et les fusions fréquentes à une meilleure performance de livraison, et c’est une condition préalable à l’intégration continue au sens littéral : du code qui reste trois semaines sur une branche n’est pas intégré en continu.

Les branches de fonctionnalité de longue durée semblent plus sûres, parce que le travail inachevé est tenu à l’écart, mais le risque n’est que reporté : plus deux branches divergent longtemps, plus la fusion finale est grosse et risquée, et plus longtemps le pipeline voit du code qui n’est pas celui qui sera livré. GitFlow, un modèle de branches avec des branches develop et release de longue durée publié par Vincent Driessen en 2010, a été largement adopté ; en 2020, Driessen a ajouté une note indiquant que les équipes qui livrent en continu, comme pour les applications web, devraient envisager un flux de travail plus simple. Les équipes qui doivent travailler sur de gros changements dans le tronc utilisent deux techniques : les feature flags, qui masquent un comportement inachevé, et le branch by abstraction, qui introduit une interface devant l’ancienne implémentation, construit la nouvelle derrière elle et bascule quand elle est prête.

Les praticiens sont réellement en désaccord à la marge. Les projets open source qui ont de nombreux contributeurs non fiables s’appuient sur des pull requests de plus longue durée et sur la relecture, et les équipes réglementées ont parfois besoin de branches de version explicites pour l’audit. Le principe qui survit au désaccord est la taille des lots : plus chaque changement est petit, plus il est facile à relire, tester, déployer, diagnostiquer et annuler.

name: delivery
on:
  push:
    branches: [main]
env:
  IMAGE: registry.example.com/food/orders:${{ github.sha }}
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: make lint test              # fast feedback first
      - run: docker build -t "$IMAGE" . && docker push "$IMAGE"
  staging:
    needs: build
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - uses: actions/checkout@v4
      - run: ./deploy.sh staging "$IMAGE" && ./smoke-test.sh staging
  production:
    needs: staging
    runs-on: ubuntu-latest
    environment: production            # can require an approval
    steps:
      - uses: actions/checkout@v4
      - run: ./deploy.sh production "$IMAGE" --canary 5
Un flux de livraison continue minimal dans la syntaxe de GitHub Actions : construire et tester une fois, pousser une image nommée d’après le commit, déployer cette image en staging, puis en production comme canari. GitLab CI, Azure Pipelines, Jenkins et d’autres expriment les mêmes étapes. La connexion au registre et les scripts de déploiement sont omis.

Stratégies de déploiement

Une stratégie de déploiement décide comment la nouvelle version remplace l’ancienne en production, et donc combien d’utilisateurs une mauvaise version peut toucher avant d’être arrêtée. Les stratégies diffèrent par l’infrastructure supplémentaire qu’elles exigent, la rapidité de leur retour arrière et le fait que deux versions tournent ou non en même temps. Chaque fois que deux versions tournent en même temps, elles doivent être compatibles avec les données et les messages l’une de l’autre : c’est le prix de toutes les stratégies sauf la recréation.

Comparaison des stratégies de déploiement

StratégieComment ça marcheRisque pour les utilisateursRetour arrière (rollback)Coût et complexité supplémentaires
RecréationArrêter toutes les anciennes instances, puis démarrer les nouvelles.Interruption de service pendant la bascule ; chaque utilisateur rencontre une mauvaise version en même temps.Redéployer l’ancienne version, avec une nouvelle interruption.Aucun. Acceptable pour les outils internes, les traitements par lots et les fenêtres de maintenance.
ProgressifRemplacer les instances quelques-unes à la fois (le comportement par défaut de Kubernetes pour les Deployments, avec maxSurge et maxUnavailable valant tous deux 25 % par défaut).L’exposition augmente à mesure que le déploiement avance ; les contrôles de santé détectent les plantages, mais pas les erreurs subtiles.Revenir en arrière en redéployant progressivement l’ancienne version, ce qui prend autant de temps que le déploiement.Faible. L’ancienne et la nouvelle version tournent côte à côte, elles doivent donc être compatibles.
Bleu-vertFaire tourner un nouvel environnement complet (vert) à côté de l’environnement actif (bleu), le tester, puis basculer tout le trafic au niveau du routeur.Tous les utilisateurs basculent en même temps, mais le nouvel environnement a été vérifié avant la bascule.Rapide : rebasculer le routeur, tant que le bleu tourne encore.Jusqu’au double de capacité pendant la bascule ; les bases de données partagées doivent fonctionner avec les deux versions.
CanariEnvoyer une petite part du trafic (disons 1 à 5 %) vers la nouvelle version, comparer ses métriques, puis élargir par paliers.Seule la part des utilisateurs dirigée vers le canari rencontre une mauvaise version, et seulement jusqu’à ce que l’analyse l’arrête.Rapide : ramener le poids du canari à zéro.Exige un routage pondéré, de bonnes métriques et assez de trafic pour une comparaison significative.
Fantôme (dark launch)Copier les vraies requêtes vers la nouvelle version ; ses réponses sont comparées ou jetées, jamais renvoyées.Aucun directement, à condition que les effets de bord (paiements, e-mails, écritures) soient supprimés ou simulés.Rien à annuler ; les utilisateurs n’en ont jamais dépendu.Double charge sur le chemin dupliqué et gestion soigneuse des effets de bord ; idéal pour les chemins de lecture et les réécritures.

Le déploiement bleu-vert a été décrit par Martin Fowler en 2010, qui en attribue le mérite à Dan North et Jez Humble ; le déploiement canari, nommé d’après les canaris que les mineurs emportaient pour détecter le gaz, a été présenté par Danilo Sato sur le même site en 2014. Dans Kubernetes, les mises à jour progressives sont intégrées ; les déploiements bleu-vert et canari viennent généralement d’un contrôleur de livraison progressive (Argo Rollouts, Flagger) ou d’un service mesh et du routage pondéré de la Gateway API. Sur les plateformes managées, les fonctionnalités équivalentes s’appellent traffic splitting (répartition du trafic) ou deployment slots (emplacements de déploiement).

Déploiement canari avec analyse automatisée

Déploiement canari avec analyse automatisée : un routeur envoie 90 % du trafic à la production, 5 % à une référence neuve de l’ancienne version et 5 % au canari ; une étape d’analyse compare les métriques de la référence et du canari, puis élargit ou annuleUsagersRouteur (trafic)équilibreurou service meshProduction v1le gros du parcRéférence v1neuve, même tailleCanari v2version neuve90%5%5%Analyse canaricompare erreurs,latence, saturationmétriquesDécisionOK : élargir à 25 %KO : annulerfixe auto. les nouveaux poids du trafic
Comparer le canari à une référence neuve de l’ancienne version, plutôt qu’au parc qui tourne depuis longtemps, élimine les différences dues uniquement à la durée de fonctionnement et aux caches chauds.

Séparer le déploiement de la mise en production avec des feature flags

Le déploiement installe une nouvelle version du logiciel dans un environnement ; la mise en production rend un comportement accessible aux utilisateurs. Les traiter comme un seul événement fait de chaque déploiement un événement métier, avec toute la nervosité que cela entraîne. Les feature flags (feature toggles) les séparent : le nouveau code est déployé désactivé, et le comportement est mis en production plus tard, progressivement et de façon réversible, en changeant la configuration. L’article de Pete Hodgson Feature Toggles (aka Feature Flags) sur martinfowler.com (2017) distingue quatre catégories selon leur durée de vie et le caractère plus ou moins dynamique de leur décision.

Les quatre catégories de feature toggles selon Hodgson

CatégorieObjectifDurée de vie typiqueDegré de dynamisme
Toggles de mise en productionLivrer dans le tronc des fonctionnalités incomplètes ou pas encore mises en production, désactivées.De quelques jours à quelques semaines ; à supprimer après la mise en production.Plutôt statique pour une version donnée.
Toggles d’expérimentationTests A/B ou multivariés qui orientent chaque utilisateur vers une cohorte.Assez longtemps pour obtenir des résultats statistiquement solides, puis supprimés.À chaque requête, selon la cohorte de l’utilisateur.
Toggles opérationnelsCommandes d’exploitation, comme la désactivation d’un panneau de recommandations coûteux en cas de forte charge (kill switches, ou interrupteurs d’arrêt d’urgence).Plutôt courte ; quelques kill switches sont conservés à long terme.Modifiés à l’exécution, souvent pendant un incident.
Toggles de permissionFonctionnalités réservées à certains utilisateurs : offres premium, bêta-testeurs, personnel interne.Peuvent vivre des années.À chaque requête, selon l’utilisateur.

Les flags ont un coût de possession. Chaque flag double les chemins dans le code qu’il protège, ajoute des combinaisons à tester et laisse du code mort une fois sa décision arrêtée. Hodgson recommande de traiter les flags comme un stock : ajouter une tâche de suppression quand un toggle de mise en production est créé, donner aux flags des dates d’expiration, ajouter des tests qui échouent dès qu’un flag a dépassé sa date, et limiter le nombre de flags qui peuvent exister en même temps. La perte de Knight Capital en 2012, décrite en section 1.3, impliquait un flag réaffecté qui a réactivé du vieux code sur un serveur oublié lors d’un déploiement manuel : un rappel de ne jamais réutiliser les noms de flags et de supprimer le code mort derrière les flags dont la décision est arrêtée. À grande échelle, les flags sont servis par un service dédié (des options open source comme Unleash et Flagsmith, des offres commerciales comme LaunchDarkly, ou l’API OpenFeature, indépendante des fournisseurs) afin qu’un changement se propage en quelques secondes et soit tracé.

Les changements de base de données dans le pipeline

Le code peut revenir en arrière en quelques secondes ; les données, non. Un déploiement qui renomme une colonne, puis fait l’objet d’un retour arrière, laisse l’ancien code face à un schéma qu’il ne comprend pas. La réponse, traitée en détail dans l’évolution des schémas, consiste à rendre chaque changement de schéma rétrocompatible avec la version du code en cours d’exécution, au moyen de l’expansion-contraction : ajouter d’abord la nouvelle structure, déployer du code qui écrit dans les deux et lit l’une ou l’autre, faire le backfill, basculer les lecteurs, et ne supprimer l’ancienne structure que dans une version ultérieure, une fois que plus rien ne l’utilise.

Dans le pipeline, cela signifie que les migrations sont des artefacts versionnés qui s’exécutent comme une étape à part, avant le déploiement du code qui en a besoin, et qu’elles sont testées sur une copie des données de la taille de la production, afin qu’un verrou sur une grande table soit découvert en staging plutôt qu’à l’heure du déjeuner. Les étapes destructrices (suppression de colonnes ou de tables) sont différées et exécutées séparément, car c’est le seul type de changement qu’un retour arrière ne peut pas annuler. Un contrôle utile dans le pipeline fait échouer le build quand une migration n’est pas additive, sauf si elle est explicitement marquée comme une étape de contraction.

Livraison progressive et analyse canari automatisée

La livraison progressive, un terme popularisé en 2018 par James Governor, du cabinet d’analystes RedMonk, combine les canaris, les feature flags et la vérification automatisée : un changement atteint des publics de plus en plus larges, et à chaque étape, c’est le système, et non une personne qui surveille des tableaux de bord, qui décide de continuer ou non. La décision repose sur l’analyse canari automatisée : les métriques du canari (taux d’erreur, percentiles de latence, saturation, signaux métier comme les commandes passées) sont comparées statistiquement à celles d’une référence. Netflix et Google ont publié en open source leur moteur d’analyse, Kayenta, en 2018 ; Argo Rollouts et Flagger fournissent des étapes d’analyse similaires dans Kubernetes.

Trois détails décident si l’on peut se fier à l’analyse. Comparez ce qui est comparable : une référence neuve de l’ancienne version recevant la même part de trafic évite d’imputer à la nouvelle version des différences dues à des caches froids ou à des redémarrages récents. Ayez assez de trafic : à 5 % d’un service qui traite dix requêtes par minute, une heure de canari voit trente requêtes, trop peu pour détecter un taux d’erreur de 1 % ; les services à faible trafic ont donc besoin de paliers plus longs, d’une charge synthétique ou d’une autre stratégie. Choisissez des métriques liées aux objectifs de niveau de service et aux résultats métier, car une version peut être rapide et sans erreur tout en facturant silencieusement de mauvais frais de livraison.

Retour arrière ou roll forward

Quand une mise en production tourne mal, il y a deux façons d’en sortir. Le retour arrière (rollback) revient à l’artefact précédent, ce qui est rapide et ne demande aucun nouveau code, à condition que la version précédente fonctionne toujours avec les données actuelles et avec les versions des autres services. Le roll forward (correction vers l’avant) fait passer un correctif par le pipeline, ce qui est plus lent mais parfois la seule option, par exemple après une migration de données irréversible ou un changement dont d’autres services dépendent déjà.

Une bonne règle par défaut est revenir en arrière d’abord, diagnostiquer ensuite : rétablir le service avec l’action sûre la plus rapide, puis enquêter sans pression. Corriger vers l’avant sous pression tend à contourner les contrôles du pipeline, et un correctif précipité sur un incident de production est une source classique de l’incident suivant. Le retour arrière n’est une vraie option que s’il est prévu dès la conception : artefacts précédents conservés, changements de schéma compatibles dans les deux sens pendant au moins une version, messages lisibles par les anciens comme par les nouveaux consommateurs, et chemin de retour arrière lui-même exercé régulièrement. Une équipe qui n’est jamais revenue en arrière devrait supposer qu’elle en est incapable.

Exemple commenté

Exemple commenté : mettre en production une nouvelle règle de frais de livraison

Le service de commandes de la plateforme de livraison de repas change sa façon de calculer les frais de livraison, en utilisant la distance et la demande au lieu d’un forfait. L’équipe pratique le développement basé sur le tronc, un déploiement canari et un flag de mise en production.

ChangementNouveau calculateur de frais derrière un flag de mise en production dynamic-delivery-fee, désactivé par défaut ; une migration d’expansion seule ajoute une colonne pouvant être nulle, fee_rule_version.
Du commit à l’artefactFusionné dans main à 10:02. Le lint, les tests unitaires et les analyses prennent 6 minutes ; l’image orders:4f1c2ab, avec sa SBOM et sa signature, est poussée à 10:09.
MigrationLa migration additive s’exécute à 10:15 comme une étape distincte du pipeline. La version en cours d’exécution ignore la nouvelle colonne, donc rien ne casse.
StagingLa même image est déployée à 10:16 ; les tests de contrat avec les services de paiement et des restaurants, ainsi que les smoke tests, réussissent à 10:31.
CanariÀ 10:35, 5 % du trafic de production va vers la nouvelle version, flag toujours désactivé. Une analyse sur 20 minutes compare la latence p99, le taux de 5xx et le taux de commandes réussies à une référence neuve : réussite.
DéploiementLes poids passent à 25 %, 50 % puis 100 % par paliers de 15 minutes ; terminé à 11:40. Le déploiement est fini, et pourtant aucun client n’a vu les nouveaux frais.
Mise en productionLe lendemain, la responsable produit active le flag pour 10 % des clients d’une ville et surveille la conversion des commandes et les réclamations, puis élargit à toutes les villes en une semaine.
NettoyageLe flag et le code des frais forfaitaires sont supprimés au sprint suivant ; une migration de contraction ultérieure rend la colonne obligatoire.

Le risque de déploiement (le code fonctionne-t-il ?) et le risque de mise en production (les clients apprécient-ils les nouveaux frais ?) ont été traités séparément, chacun avec son propre petit rayon d’impact.

À chaque étape jusqu’à la migration de contraction, la reprise passait par un changement de configuration ou un poids du routeur, pas par un correctif d’urgence. Du commit au déploiement complet en production, il a fallu environ 1 heure 40 minutes.

Mesurer le pipeline

Les métriques DORA de livraison logicielle présentées en section 2.6 (délai de mise en œuvre des changements, fréquence de déploiement, taux d’échec des changements, temps de rétablissement après un déploiement en échec et taux de reprise des déploiements) sont en grande partie des propriétés du pipeline et de l’architecture réunis. Les petits lots et le développement basé sur le tronc raccourcissent le délai et augmentent la fréquence ; les tests automatisés et l’analyse canari font baisser le taux d’échec des changements ; un retour arrière rapide et les flags raccourcissent le temps de rétablissement. Mesurez-les par service, observez les tendances plutôt que des valeurs isolées, et n’en faites jamais des objectifs individuels, ce qui ne fait qu’inviter à tricher.

Vérifiez votre compréhension

Pourquoi reconstruire l’artefact séparément pour la production pose-t-il problème, même si le code source est identique ?

Les dépendances, les images de base ou les outils de build peuvent avoir changé entre les builds : l’artefact de production n’est donc pas celui qui a été testé. Construisez une seule fois et promouvez le même artefact.

Quelle est la différence entre déployer une fonctionnalité et la mettre en production ?

Le déploiement installe le code dans un environnement ; la mise en production rend le comportement accessible aux utilisateurs. Les feature flags permettent de déployer le code désactivé et de le mettre en production plus tard, progressivement et de façon réversible.

Pourquoi un canari sur un service à faible trafic donne-t-il souvent des résultats peu fiables ?

Une petite part d’un trafic faible produit trop peu de requêtes pour détecter avec une confiance statistique des différences de taux d’erreur ou de latence : il faut donc des paliers plus longs, un trafic synthétique ou une autre stratégie.

Quand le roll forward peut-il être la seule option ?

Quand la mise en production comprenait un changement irréversible, comme une migration destructrice, ou que d’autres services dépendent déjà du nouveau comportement, si bien que la version précédente ne peut plus fonctionner correctement.

Suivant · 10.6Multirégion et edgeQuand et comment fonctionner sur plusieurs régions : latence, reprise après sinistre et résidence des données, les quatre stratégies de reprise avec RTO, RPO et coût, les données interrégions, le basculement, les cellules pour limiter le rayon d’impact, les CDN et les fonctions en périphérie.Continuer →

Sources et lectures complémentaires

Une question sur cette section ? ArchitectBot, l’assistant d’étude IA du cours, répond d’abord à partir du cours.

Demander : « Notre équipe déploie toutes les deux semaines avec une liste de contrôle manuelle. Quels changements de pipeline et de déploiement devrions-nous faire en premier pour déployer en toute sécurité plusieurs fois par jour ? »