Pourquoi chaque build a besoin d'une identité unique
Vous venez de lancer un build. Un fichier JAR apparaît dans le répertoire de sortie. Ou peut-être une archive ZIP, ou un binaire compilé. Il ressemble à tous les autres builds que vous avez faits cette semaine. Vous le copiez sur un serveur, le déployez, et passez à autre chose.
Trois jours plus tard, quelqu'un signale un bug en production. Vous devez déterminer quel artefact est réellement en cours d'exécution. Vous vérifiez le serveur, trouvez un fichier nommé app-1.0.0.jar, et réalisez que vous n'avez aucune idée s'il s'agit du build de mardi ou de celui de jeudi. Les deux étaient étiquetés 1.0.0. Les deux provenaient du même dépôt. Mais quelque chose cloche, et vous ne pouvez pas retracer le problème jusqu'au code source.
C'est le moment où l'absence d'identité d'artefact devient un véritable casse-tête opérationnel.
Le problème avec un simple numéro de version
Les numéros de version sont la forme d'identification la plus basique. Ils vous donnent une idée approximative de ce que vous manipulez. 1.0.0, 2.3.1, 3.0.0-beta — ces étiquettes aident les humains à comprendre la progression et la compatibilité.
Mais les seuls numéros de version montrent rapidement leurs limites en pratique.
Imaginez que vous construisiez la version 1.0.0 aujourd'hui. Demain, vous relancez le même build à partir du même code source. Vous obtenez un autre 1.0.0. Vous avez maintenant deux fichiers différents avec la même étiquette. Lequel est en production ? Lequel a été testé ? Si vous devez reproduire un bug, quel 1.0.0 devez-vous utiliser ?
La vérité inconfortable est que deux builds à partir d'un code source identique peuvent produire des artefacts différents. Une version de dépendance a peut-être changé dans votre gestionnaire de paquets. L'outil de build lui-même a pu être mis à jour. L'environnement de build — correctifs du système d'exploitation, versions de bibliothèques, même le fuseau horaire — peut introduire des différences subtiles. Même numéro de version, artefact différent.
Ce qui fait une bonne identité d'artefact
Une identité d'artefact utile doit être unique, traçable et permanente. Elle doit répondre à trois questions :
- Quel code a été utilisé ?
- Quand a-t-il été construit ?
- Quelle exécution de build l'a produit ?
L'approche la plus courante combine trois informations en un seul identifiant.
Build ID
Chaque exécution de pipeline reçoit un numéro séquentiel. Jenkins l'appelle le numéro de build. GitLab CI l'appelle l'ID de pipeline. GitHub Actions l'appelle le numéro d'exécution. Quel que soit le nom, c'est un entier croissant unique au sein d'un projet. Le build 142 est toujours différent du build 143.
Mais un build ID seul ne vous dit pas quel code a été construit. Vous avez besoin de plus.
Hash de commit
Chaque commit dans Git possède un hash SHA — une longue chaîne hexadécimale qui identifie de manière unique l'état exact du code source à ce moment-là. Lorsque vous combinez le build ID avec le hash de commit, vous obtenez quelque chose de puissant : "Cet artefact provient du build 142, qui a utilisé le commit a3f2c9e."
Si quelque chose tourne mal, vous pouvez extraire ce commit exact et voir le code qui a été compilé. Pas de supposition, pas de "je pense que c'était la version que nous avons utilisée".
Timestamp
Certaines équipes ajoutent un timestamp à l'identité. Cela aide lorsque vous avez besoin de savoir exactement quand le build a eu lieu, surtout pour comparer des artefacts entre différents environnements. Mais les timestamps seuls ne sont pas uniques — deux builds dans des pipelines différents pourraient démarrer à la même seconde.
La combinaison du build ID, du hash de commit et du timestamp vous donne une identité robuste et lisible par un humain. Quelque chose comme 142-a3f2c9e-20250321T143022. Ce n'est pas joli, mais c'est sans ambiguïté.
Voici comment construire cette identité dans un pipeline CI :
BUILD_ID="${CI_PIPELINE_ID:-142}"
COMMIT_HASH="${CI_COMMIT_SHA:-a3f2c9e}"
TIMESTAMP=$(date +%Y%m%d%H%M%S)
ARTIFACT_NAME="myapp-${BUILD_ID}-${COMMIT_HASH}-${TIMESTAMP}.jar"
echo "Construction de ${ARTIFACT_NAME}"
# ... étapes de build ...
cp target/app.jar "dist/${ARTIFACT_NAME}"
La règle de l'artefact immuable
Une fois qu'un artefact reçoit son identité, cette identité ne doit jamais changer. C'est le principe d'immuabilité.
Un artefact immuable signifie :
- Vous n'écrasez jamais un artefact existant.
- Vous ne réutilisez jamais une identité pour un fichier différent.
- Vous ne modifiez jamais un artefact après sa construction.
Si vous devez reconstruire, vous obtenez une nouvelle identité. L'ancien artefact reste là où il est, avec son étiquette d'origine. Cela peut sembler gaspilleur, mais c'est le fondement de la traçabilité.
Sans immuabilité, votre stockage d'artefacts devient un fouillis de fichiers écrasés et d'historique perdu. Vous ne pouvez pas affirmer avec certitude "c'est l'artefact qui a été testé en staging" car quelqu'un a peut-être remplacé par une version plus récente sous le même nom.
Avec l'immuabilité, vous pouvez suivre chaque artefact tout au long de son cycle de vie. Vous savez exactement quel artefact est allé en staging, lequel est allé en production, et lequel attend encore d'être testé. Vous pouvez comparer des artefacts entre environnements et confirmer qu'ils sont identiques.
Où vivent les artefacts ?
L'identité seule ne suffit pas. Vous avez également besoin d'un endroit pour stocker les artefacts afin qu'ils survivent au-delà de la machine de build.
Si vos artefacts traînent dans un dossier sur votre serveur CI ou votre ordinateur portable, ils disparaîtront lorsque le disque sera nettoyé, la machine remplacée, ou que vous manquerez d'espace. Vous avez besoin d'un système de stockage centralisé accessible à tous ceux qui en ont besoin — développeurs, testeurs, équipes d'exploitation et pipelines de déploiement.
Ce stockage s'appelle un registre. Il peut s'agir d'un simple serveur de fichiers, d'un dépôt d'artefacts dédié comme Nexus ou Artifactory, ou d'une solution cloud-native comme les registres de conteneurs pour les images Docker. L'important est qu'il s'agisse d'une source unique de vérité pour tous les artefacts construits.
Lorsque vous combinez une identité unique et immuable avec un registre fiable, vous créez une chaîne de traçabilité pour chaque logiciel que vous produisez. Vous pouvez retracer toute instance en cours d'exécution jusqu'à son build exact, son code source et les conditions dans lesquelles elle a été créée.
Liste de contrôle pratique
- Chaque build produit un identifiant unique combinant build ID, hash de commit et timestamp.
- Les artefacts ne sont jamais écrasés ou remplacés avec la même identité.
- Le stockage des artefacts est centralisé et accessible à toutes les équipes qui en ont besoin.
- Vous pouvez retracer tout artefact déployé jusqu'au commit exact de son code source.
- Votre processus de déploiement enregistre quelle identité d'artefact est en cours d'exécution dans chaque environnement.
L'essentiel à retenir
Un build sans identité unique est un passif. Vous ne pouvez pas déboguer efficacement les problèmes de production, vous ne pouvez pas vérifier ce qui s'exécute où, et vous ne pouvez pas faire confiance à votre processus de déploiement. La combinaison du build ID, du hash de commit et du timestamp vous donne un moyen simple et fiable d'identifier chaque artefact que vous produisez. Rendez-le immuable, stockez-le dans un registre, et vous n'aurez jamais à deviner quelle version de votre logiciel est réellement en cours d'exécution.