Frontend-Änderungen ausliefern, ohne alles zu zerstören
Du hast gerade eine neue Version deines Frontends gepusht. Der Build war erfolgreich, die Tests sind grün, und die Deployment-Pipeline meldet „Erfolg". Doch als du die Produktionsmetriken prüfst, stimmt etwas nicht. Einige Nutzer sehen ein kaputtes Layout. Andere berichten, dass ein Button nicht funktioniert. Und ein paar Nutzer haben ohnehin noch die alte Version, weil ihr Browser die neuen Dateien noch nicht geladen hat.
Das ist die Realität von Frontend-Releases. Anders als bei Backend-Diensten, bei denen du einen Server neustarten und sofort die Version wechseln kannst, lebt Frontend-Code im Browser des Nutzers. Du kannst nicht jeden Nutzer zwingen, neu zu laden. Du kannst nicht steuern, wann ihr Cache abläuft. Und wenn etwas schiefgeht, kannst du nicht einfach einen Rollback-Knopf drücken und erwarten, dass alle sofort die Korrektur erhalten.
Warum Frontend-Releases anders sind
Das Kernproblem ist, dass Frontend-Assets auf Tausende von Browsern verteilt sind, jeder mit eigenem Cache-Status. Wenn du eine neue Version ausrollst, bekommen sie manche Nutzer sofort, andere erst nach Ablauf ihres Caches, und wieder andere bleiben möglicherweise auf einer kaputten Version hängen, bis sie manuell aktualisieren.
Bei statischen Frontends, die über ein CDN ausgeliefert werden, besteht die Herausforderung darin, dass du nicht auf einen Server deployst, den du kontrollierst. Du lädst Dateien in einen Storage-Bucket hoch und lässt das CDN sie verteilen. Das CDN könnte je nach Cache-Headern und Edge-Node-Verhalten alten Nutzern alte und neuen Nutzern neue Dateien ausliefern.
Bei serverseitig gerenderten (SSR) Frontends ist die Herausforderung eine andere. Du hast es mit echten Servern zu tun, die aktualisiert werden müssen, ohne aktive Verbindungen zu trennen. Ein Nutzer, der ein Formular ausfüllt oder zwischen Seiten navigiert, sollte seine Sitzung nicht verlieren, nur weil du die Version gewechselt hast.
Das folgende Flussdiagramm hilft dir, die richtige Release-Strategie basierend auf deinem Frontend-Typ und deiner Risikotoleranz zu wählen:
Gestaffelte Rollouts für statische Frontends
Der sicherste Weg, ein statisches Frontend auszuliefern, ist zu kontrollieren, wie viele Nutzer die neue Version sehen. Die meisten CDNs unterstützen gewichtete Verteilungen, bei denen du einen Prozentsatz der Anfragen an die neuen Dateien und den Rest an die alten senden kannst.
So funktioniert es typischerweise:
- Lade die neue Version mit einem eindeutigen Pfad in deinen Storage-Bucket hoch, z. B.
app-v2/oder mit gehashten Dateinamen. - Konfiguriere dein CDN so, dass 5 % der Anfragen an die neuen Dateien weitergeleitet werden.
- Überwache Fehlerraten, Seitenladezeiten und von Nutzern gemeldete Probleme.
- Wenn alles gut aussieht, erhöhe den Prozentsatz schrittweise auf 25 %, dann 50 %, dann 100 %.
Du kannst auch Feature-Flags auf der Client-Seite verwenden. Liefere allen die gleiche Anwendungs-Shell aus, lade aber neue Komponenten oder Funktionen bedingt basierend auf einem Cookie, URL-Parameter oder einer Nutzer-ID. Das gibt dir eine feinere Kontrolle darüber, wer was sieht, ohne dass du Traffic-Splitting auf CDN-Ebene benötigst.
Der entscheidende Vorteil von gestaffelten Rollouts ist, dass du jederzeit anhalten kannst. Wenn die Fehlerrate bei 10 % in die Höhe schießt, setzt du den Prozentsatz wieder auf null zurück. Nutzer, die die neue Version bereits geladen haben, sehen möglicherweise weiterhin Probleme, aber du hast den Schaden begrenzt.
Canary-Releases für SSR-Frontends
Bei SSR-Frontends funktionieren gestaffelte Rollouts ähnlich wie Canary-Deployments im Backend. Du betreibst mehrere Instanzen deiner Anwendung hinter einem Load Balancer. Wenn du eine neue Version ausrollen willst, deployst du sie auf ein oder zwei Instanzen, während der Rest die alte Version weiter ausführt.
Der Load Balancer wird so konfiguriert, dass er einen kleinen Prozentsatz des Traffics an die neuen Instanzen sendet. Wenn Health-Checks fehlschlagen oder die Fehlerrate steigt, werden diese Instanzen aus der Rotation genommen. Ein Rollback ist so einfach wie das Herunterfahren der neuen Instanzen, sodass der gesamte Traffic wieder zu den alten zurückfließt.
Dieser Ansatz funktioniert gut, weil SSR-Anwendungen den Zustand auf der Serverseite halten. Die Sitzung eines Nutzers ist an eine bestimmte Instanz gebunden. Daher musst du sicherstellen, dass Sitzungsdaten in einem gemeinsamen Speicher wie Redis oder einer Datenbank abgelegt werden. Andernfalls führt das Umschalten des Traffics zwischen Versionen dazu, dass Nutzer ausgeloggt werden.
Um diesen Prozess zu automatisieren, kannst du ein Canary-Rollout in deiner Deployment-Konfiguration definieren. Hier ein Beispiel mit Argo Rollouts auf Kubernetes:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: frontend-ssr
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 10
- pause: { duration: 5m }
- setWeight: 50
- pause: { duration: 5m }
- setWeight: 100
analysis:
templates:
- templateName: success-rate
startingStep: 0
args:
- name: service-name
value: frontend-ssr
---
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
metrics:
- name: error-rate
successCondition: result < 0.01
provider:
prometheus:
query: |
sum(rate(http_requests_total{status=~"5.."}[5m])) /
sum(rate(http_requests_total[5m]))
Diese Konfiguration leitet 10 % des Traffics an die neue Version, wartet 5 Minuten, um die Fehlerrate zu überwachen, und fährt dann mit 50 % und schließlich 100 % fort – jedoch nur, wenn die Fehlerrate unter 1 % bleibt.
Blue-Green-Deployments für null Ausfallzeit
Wenn du garantieren musst, dass kein Nutzer während eines Releases Ausfallzeiten erlebt, ist Blue-Green-Deployment eine solide Wahl. Du betreibst zwei identische Umgebungen: Blue (aktuelle Version) und Green (neue Version). Der gesamte Traffic läuft über Blue. Sobald Green bereit ist und alle Health-Checks bestanden hat, schaltest du den Load Balancer um, sodass der gesamte Traffic zu Green fließt.
Wenn nach dem Umschalten etwas schiefgeht, schaltest du zurück zu Blue. Der gesamte Vorgang dauert Sekunden, und die Nutzer sehen keine Unterbrechung, solange der Sitzungszustand ordnungsgemäß behandelt wird.
Der Haken ist, dass du die doppelte Infrastruktur benötigst. Für kleine Teams oder Anwendungen mit geringem Traffic ist das vielleicht übertrieben. Aber für Produktionssysteme mit hohem Traffic, bei denen selbst wenige Sekunden Ausfallzeit Geld oder Vertrauen kosten, ist Blue-Green den Aufwand wert.
Die eigentliche Herausforderung: Rollback bei statischen Frontends
Hier wird es knifflig. Ein Rollback bei einem statischen Frontend ist technisch einfach, aber praktisch unordentlich. Du kannst die Dateien in deinem CDN auf die alte Version zurücksetzen, aber Nutzer, die die neuen Dateien bereits heruntergeladen haben, bekommen nicht automatisch die alten. Ihr Browser-Cache enthält noch die neue Version und wird diese weiter ausliefern, bis der Cache abläuft.
Die Lösung: Überschreibe niemals Dateien. Jede Version sollte einen eindeutigen Pfad haben, typischerweise basierend auf einem Content-Hash. Beim Deployment lädst du neue Dateien neben den alten hoch. Das CDN liefert die Version aus, auf die die Anwendung zeigt. Für ein Rollback änderst du den Pointer von der neuen auf die alte Version. Nutzer, die die neue Version bereits im Cache haben, verwenden sie weiter, bis ihr Cache geleert wird. Neue Nutzer und Nutzer, die aktualisieren, erhalten jedoch die alte Version.
Dieser Ansatz bedeutet, dass du über das Rollback nachdenken musst, bevor du es jemals brauchst. Wenn deine Pipeline so ausgelegt ist, dass sie Dateien direkt überschreibt, bereitest du dir eine schmerzhafte Wiederherstellung, wenn etwas schiefgeht.
Praktische Checkliste für Frontend-Releases
Bevor du das nächste Release ausrollst, gehe diese kurze Checkliste durch:
- Sind alle Dateipfade versionsspezifisch eindeutig (Content-Hash oder versioniert)?
- Kannst du einen kleinen Prozentsatz des Traffics an die neue Version weiterleiten?
- Hast du eine Möglichkeit, Fehlerraten und Seitenladezeiten in Echtzeit zu überwachen?
- Ist dein Rollback-Plan getestet, nicht nur dokumentiert?
- Bei SSR: Ist der Sitzungszustand außerhalb des Anwendungsservers gespeichert?
- Bei statischen Frontends: Hast du einen Mechanismus, um den Versions-Pointer umzuschalten, ohne neu zu deployen?
Worauf es wirklich ankommt
Gestaffelte Rollouts und Rollback-Strategien sind keine Funktionen, die du nachträglich in die Pipeline einbauen kannst. Sie müssen von Anfang an in den Deployment-Prozess einfließen. Wenn deine Pipeline nur eine Version an einen Ort deployen kann, wirst du dich mit Canary-Releases oder Blue-Green-Deployments schwer tun. Wenn du kein Traffic-Management auf CDN- oder Load-Balancer-Ebene hast, hast du keine Möglichkeit, die Auswirkungen eines fehlerhaften Releases zu begrenzen.
Das Ziel ist nicht, alle Probleme zu verhindern. Probleme werden auftreten. Das Ziel ist, sicherzustellen, dass du reagieren kannst, ohne in Panik zu geraten, wenn ein Problem auftritt. Eine gut durchdachte Release-Strategie gibt dir die Kontrolle über den Schadensbereich, einen klaren Rollback-Pfad und das Vertrauen, Änderungen häufig auszuliefern. Ohne sie fühlt sich jedes Release wie ein Glücksspiel an.