Teil C — Wie man ausliefert. Zurück zur Übersicht.
Lernziel
Nach diesem Kapitel kennst du die fünf gängigen Ausrollverfahren mit ihren Stärken und Kosten, kannst begründet eines auswählen und weißt, wie Feature Flags Deployment und Release trennen. Du hast ein Blue/Green-Deployment mit Podman selbst aufgebaut.
Die Pipeline aus den letzten Kapiteln kann jetzt zuverlässig ausliefern. Offen ist die Frage: Wie kommt die neue Version in Betrieb, ohne dass jemand etwas davon merkt?
Das ist keine akademische Frage. Sie entscheidet darüber, ob eine Auslieferung ein Wartungsfenster, eine Nachtschicht und eine Vorabinformation an den Fachbereich braucht — oder ob sie am Dienstagvormittag zwischen zwei Besprechungen stattfindet.
alt ████████████░░░░░░░░
neu ░░░░░░░░░░░░████████
▲
Ausfallzeit
Alte Version stoppen, neue starten. Ehrlich, verständlich, und mit einer Lücke dazwischen.
Passt zu: Batch-Verarbeitung, internen Werkzeugen, allem mit vereinbartem Wartungsfenster. Passt nicht zu: allem, was ständig erreichbar sein muss.
podman stop kfz-rechner && podman rm kfz-rechner podman run -d --name kfz-rechner registry.intern/kfz-rechner:2.5.0
Instanz 1 ██████░░████████
Instanz 2 ████████░░██████
Instanz 3 ██████████░░████
─────────────────►
immer mindestens zwei erreichbar
Die Instanzen werden nacheinander ausgetauscht. Der Standard in Kubernetes und OpenShift.
Vorteil: kein Ausfall, kein zusätzlicher Ressourcenbedarf. Nachteil: Für einen Zeitraum laufen beide Versionen gleichzeitig. Das muss die Anwendung aushalten — insbesondere die Datenbank, siehe Expand-Contract in Kapitel 6.
Das gleichzeitige Laufen zweier Versionen wird regelmäßig unterschätzt. Wenn Version 2.4 ein Feld erwartet, das Version 2.5 nicht mehr schreibt, entstehen für einige Minuten Fehler, die anschließend spurlos verschwinden — und sich nicht reproduzieren lassen. Solche Fehler kosten mehr Ermittlungszeit als das gesamte Ausrollverfahren einspart.
┌─────────────┐
Anfragen ─►│ Lastverteiler│
└──────┬──────┘
│ Umschalten in einer Sekunde
┌──────────┴──────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ BLAU │ │ GRÜN │
│ v2.4 │ │ v2.5 │
│ aktiv │ │ Bereitsch│
└──────────┘ └──────────┘
Zwei vollständige Umgebungen. Die neue Version wird in der inaktiven aufgebaut und in Ruhe geprüft. Dann schaltet der Lastverteiler um. Geht etwas schief, schaltet man zurück.
Vorteil: Rollback in Sekunden, Prüfung unter realen Bedingungen vor der Umschaltung. Nachteil: doppelte Ressourcen; die gemeinsame Datenbank bleibt der Knackpunkt.
100 % ─┐
│ v2.4 ████████████░░░░░░░░░░░░
│ v2.5 ░░░░░░░░░░░░▓▓▓▓████████
└──────────────────────────────────
5 % 25 % 50 % 100 %
▲
Fehlerrate beobachten,
bei Auffälligkeit abbrechen
Die neue Version bekommt zunächst einen kleinen Anteil des Verkehrs. Bleiben Fehlerrate und Antwortzeiten unauffällig, wird der Anteil schrittweise erhöht.
Vorteil: Ein Fehler trifft fünf Prozent der Anwender statt aller. Man findet Probleme, die nur unter echter Last auftreten. Nachteil: braucht belastbare Messwerte — sonst schaltet man blind weiter. Ohne Observability (Kapitel 12) ist Canary lediglich ein langsameres Rolling Update.
Der Name stammt vom Kanarienvogel im Bergbau. Das Bild ist zutreffend, aber unhöflich gegenüber den fünf Prozent.
Echte Anfragen werden zusätzlich an die neue Version geschickt, deren Antworten aber verworfen. Man vergleicht Laufzeiten und Ergebnisse, ohne dass ein Anwender betroffen ist.
Passt zu: Umbauten mit unverändertem fachlichem Verhalten — etwa dem Austausch einer Berechnungsbibliothek. Achtung: Schreibende Vorgänge müssen zuverlässig unterdrückt werden. Sonst verschickt der Schattenbetrieb Policen zweimal, und die Erklärung gegenüber dem Fachbereich wird unerfreulich.
| Recreate | Rolling | Blue/Green | Canary | Shadow | |
|---|---|---|---|---|---|
| Ausfallzeit | ja | nein | nein | nein | nein |
| Zusätzliche Ressourcen | keine | gering | doppelt | gering | doppelt |
| Rollback-Dauer | Minuten | Minuten | Sekunden | Sekunden | entfällt |
| Zwei Versionen gleichzeitig | nein | ja | nein | ja | ja |
| Braucht Messwerte | nein | nein | wenig | ja | ja |
| Aufwand der Einrichtung | sehr gering | gering | mittel | hoch | hoch |
| Risiko bei Fehlern | alle Anwender | alle Anwender | alle Anwender | wenige | keine |
Empfehlung für den Einstieg: Blue/Green. Es lässt sich mit einem Reverse Proxy und zwei Containern auf einem einzelnen Server umsetzen, erfordert keine Messinfrastruktur und liefert den größten Einzelgewinn — ein Rollback in Sekunden.
Die Technik, die Deployment und Release endgültig entkoppelt.
"""Sehr einfache Feature-Flag-Verwaltung über Umgebungsvariablen.""" import os def feature_aktiv(name: str, standard: bool = False) -> bool: wert = os.environ.get(f"FEATURE_{name.upper()}") if wert is None: return standard return wert.lower() in ("1", "true", "ja", "an")
from src.features import feature_aktiv def berechne_praemie(sf_klasse, fahrzeugalter, jahreskilometer=None): beitrag = grundberechnung(sf_klasse, fahrzeugalter) if feature_aktiv("wenigfahrer_rabatt") and jahreskilometer: if jahreskilometer < 6000: beitrag *= Decimal("0.92") return beitrag.quantize(Decimal("0.01"))
| Art | Zweck | Lebensdauer |
|---|---|---|
| Release-Flag | unfertige Funktion verbergen | Tage bis Wochen — danach entfernen |
| Betriebs-Flag | Funktion bei Überlast abschalten | dauerhaft |
| Berechtigungs-Flag | Funktion nur für bestimmte Gruppen | dauerhaft |
| Experiment-Flag | A/B-Test | Dauer des Versuchs |
Feature Flags sind technische Schulden mit Verfallsdatum.
Jedes Flag verdoppelt rechnerisch die Zahl der möglichen Codepfade. Zehn Flags ergeben theoretisch 1.024 Kombinationen, von denen sicher niemand mehr als drei testet. Nach zwei Jahren weiß niemand, ob FEATURE_ALTE_TARIFLOGIK noch irgendwo aktiv ist — und ob man den Zweig löschen darf.
Regel: Jedes Release-Flag bekommt beim Anlegen ein Ablaufdatum und ein Ticket zum Entfernen. Wer das nicht diszipliniert durchhält, tauscht das Problem langlebiger Branches gegen ein schlechter sichtbares ein.
| Rollback | Roll-forward | |
|---|---|---|
| Vorgehen | zurück zur alten Version | Fehler beheben, neu ausliefern |
| Dauer | Sekunden bis Minuten | abhängig von Analyse und Pipeline |
| Voraussetzung | altes Artefakt verfügbar, DB verträglich | schnelle, verlässliche Pipeline |
| Passt zu | akuter Störung | kleinen, klaren Fehlern |
Die pragmatische Regel: Bei einer laufenden Störung wird zurückgerollt, nicht analysiert. Die Ursachensuche findet statt, wenn das System wieder läuft — nicht, während Anwender warten. Wer bei einem Ausfall zuerst die Ursache verstehen will, verlängert die Ausfallzeit um die Dauer seiner Neugier.
Roll-forward ist die richtige Wahl, wenn der Fehler offensichtlich und die Korrektur einzeilig ist — oder wenn eine Datenbankmigration das Zurückrollen ohnehin ausschließt.
Umsetzbar auf einem einzelnen Server, auch auf einem Raspberry Pi.
#!/usr/bin/env bash # # Blue/Green-Deployment mit Podman und nginx. # Aufruf: ./bluegreen.sh <image:tag> # set -euo pipefail NEUES_IMAGE="$1" PROXY_KONF="/etc/nginx/conf.d/kfz-upstream.conf" # --- Welche Farbe ist gerade aktiv? --- if grep -q "8081" "$PROXY_KONF"; then AKTIV="blau"; AKTIV_PORT=8081 NEU="gruen"; NEU_PORT=8082 else AKTIV="gruen"; AKTIV_PORT=8082 NEU="blau"; NEU_PORT=8081 fi echo "Aktiv: ${AKTIV} (${AKTIV_PORT}). Neue Version geht nach ${NEU} (${NEU_PORT})." # --- Neue Version in der inaktiven Farbe starten --- podman rm -f "kfz-${NEU}" 2>/dev/null || true podman run -d --name "kfz-${NEU}" \ -p "127.0.0.1:${NEU_PORT}:8080" \ -e "UMGEBUNG=produktion" \ --health-cmd 'curl -f http://localhost:8080/health || exit 1' \ --health-interval 5s \ "$NEUES_IMAGE" # --- Warten, bis sie gesund ist --- echo "Warte auf Gesundheitsstatus ..." for i in {1..30}; do status=$(podman inspect "kfz-${NEU}" --format '{{.State.Health.Status}}') [[ "$status" == "healthy" ]] && break sleep 2 done if [[ "$status" != "healthy" ]]; then echo "FEHLER: Neue Version wird nicht gesund. Umschaltung unterbleibt." podman logs --tail 50 "kfz-${NEU}" podman rm -f "kfz-${NEU}" exit 1 fi # --- Fachliche Stichprobe vor der Umschaltung --- ergebnis=$(curl -fsS "http://127.0.0.1:${NEU_PORT}/api/praemie?sf=5&alter=3" | jq -r '.betrag') if [[ "$ergebnis" != "288.00" ]]; then echo "FEHLER: Fachliche Prüfung fehlgeschlagen (${ergebnis}). Umschaltung unterbleibt." podman rm -f "kfz-${NEU}" exit 1 fi # --- Umschalten --- echo "Schalte um auf ${NEU} ..." sed -i "s/127.0.0.1:${AKTIV_PORT}/127.0.0.1:${NEU_PORT}/" "$PROXY_KONF" nginx -t && systemctl reload nginx echo "Umschaltung erfolgt. ${AKTIV} bleibt als Rückfallebene stehen." echo "Zurückschalten: sed -i 's/${NEU_PORT}/${AKTIV_PORT}/' ${PROXY_KONF} && systemctl reload nginx"
upstream kfz_backend {
server 127.0.0.1:8081;
}
server {
listen 443 ssl;
server_name kfz.intern;
ssl_certificate /etc/pki/tls/certs/kfz.intern.crt;
ssl_certificate_key /etc/pki/tls/private/kfz.intern.key;
location / {
proxy_pass http://kfz_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Aufgaben:
Die vorletzte Aufgabe ist die wichtigste. In Kapitel 15 taucht diese Zahl als Time to Restore Service wieder auf — eine der vier zentralen DevOps-Kennzahlen. Wer sie gemessen hat, kann sie verbessern. Wer sie schätzt, schätzt meist zu optimistisch.
| Anti-Pattern | Folge | Abhilfe |
|---|---|---|
| Ausrollen ohne Rückweg | jede Auslieferung ist ein Wagnis | Rollback vorher üben, nicht im Ernstfall |
| Canary ohne Messung | man merkt nichts und schaltet trotzdem weiter | erst Observability, dann Canary |
| Flags ohne Ablaufdatum | Codepfad-Wildwuchs | Ablaufdatum und Ticket beim Anlegen |
| Blue/Green mit gemeinsamer Datenbank ohne Expand-Contract | Rollback bricht die Daten | rückwärtskompatible Migrationen |
| Rollback erst nach der Ursachenanalyse | Ausfallzeit verlängert sich | erst wiederherstellen, dann verstehen |
| Ausrollen freitags um 16 Uhr | niemand da, wenn es klemmt | entweder früher — oder gute Automatisierung |
Der letzte Punkt verdient eine Anmerkung: Das Freitagsverbot ist ein Symptom, keine Lösung. Es bedeutet, dass dem eigenen Ausrollverfahren nicht getraut wird. Reife Organisationen liefern freitags aus, weil sie es können — nicht weil sie mutig sind.
Wann habt ihr zuletzt ein Rollback durchgeführt — und war das eine geübte Routine oder eine Improvisation?
Weiter mit Kapitel 09 — Infrastructure as Code