08 — Deployment-Strategien

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.

8.1 Warum die Strategie zählt

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.

8.2 Recreate — die einfachste Variante

  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

8.3 Rolling Update

  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.

8.4 Blue/Green

              ┌─────────────┐
   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.

8.5 Canary

   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.

8.6 Shadow Traffic

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.

8.7 Gegenüberstellung

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.

8.8 Feature Flags

Die Technik, die Deployment und Release endgültig entkoppelt.

src/features.py
"""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"))

Vier Arten von Flags

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.

8.9 Rollback oder Roll-forward

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.

8.10 Lab: Blue/Green mit Podman

Umsetzbar auf einem einzelnen Server, auch auf einem Raspberry Pi.

scripts/bluegreen.sh
#!/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"
/etc/nginx/conf.d/kfz-upstream.conf
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:

  1. Führe das Skript zweimal aus und beobachte, wie die Farben wechseln.
  2. Lass die fachliche Stichprobe absichtlich fehlschlagen. Prüfe, dass die alte Version weiterläuft.
  3. Miss, wie lange die Umschaltung tatsächlich dauert.
  4. Schalte von Hand zurück und stoppe die Zeit. Das ist eure reale Rollback-Dauer — eine Zahl, die man kennen sollte, bevor man sie braucht.
  5. Überlege: Was müsste am Skript geändert werden, damit es Canary statt Blue/Green umsetzt?

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.

8.11 Anti-Pattern

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.

8.12 Reflexionsfrage

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