Warum ein Rebuild für die Produktion riskanter ist als es scheint
Du hast einen grünen Build auf dem Staging-System. Alle Tests bestanden. Das Team ist bereit für den Deployment. Jemand sagt: „Lass uns einfach denselben Tag auschecken, neu bauen und in die Produktion deployen. Wir müssen keine alten Artefakte aufbewahren.“
Das klingt effizient. Kein Artefakt-Management, kein Durchwühlen alter Builds. Einfach den Build erneut ausführen und ausliefern. Doch dieser scheinbar praktische Shortcut bringt zwei Probleme mit sich, die alles untergraben, was du mit einer Delivery-Pipeline erreichen willst: Du verlierst die Nachvollziehbarkeit (Traceability) und die Reproduzierbarkeit (Reproducibility).
Das Problem der Nachvollziehbarkeit
Wenn du für die Produktion neu baust, ist das Artefakt, das in der Produktion läuft, nicht dasselbe Artefakt, das im Staging getestet wurde. Du hast es aus demselben Quellcode gebaut, aber der Build-Prozess hat ein neues Artefakt mit einer neuen Identität erzeugt. Es hat eine andere Prüfsumme, einen anderen Build-Zeitstempel und möglicherweise andere eingebettete Metadaten.
Wenn in der Produktion etwas schiefgeht, kannst du nicht auf die Staging-Ergebnisse verweisen und sagen: „Dieses genaue Artefakt wurde getestet.“ Du musst darauf vertrauen, dass der zweite Build ein identisches Ergebnis geliefert hat. Ohne Verifikation ist dieses Vertrauen blind.
Das folgende Flussdiagramm zeigt die beiden Pfade im Vergleich:
Nachvollziehbarkeit ist keine Bürokratie. Es geht darum, eine einfache Frage beantworten zu können: „Was läuft gerade in der Produktion, und wie weiß ich, dass es dem entspricht, was wir getestet haben?“ Wenn du neu baust, wird diese Frage schwerer mit Gewissheit zu beantworten.
Das Problem der Reproduzierbarkeit
Selbst wenn du denselben Commit auscheckst, liefert der Build-Prozess nicht immer dieselbe Ausgabe. Viele Faktoren können das Ergebnis zwischen zwei Builds verändern:
Abhängigkeitsdrift. Dein erster Build am Montag hat Version 1.2.3 einer Open-Source-Bibliothek gezogen. Bis Mittwoch hat der Maintainer Version 1.2.4 veröffentlicht. Dein zweiter Build zieht automatisch die neue Version. Kein Quellcode wurde geändert, aber das Anwendungsverhalten könnte sich geändert haben. Ein kleiner Patch könnte einen Bug beheben, auf den du angewiesen warst, oder eine Regression einführen. Er könnte auch stillschweigend eine Sicherheitslücke einbringen.
Basis-Image-Updates. Wenn dein Build ein Docker-Basis-Image mit dem Tag latest oder sogar einer bestimmten Minor-Version verwendet, die gepatcht wird, könnte der zweite Build eine andere zugrunde liegende Betriebssystemschicht nutzen. Der Anwendungscode ist derselbe, aber die Laufzeitumgebung hat sich darunter verschoben.
Unterschiede in der Build-Umgebung. Der CI-Runner, der das Staging gebaut hat, könnte eine leicht andere JDK-Version, Node.js-Laufzeit oder Systembibliothek gehabt haben. Vielleicht ist der Build-Cache zwischen den Läufen abgelaufen, was eine vollständige Neukompilierung verursacht hat, die anderen Bytecode produziert. Diese Unterschiede treten während der Entwicklung selten zutage, können aber in der Produktion zu subtilen Fehlern führen.
Zeitstempel und Metadaten. Viele Build-Tools betten Zeitstempel, Build-Nummern oder Commit-Hashes in das Artefakt ein. Selbst wenn der funktionale Code identisch ist, unterscheiden sich die Artefakt-Metadaten. Das erschwert das Debugging, wenn du das Produktionsverhalten mit einem bestimmten Build korrelieren musst.
Die Auswirkungen in der Praxis
Diese Probleme sind nicht theoretisch. Teams haben Rebuilds in die Produktion ausgeliefert und erst später entdeckt, dass eine automatisch aktualisierte Abhängigkeit eine Sicherheitslücke eingeschleust hat. Andere haben gesehen, wie sich das Anwendungsverhalten änderte, weil ein Patch-Level-Update in einer Bibliothek die Funktionsweise einer Funktion veränderte. In manchen Fällen produzierte der Rebuild ein Artefakt, das in der Entwicklung einwandfrei funktionierte, in der Produktion aber versagte, weil die Build-Umgebung eine andere Compiler-Version hatte.
Das Schlimmste ist, dass diese Probleme schwer zu erkennen sind. Die Pipeline zeigt grün. Der Commit-Hash stimmt. Alles sieht gut aus – bis jemand merkt, dass in der Produktion etwas nicht stimmt. Und dann wird die Ursachenforschung zur forensischen Untersuchung.
Das Prinzip: Einmal bauen, mehrfach promoten
Deshalb gibt es das Prinzip „Build Once, Promote Many“. Du baust dein Artefakt einmal, verifizierst es und promotest dann genau dasselbe Artefakt durch jede Umgebung: Entwicklung, Staging, Produktion. Kein Neubauen. Keine zweiten Chancen.
Mit diesem Ansatz ist das Artefakt in der Produktion physisch identisch mit dem Artefakt, das alle Tests bestanden hat. Die Prüfsumme stimmt. Die eingebetteten Metadaten stimmen. Du weißt genau, was getestet und was ausgeliefert wurde. Nachvollziehbarkeit ist eingebaut, weil jedes Artefakt eine eindeutige Kennung hat, die mit seinem Commit, der Build-Konfiguration und dem Zeitstempel verknüpft ist. Reproduzierbarkeit ist kein Problem, weil du nichts reproduzierst – du verwendest dasselbe Binary.
Wenn ein Rebuild unvermeidbar ist
Es gibt legitime Fälle, in denen ein Rebuild notwendig ist. Ein altes Artefakt könnte mit einem Produktions-Infrastruktur-Upgrade inkompatibel sein. Ein kritischer Sicherheitspatch in einem Basis-Image könnte einen Rebuild erzwingen. Eine Compliance-Anforderung könnte verlangen, dass Produktionsartefakte aus einer bestimmten gehärteten Umgebung stammen.
Diese Situationen gibt es, aber sie sollten Ausnahmen sein, nicht der Standard. Jedes Mal, wenn dein Team beschließt, für die Produktion neu zu bauen, solltet ihr die Risiken explizit benennen: Ihr brecht die Nachvollziehbarkeit, und ihr geht die Wette ein, dass der Build reproduzierbar ist. Dokumentiert die Entscheidung, verifiziert die Ausgabe gegen den ursprünglichen Build und behandelt es als Gelegenheit für eine Incident-Review, um zukünftige Rebuilds zu vermeiden.
Praktische Checkliste vor einem Rebuild für die Produktion
- Kannst du verifizieren, dass das Rebuild-Artefakt funktional identisch mit dem getesteten Artefakt ist?
- Hast du alle Abhängigkeitsversionen, einschließlich transitiver Abhängigkeiten, festgeschrieben?
- Ist die Build-Umgebung (Compiler, Laufzeit, Systembibliotheken) identisch mit dem ursprünglichen Build?
- Sind Basis-Images auf bestimmte Digests festgelegt, nicht auf Tags?
- Hast du einen dokumentierten Grund, warum ein Promote des ursprünglichen Artefakts nicht möglich ist?
- Hat das Team zugestimmt, dies als Ausnahme und nicht als Standardpraxis zu behandeln?
Das Fazit
Jeder Rebuild für die Produktion bringt Unsicherheit in deine Delivery-Pipeline. Du verlierst die Fähigkeit, mit Gewissheit zu sagen, dass das in der Produktion laufende Artefakt dasselbe ist, das die Tests bestanden hat. Die Ersparnis bei der Artefakt-Speicherung oder die Bequemlichkeit sind selten die Debugging-Kosten wert, wenn etwas schiefgeht. Baue einmal. Promote dasselbe Artefakt überall. Lass den Rebuild die Ausnahme sein, die eine explizite Rechtfertigung erfordert – nicht den Standardweg in die Produktion.