Lab 15: Rollback-Strategien¶
Hintergrund¶
Trotz sorgfältiger Tests, Code-Reviews und Approval Gates kann ein Deployment in Production fehlschlagen. Der Health Check zeigt Fehler, die Anwendung antwortet nicht, oder ein bisher unentdeckter Bug tritt unter realer Last auf. In solchen Fällen muss schnell auf eine funktionierende Version zurückgekehrt werden können — idealerweise innerhalb von Minuten, nicht Stunden.
Es gibt verschiedene Rollback-Strategien, die je nach Infrastruktur und Deployment-Methode zum Einsatz kommen:
- Slot Swap Rollback (Lab 14): Bei Blue/Green Deployments ist ein erneuter Swap der schnellste Rollback — die alte Version ist noch im Staging-Slot und sofort wieder live. Dauer: wenige Sekunden.
- Re-Deploy der vorherigen Version: Man startet einen älteren erfolgreichen Pipeline-Run erneut. Azure DevOps speichert die Artefakte aller Runs für die konfigurierte Aufbewahrungsdauer (Standard: 30 Tage), sodass man jederzeit auf eine ältere Version zurückgreifen kann.
- Automatischer Rollback: Die Pipeline erkennt Fehler über einen Health
Check und führt im
on:failure-Hook automatisch Rollback-Schritte aus — z. B. ein Re-Deploy der letzten funktionierenden Version, einen Slot Swap zurück oder eine Benachrichtigung an das Team. - Manueller Rollback per Parameter: Die Pipeline bietet einen Parameter an, über den man gezielt eine bestimmte Build-Nummer für ein Rollback angeben kann. Die Pipeline lädt dann die Artefakte dieses Builds und deployt sie.
In diesem Lab implementieren wir die Strategien 2, 3 und 4 in einer Pipeline.
Wir verwenden Pipeline-Parameter (aus Lab 04), um Fehler zu simulieren und
Rollbacks manuell auszulösen, sowie die on:failure- und on:success-
Lifecycle-Hooks (aus Lab 11), um automatisch auf Deployment-Fehler zu
reagieren.
Voraussetzungen¶
- Die Environments
devaus Lab 11. - Die Anwendungsdateien (
src/server.js,index.html,package.json) aus den vorherigen Labs.
Aufgabenstellung¶
Schritt 1: Pipeline mit Rollback-Logik¶
Wir erstellen eine Pipeline mit drei Stages: Build, Deploy (mit Health Check und automatischem Rollback) und ein optionaler manueller Rollback, der über Pipeline-Parameter gesteuert wird.
Ersetze den Inhalt von azure-pipelines.yml:
trigger:
branches:
include:
- master
parameters:
- name: simulateFailure
displayName: 'Deployment-Fehler simulieren?'
type: boolean
default: false
- name: rollbackToBuild
displayName: 'Rollback auf Build-Nummer (leer = kein Rollback)'
type: string
default: ''
variables:
azureSubscription: 'azure-training-connection'
appVersion: '1.0.$(Build.BuildId)'
stages:
# ===== Build =====
- stage: Build
displayName: 'Build'
jobs:
- job: BuildApp
pool:
vmImage: 'ubuntu-latest'
steps:
- script: |
mkdir -p dist
cp src/*.js dist/
cp index.html dist/
cp package.json dist/
echo '{"version": "$(appVersion)", "buildId": "$(Build.BuildId)"}' > dist/version.json
displayName: 'Build'
- publish: dist
artifact: app-package
# ===== Deploy mit Health Check =====
- stage: Deploy
displayName: 'Deploy mit Health Check'
dependsOn: Build
jobs:
- deployment: DeployWithHealthCheck
displayName: 'Deploy und validieren'
pool:
vmImage: 'ubuntu-latest'
environment: 'dev'
strategy:
runOnce:
deploy:
steps:
- script: |
echo "=== Deployment Version $(appVersion) ==="
echo "Artefakte:"
ls -la $(Pipeline.Workspace)/app-package/
echo ""
cat $(Pipeline.Workspace)/app-package/version.json
echo ""
echo "Deployment durchgeführt."
displayName: 'Deploy'
# Health Check
- script: |
echo "=== Health Check ==="
# Fehler simulieren, wenn Parameter gesetzt
if [ "${{ parameters.simulateFailure }}" = "True" ]; then
echo "FEHLER: Health Check fehlgeschlagen (simuliert)!"
echo "Die Anwendung antwortet nicht auf dem Health-Endpoint."
exit 1
fi
echo "HTTP 200 OK"
echo "App-Version: $(appVersion)"
echo "Health Check bestanden."
displayName: 'Health Check'
on:
failure:
steps:
- script: |
echo "======================================="
echo " DEPLOYMENT FEHLGESCHLAGEN"
echo "======================================="
echo ""
echo "Version $(appVersion) konnte nicht deployt werden."
echo "Automatischer Rollback wird eingeleitet..."
echo ""
echo "Rollback-Strategie:"
echo "1. Letzte erfolgreiche Version aus Artefakt-Speicher laden"
echo "2. Re-Deploy der letzten Version"
echo "3. Health Check der Rollback-Version"
echo ""
echo "In einer realen Umgebung würde jetzt:"
echo " - Die vorherige Version re-deployt"
echo " - Oder ein Slot-Swap zurück auf Blue durchgeführt"
echo " - Eine Benachrichtigung an das Team gesendet"
displayName: 'Automatischer Rollback'
- script: |
echo "=== Rollback-Benachrichtigung ==="
echo "An: dev-team@example.com"
echo "Betreff: Deployment $(appVersion) fehlgeschlagen - Rollback durchgeführt"
echo "Build-URL: $(System.CollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId)"
displayName: 'Team benachrichtigen'
success:
steps:
- script: |
echo "Version $(appVersion) erfolgreich deployt!"
echo "Keine Rollback-Aktion nötig."
displayName: 'Deployment bestätigt'
# ===== Manueller Rollback =====
- stage: ManualRollback
displayName: 'Manueller Rollback'
dependsOn: [] # Unabhängig von anderen Stages
condition: ne('${{ parameters.rollbackToBuild }}', '')
jobs:
- deployment: RollbackDeployment
displayName: 'Rollback durchführen'
pool:
vmImage: 'ubuntu-latest'
environment: 'dev'
strategy:
runOnce:
deploy:
steps:
- script: |
echo "======================================="
echo " MANUELLER ROLLBACK"
echo "======================================="
echo ""
echo "Rollback auf Build: ${{ parameters.rollbackToBuild }}"
echo ""
echo "In einer realen Umgebung würde:"
echo "1. Das Artefakt von Build ${{ parameters.rollbackToBuild }} geladen"
echo "2. Dieses Artefakt deployt"
echo "3. Health Check durchgeführt"
echo ""
echo "Tipp: Du kannst auch unter 'Pipelines > Runs' einen"
echo "älteren erfolgreichen Run finden und diesen re-deployen:"
echo " Run öffnen > drei Punkte (...) > 'Rerun failed jobs'"
echo " oder einen komplett neuen Run starten."
displayName: 'Rollback durchführen'
Gehe die Pipeline Abschnitt für Abschnitt durch:
- Parameter: Zwei Parameter steuern das Verhalten der Pipeline.
simulateFailureist ein Boolean, der beim manuellen Start gesetzt werden kann — er lässt den Health Check absichtlich fehlschlagen, um denon:failure-Hook zu demonstrieren.rollbackToBuildist ein String, der eine Build-Nummer enthält, auf die zurückgerollt werden soll. Ist er leer (der Default), wird die ManualRollback-Stage übersprungen. - Build-Stage: Baut die Anwendung und erzeugt eine
version.jsonmit der aktuellen Version und Build-ID. Diese Datei dient in späteren Stages zur Identifikation der deployten Version. - Deploy-Stage: Ein Deployment Job mit zwei Steps im
deploy-Hook: erst das Deployment, dann ein Health Check. Der Health Check prüft den ParametersimulateFailure— ist erTrue, schlägt der Check mit Exit-Code 1 fehl, und deron:failure-Hook wird ausgelöst. Bei Erfolg wird deron:success-Hook ausgeführt. on:failure-Hook: Wird nur ausgeführt, wenn ein Step imdeploy-Hook fehlgeschlagen ist. Hier werden zwei Steps ausgeführt: der eigentliche Rollback (in der Praxis würde hier die letzte funktionierende Version re-deployt) und eine Benachrichtigung an das Team mit einem Link zum fehlgeschlagenen Build. In einer realen Umgebung könnte die Benachrichtigung z. B. per Slack-Webhook, Microsoft Teams oder E-Mail erfolgen.- ManualRollback-Stage: Hat
dependsOn: []— sie ist von keiner anderen Stage abhängig und kann parallel zu Build und Deploy laufen. Dieconditionprüft, ob der ParameterrollbackToBuildnicht leer ist. Ist er leer (Default), wird die Stage komplett übersprungen. In einer realen Umgebung würde diese Stage die Artefakte des angegebenen Builds laden und deployen.
Schritt 2: Erfolgreichen Deploy testen¶
Committe die Pipeline und lass sie einmal mit den Default-Parametern laufen (kein Fehler, kein Rollback):
git add azure-pipelines.yml
git commit -m "Add rollback strategies"
git push origin master
Warte, bis die Pipeline durchläuft. Die Deploy-Stage sollte erfolgreich sein,
der on:success-Hook sollte "Deployment bestätigt" ausgeben, und die
ManualRollback-Stage sollte übersprungen werden (da rollbackToBuild leer
ist).
Schritt 3: Fehler simulieren¶
Jetzt lösen wir absichtlich einen Deployment-Fehler aus, um den automatischen Rollback zu demonstrieren:
- Gehe zu Pipelines > hello-pipeline.
- Klicke auf "Run pipeline".
- Im Parameter-Dialog siehst du die beiden Parameter:
- Setze "Deployment-Fehler simulieren?" auf Ja/True.
- Lass "Rollback auf Build-Nummer" leer.
- Klicke auf "Run".
Beobachte den Pipeline-Run im Browser:
- Die Build-Stage läuft normal durch.
- In der Deploy-Stage schlägt der Health Check-Step fehl (Exit-Code 1). Die Stage wird rot markiert.
- Anschließend werden die
on:failure-Hooks ausgeführt: "Automatischer Rollback" und "Team benachrichtigen". Diese Steps laufen trotz des Deployment-Fehlers, da sie imon:failure-Block definiert sind. - Die ManualRollback-Stage wird übersprungen (Parameter ist leer).
Schritt 4: Manuellen Rollback testen¶
Jetzt testen wir den manuellen Rollback, indem wir eine Build-Nummer angeben:
- Klicke erneut auf "Run pipeline".
- Setze "Deployment-Fehler simulieren?" auf Nein/False.
- Setze "Rollback auf Build-Nummer" auf eine vorherige Build-Nummer
(z. B.
20260222.1— du findest die Nummern unter Pipelines > Runs). - Klicke auf "Run".
Beobachte den Pipeline-Run:
- Die Build-Stage und Deploy-Stage laufen normal durch (kein Fehler simuliert).
- Die ManualRollback-Stage wird zusätzlich ausgeführt, da der Parameter nicht leer ist. Sie zeigt die angegebene Build-Nummer und die Rollback-Schritte.
Beachte, dass in diesem Lab-Beispiel beide Stages parallel laufen können
(dependsOn: []). In einer realen Pipeline würde man den manuellen Rollback
typischerweise als eigenständige Pipeline oder mit einer Condition
implementieren, die den regulären Deploy-Pfad ausschließt.
Schritt 5: Re-Run eines älteren Builds¶
Die dritte Rollback-Methode braucht keine besondere Pipeline-Konfiguration — sie nutzt eine eingebaute Funktion von Azure DevOps:
- Gehe zu Pipelines > Runs (oder Pipelines > hello-pipeline > Runs).
- Finde einen älteren, erfolgreichen Run in der Liste.
- Klicke auf den Run, um die Details zu öffnen.
- Klicke auf die drei Punkte (...) oben rechts.
- Wähle "Run new" — dies startet einen neuen Run mit dem gleichen Commit. Der Build erzeugt dieselben Artefakte wie der ursprüngliche Run, und das Deployment rollt die alte Version aus.
Diese Methode ist in der Praxis oft der einfachste Rollback: Man braucht keine spezielle Pipeline-Logik, sondern nutzt einfach die Tatsache, dass Azure DevOps jeden Run mit seinem Commit verknüpft.
Validierung¶
Prüfe per CLI, dass alle Runs ausgeführt wurden:
# Alle letzten Runs anzeigen
az pipelines runs list --top 5 --output table
Öffne im Browser die drei Pipeline-Runs und prüfe die folgenden Punkte:
- Erfolgreicher Run (Schritt 2): Der
on:success-Hook zeigt "Deployment bestätigt". Die ManualRollback-Stage ist übersprungen. - Fehlgeschlagener Run (Schritt 3): Die Deploy-Stage ist rot. Die
on:failure-Hooks "Automatischer Rollback" und "Team benachrichtigen" wurden ausgeführt. Die ManualRollback-Stage ist übersprungen. - Manueller Rollback-Run (Schritt 4): Sowohl die Deploy-Stage als auch die ManualRollback-Stage wurden ausgeführt.
Erwartetes Ergebnis¶
Erfolgreicher Deploy:
Health Check bestanden.
Version 1.0.42 erfolgreich deployt!
Keine Rollback-Aktion nötig.
Fehlgeschlagener Deploy:
FEHLER: Health Check fehlgeschlagen (simuliert)!
=======================================
DEPLOYMENT FEHLGESCHLAGEN
=======================================
Automatischer Rollback wird eingeleitet...
Manueller Rollback:
=======================================
MANUELLER ROLLBACK
=======================================
Rollback auf Build: 20260222.1
Aufräumen¶
Kein Aufräumen nötig. Die Pipeline erzeugt keine externen Ressourcen.
Tipps und Troubleshooting¶
on:failurevs.on:success: Diese Lifecycle-Hooks sind nur in Deployment Jobs verfügbar (nicht in normalen Jobs). Sie werden nach Abschluss aller Steps imdeploy-Hook ausgeführt — je nachdem, ob ein Step fehlgeschlagen ist oder alle erfolgreich waren. Sie ersetzen nicht das Fehlerhandling innerhalb von Steps (z. B.continueOnError).- Re-Deploy der vorherigen Version: Der einfachste Rollback in der Praxis ist, einen älteren erfolgreichen Pipeline-Run erneut auszuführen ("Run new"). Die Artefakte werden neu gebaut, und das Deployment erfolgt mit dem alten Code-Stand.
- Slot Swap Rollback: Bei Blue/Green Deployments (Lab 14) ist ein erneuter Swap der schnellste Rollback — keine Pipeline nötig, dauert Sekunden statt Minuten.
- Datenbank-Rollbacks: Wenn ein Deployment auch Datenbank-Migrationen
enthält, ist ein Code-Rollback allein oft nicht ausreichend. Plane
Forward-Only Migrationen (die auch mit der alten Code-Version
kompatibel sind) oder implementiere einen separaten Rollback-Migrations-
Schritt. Vermeide destruktive Migrationen (wie
DROP COLUMN), bis sichergestellt ist, dass kein Rollback mehr nötig ist. - Rollback-Zeitfenster: Definiere im Team, wie lange ein Rollback möglich sein soll. Nach einem bestimmten Zeitpunkt (z. B. wenn neue Daten mit dem neuen Schema geschrieben wurden) kann ein Rollback mehr Schaden anrichten als nützen. In solchen Fällen ist ein Forward-Fix (schnelles Beheben des Bugs in einer neuen Version) oft die bessere Strategie.
- Automatische Benachrichtigungen: In der Praxis würde der
on:failure- Hook eine echte Benachrichtigung senden — z. B. über einen Slack-Webhook (curl -X POST -H 'Content-Type: application/json' ...), eine Microsoft Teams Incoming-Webhook-URL oder den Azure DevOps Service Hook für E-Mails.