Pourquoi reconstruire pour la production est plus risqué qu'il n'y paraît
Vous avez un build vert sur la staging. Les tests passent. L'équipe est prête à déployer. Quelqu'un dit : "On va juste checkout le même tag, rebuild, et déployer en production. Pas besoin de garder les vieux artefacts."
Cela semble efficace. Pas de stockage d'artefacts à gérer. Pas besoin de fouiller dans les vieux builds. Il suffit de relancer le build et de livrer. Mais cette astuce apparemment pratique introduit deux problèmes qui minent silencieusement tout ce que vous essayez d'accomplir avec un pipeline de delivery : vous perdez la traçabilité et la reproductibilité.
Le problème de traçabilité
Quand vous reconstruisez pour la production, l'artefact qui tourne en production n'est pas le même artefact qui a passé les tests en staging. Vous l'avez construit à partir du même code source, mais le processus de build a créé un nouvel artefact avec une nouvelle identité. Il a un checksum différent, un timestamp de build différent, et potentiellement des métadonnées embarquées différentes.
Si quelque chose se passe mal en production, vous ne pouvez pas pointer vers les résultats de staging et dire "cet artefact exact a été testé". Vous devez faire confiance au fait que le second build a produit un résultat identique. Sans vérification, cette confiance est aveugle.
Le diagramme suivant compare les deux chemins :
La traçabilité n'est pas une question de paperasse. Il s'agit de pouvoir répondre à une question simple : "Qu'est-ce qui tourne exactement en production en ce moment, et comment savoir que cela correspond à ce que nous avons testé ?" Quand vous reconstruisez, cette question devient plus difficile à répondre avec confiance.
Le problème de reproductibilité
Même si vous checkout le commit exact, le processus de build ne produit pas toujours le même résultat. De nombreux facteurs peuvent changer le résultat entre deux builds :
Dérive des dépendances. Votre premier build lundi a tiré la version 1.2.3 d'une bibliothèque open source. Mercredi, le mainteneur a publié la version 1.2.4. Votre second build tire automatiquement la nouvelle version. Aucun code source n'a changé, mais le comportement de l'application pourrait avoir changé. Un correctif mineur pourrait corriger un bug sur lequel vous comptiez, ou introduire une régression. Il pourrait aussi silencieusement introduire une vulnérabilité de sécurité.
Mises à jour de l'image de base. Si votre build utilise une image Docker de base taggée latest ou même une version mineure spécifique qui reçoit des correctifs, le second build pourrait utiliser une couche de système d'exploitation sous-jacente différente. Le code de l'application est le même, mais l'environnement d'exécution a changé en dessous.
Différences d'environnement de build. Le runner CI qui a construit la staging pourrait avoir eu une version de JDK légèrement différente, un runtime Node.js différent, ou une bibliothèque système différente. Peut-être que le cache de build a expiré entre les exécutions, provoquant une recompilation complète qui produit un bytecode différent. Ces différences apparaissent rarement pendant le développement, mais elles peuvent causer des échecs subtils en production.
Timestamps et métadonnées. De nombreux outils de build intègrent des timestamps, des numéros de build ou des hashs de commit dans l'artefact. Même si le code fonctionnel est identique, les métadonnées de l'artefact diffèrent. Cela rend le débogage plus difficile quand vous devez corréler le comportement en production avec un build spécifique.
L'impact dans le monde réel
Ces problèmes ne sont pas théoriques. Des équipes ont livré des rebuilds en production pour découvrir qu'une dépendance mise à jour automatiquement avait introduit une faille de sécurité. D'autres ont vu le comportement de l'application changer parce qu'une mise à jour de niveau patch dans une bibliothèque avait modifié le fonctionnement d'une fonction. Dans certains cas, le rebuild a produit un artefact qui fonctionnait bien en développement mais échouait en production parce que l'environnement de build avait une version de compilateur différente.
Le pire, c'est que ces problèmes sont difficiles à détecter. Le pipeline est vert. Le hash du commit correspond. Tout semble normal jusqu'à ce que quelqu'un remarque que quelque chose ne va pas en production, et à ce moment-là, retracer la cause racine devient une enquête médico-légale.
Le principe : Build once, promote many
C'est pourquoi le principe "build once, promote many" existe. Vous construisez votre artefact une fois, vous le vérifiez, puis vous promouvez cet artefact exact à travers chaque environnement : développement, staging, production. Pas de reconstruction. Pas de seconde chance.
Avec cette approche, l'artefact en production est physiquement identique à l'artefact qui a passé tous les tests. Le checksum correspond. Les métadonnées embarquées correspondent. Vous savez exactement ce qui a été testé et ce qui a été livré. La traçabilité est intégrée car chaque artefact a un identifiant unique lié à son commit, sa configuration de build et son timestamp. La reproductibilité n'est pas un problème car vous ne reproduisez rien - vous utilisez le même binaire.
Quand le rebuild est inévitable
Il existe des cas légitimes où la reconstruction est nécessaire. Un artefact ancien pourrait être incompatible avec une mise à niveau de l'infrastructure de production. Un correctif de sécurité critique dans une image de base pourrait forcer une reconstruction. Une exigence de conformité pourrait exiger que les artefacts de production soient construits à partir d'un environnement durci spécifique.
Ces situations existent, mais elles doivent rester des exceptions, pas la règle. Chaque fois que votre équipe décide de reconstruire pour la production, vous devez explicitement reconnaître les risques : vous brisez la traçabilité, et vous pariez que le build est reproductible. Documentez la décision, vérifiez la sortie par rapport au build original, et traitez-la comme une opportunité de revue d'incident pour éviter de futurs rebuilds.
Checklist pratique avant de reconstruire pour la production
- Pouvez-vous vérifier que l'artefact reconstruit est fonctionnellement identique à l'artefact testé ?
- Avez-vous épinglé toutes les versions de dépendances, y compris les dépendances transitives ?
- L'environnement de build (compilateur, runtime, bibliothèques système) est-il identique au build original ?
- Les images de base sont-elles épinglées à des digests spécifiques, pas à des tags ?
- Avez-vous une raison documentée pour laquelle la promotion de l'artefact original n'est pas possible ?
- L'équipe a-t-elle accepté de traiter cela comme une exception, pas comme une pratique standard ?
L'essentiel à retenir
Chaque reconstruction pour la production introduit de l'incertitude dans votre pipeline de delivery. Vous perdez la capacité de dire avec confiance que l'artefact qui tourne en production est le même que celui qui a passé les tests. Les économies de stockage d'artefacts ou de commodité valent rarement le coût de débogage quand quelque chose tourne mal. Construisez une fois. Promouvez ce même artefact partout. Faites du rebuild l'exception qui nécessite une justification explicite, pas le chemin par défaut vers la production.