Wie wir Delivery aufbauen
Wir beginnen beim Artefakt. Abhängigkeiten werden über Lockfiles festgeschrieben, Basis-Images per Digest referenziert statt per Tag, und der Build läuft in einer Umgebung, deren Inhalt selbst versioniert ist. Multi-Stage-Builds trennen Kompilierung von Laufzeit: ausgeliefert wird ein Image mit Binary, Zertifikatsspeicher und den nötigen Laufzeitbibliotheken, sonst nichts. Es startet unter einer unprivilegierten UID, wo möglich mit schreibgeschütztem Root-Dateisystem. Da Layer entlang der Dockerfile-Reihenfolge gecacht werden, stehen selten geänderte Schritte oben.
Die Pipeline liegt als Code im Repository – als .gitlab-ci.yml oder als Workflow unter .github/workflows – und durchläuft feste Stufen: Formatprüfung, Tests, Build, Abhängigkeits- und Image-Scan, Signatur, Deployment. Gebaut wird genau einmal. Dasselbe Image wandert per Digest durch Staging und Produktion, statt pro Umgebung neu zu entstehen. Ein SBOM entsteht im Build und wird mit dem Artefakt aufbewahrt, sodass die Frage nach einer betroffenen Bibliothek eine Abfrage ist und keine Recherche.
Infrastruktur wird deklariert, nicht geklickt. Provisionierung beschreiben wir mit OpenTofu beziehungsweise Terraform in versionierten Modulen, Konfiguration mit idempotenten Ansible-Rollen. Der Zustand liegt in einem Remote-Backend mit Locking, jede Änderung wird als Plan im Merge Request gelesen und erst danach angewendet. Wiederkehrende Plan-Läufe machen Drift sichtbar, also Abweichungen durch manuelle Eingriffe. Secrets bleiben außerhalb der Repositories: verschlüsselt mit SOPS und age oder in einem Secret-Store, für die Pipeline mit kurzlebigen OIDC-Tokens statt dauerhafter Zugangsschlüssel.
Für das Ausrollen wählen wir die einfachste Strategie, die das Risiko trägt. Rolling Updates mit ernst gemeinten Readiness-Probes genügen häufig. Blue/Green lohnt, wenn ein Umschalten am Reverse Proxy sauberer ist als ein gemischter Zustand. Canary passt dort, wo genug Verkehr für eine statistische Aussage anliegt – mit vorab definierten Abbruchkriterien aus Fehlerrate und Latenz. Datenbankmigrationen rollen wir nach dem Muster expand/contract zweistufig aus, damit alte und neue Version gleichzeitig lauffähig bleiben. Erst das macht Rollback zu einem einzelnen Schritt.