Übersicht
Dieses Runbook beschreibt die Backup-, Wiederherstellungs- und Disaster-Recovery-Verfahren für Reva. Es gilt sowohl für Docker-Compose- als auch für Kubernetes-Deployments (k3s).
PostgreSQL ist die einzige zustandsbehaftete Komponente. Alle anderen Dienste (Redis, Ollama, MCP-Server, die Reva-Anwendung selbst) sind zustandslos und starten nach einem Neustart automatisch.
Wiederherstellungsziele
| Metrik | Zielwert | Begründung |
|---|---|---|
| RPO (Recovery Point Objective) | 24 Stunden | Täglicher Backup-Zeitplan |
| RTO (Recovery Time Objective) | 30 Minuten | Wiederherstellung + Neustart + Verifizierung |
Das RPO von 24 Stunden spiegelt den standardmäßigen täglichen Backup-Zeitplan wider. Für strengere RPO-Anforderungen erhöhen Sie die Backup-Frequenz durch Anpassung des Cron-Zeitplans oder CronJob-Intervalls.
Backup-Strategie
Automatische tägliche Backups per Cron auf dem Produktionsserver:
0 2 * * * /home/evdb/roberta/bin/backup-db.sh
Das Skript (bin/backup-db.sh) führt pg_dump im reva-postgres-Container aus, komprimiert mit gzip und speichert das Ergebnis im Verzeichnis backups/. Backups älter als 30 Tage werden automatisch gelöscht.
Manuelles Backup:
./bin/backup-db.sh
Backup-Dateien werden als reva_YYYY-MM-DD_HHMMSS.sql.gz im Verzeichnis backups/ gespeichert.
Ein CronJob (k8s/db-backup-cronjob.yaml) läuft täglich um 02:00 UTC. Er verwendet das pgvector/pgvector:pg16-Image, um pg_dump gegen den postgres-Service auszuführen, komprimiert mit gzip und schreibt auf das db-backups-PVC (5Gi, local-path Storage Class). Backups älter als 30 Tage werden automatisch bereinigt.
Manuelles Backup auslösen:
kubectl create job --from=cronjob/db-backup db-backup-manual -n reva
kubectl logs -n reva job/db-backup-manual -f
Aufbewahrungsrichtlinie
| Umgebung | Speicherort | Aufbewahrung | Max. Speicher |
|---|---|---|---|
| Docker Compose | backups/ auf dem Host-Dateisystem | 30 Tage | Unbegrenzt (Host-Festplatte) |
| Kubernetes | PVC db-backups | 30 Tage | 5Gi |
Backup-Verifizierung
Verfügbare Backups auflisten
ls -lht backups/reva_*.sql.gz
kubectl run backup-ls --rm -it --restart=Never -n reva \
--image=pgvector/pgvector:pg16 \
--overrides='{
"spec": {
"containers": [{
"name": "backup-ls",
"image": "pgvector/pgvector:pg16",
"command": ["ls", "-lht", "/backups/"],
"volumeMounts": [{"name": "backups", "mountPath": "/backups"}]
}],
"volumes": [{
"name": "backups",
"persistentVolumeClaim": {"claimName": "db-backups"}
}]
}
}'
Testwiederherstellung in temporärer Datenbank
Hiermit wird überprüft, ob eine Backup-Datei wiederherstellbar ist, ohne die Produktionsdatenbank zu berühren.
# Backup zur Verifizierung auswählen
BACKUP_FILE="backups/reva_2026-03-15_020000.sql.gz"
# Temporäre Datenbank erstellen, wiederherstellen, dann löschen
docker exec reva-postgres psql -U postgres -c "CREATE DATABASE reva_dr_test;"
gunzip -c "$BACKUP_FILE" | docker exec -i reva-postgres psql -U postgres -d reva_dr_test
docker exec reva-postgres psql -U postgres -d reva_dr_test \
-c "SELECT count(*) FROM reva_subscriptions;"
docker exec reva-postgres psql -U postgres -c "DROP DATABASE reva_dr_test;"
Wenn das SELECT fehlerfrei eine Zeilenanzahl zurückgibt, ist das Backup gültig. Führen Sie diese Prüfung regelmäßig durch, um die Wiederherstellbarkeit Ihrer Backups sicherzustellen.
Wiederherstellung (Docker Compose)
Voraussetzungen
- Eine gültige Backup-Datei in
backups/(verifizieren mitls -lht backups/reva_*.sql.gz) - Der
reva-postgres-Container muss laufen
Schritt für Schritt
# 1. Backup zur Wiederherstellung auswählen
BACKUP_FILE="backups/reva_2026-03-15_020000.sql.gz"
# 2. Anwendung stoppen (Datenbank weiterlaufen lassen)
docker compose stop reva
# 3. Aktive Datenbankverbindungen beenden
docker exec reva-postgres psql -U postgres -c \
"SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'reva' AND pid <> pg_backend_pid();"
# 4. Backup wiederherstellen (--clean --if-exists im Dump behandelt DROP/CREATE)
gunzip -c "$BACKUP_FILE" | docker exec -i reva-postgres psql -U postgres -d reva
# 5. Anwendung neustarten
docker compose up -d reva
# 6. Auf Start warten und Health prüfen
sleep 10
curl -s http://localhost:3978/api/health | python3 -m json.tool
Erwartete Health-Antwort
{
"status": "ok",
"adapter_initialized": true,
"db": true,
"mcp": {
"release": {"connected": true},
"jira": {"connected": true}
}
}
Falls "db": false: Prüfen Sie sofort die PostgreSQL-Logs mit docker compose logs postgres. Häufige Ursachen sind beschädigte Dump-Dateien oder unzureichender Speicherplatz.
Wiederherstellung (Kubernetes)
Voraussetzungen
- Ein gültiges Backup auf dem
db-backups-PVC kubectlfür den Zielcluster konfiguriert
Schritt für Schritt
# 1. Anwendung herunterskalieren, um DB-Verbindungen zu beenden
kubectl scale deployment reva -n reva --replicas=0
# 2. Backup zur Wiederherstellung identifizieren
kubectl run backup-ls --rm -it --restart=Never -n reva \
--image=pgvector/pgvector:pg16 \
--overrides='{
"spec": {
"containers": [{
"name": "backup-ls",
"image": "pgvector/pgvector:pg16",
"command": ["ls", "-lht", "/backups/"],
"volumeMounts": [{"name": "backups", "mountPath": "/backups"}]
}],
"volumes": [{
"name": "backups",
"persistentVolumeClaim": {"claimName": "db-backups"}
}]
}
}'
# 3. Aus Backup wiederherstellen (Dateinamen bei Bedarf anpassen)
BACKUP_NAME="reva_2026-03-15_020000.sql.gz"
kubectl run db-restore --rm -it --restart=Never -n reva \
--image=pgvector/pgvector:pg16 \
--overrides='{
"spec": {
"containers": [{
"name": "db-restore",
"image": "pgvector/pgvector:pg16",
"command": ["sh", "-c", "gunzip -c /backups/'"$BACKUP_NAME"' | PGPASSWORD=$POSTGRES_PASSWORD psql -h postgres -U postgres -d reva"],
"env": [{"name": "POSTGRES_PASSWORD", "valueFrom": {"secretKeyRef": {"name": "reva-postgres-admin-password", "key": "password"}}}],
"volumeMounts": [{"name": "backups", "mountPath": "/backups"}]
}],
"volumes": [{
"name": "backups",
"persistentVolumeClaim": {"claimName": "db-backups"}
}]
}
}'
# 4. Anwendung wieder hochskalieren
kubectl scale deployment reva -n reva --replicas=1
# 5. Auf Rollout warten und Health prüfen
kubectl rollout status deployment/reva -n reva --timeout=120s
kubectl exec -n reva deployment/reva -- curl -s http://localhost:3978/api/health
Schritt 1 nicht überspringen. Das Herunterskalieren der Anwendung stellt sicher, dass keine aktiven Verbindungen die Wiederherstellung stören. Eine Wiederherstellung bei laufender App kann zu inkonsistentem Zustand führen.
Komponenten-Recovery-Matrix
Diese Matrix ermöglicht eine schnelle Bestimmung der Recovery-Maßnahmen pro Komponente während eines Vorfalls.
| Komponente | Zustandsbehaftet? | Wiederherstellung nötig? | Recovery-Maßnahme |
|---|---|---|---|
| PostgreSQL | Ja | Ja | Aus Backup wiederherstellen (siehe Abschnitte 4/5) |
| Redis | Nein (flüchtiger Cache) | Nein | Startet leer; App baut Cache bei Bedarf neu auf |
| Ollama | Nein (Modelle auf Festplatte) | Nein | Modelle werden bei Bedarf automatisch neu heruntergeladen (ollama pull) |
| MCP-Server (Release, Jira) | Nein | Nein | Zustandslose Container; verbinden sich beim Neustart neu |
| Reva-Anwendung | Nein | Nein | Zustandslose FastAPI-App; Tabellen werden automatisch via metadata.create_all() erstellt |
Nur PostgreSQL erfordert aktives Backup und Wiederherstellung. Alle anderen Komponenten sind entweder zustandslos oder speichern Daten, die automatisch regeneriert werden können.
Failover-Checkliste
Kurzreferenz-Checkliste für die Incident Response:
- Bewerten — Identifizieren, welche Komponente ausgefallen ist (
curl /api/health,docker compose psoderkubectl get pods -n reva) - Kommunizieren — Stakeholder benachrichtigen, dass der Bot vorübergehend nicht verfügbar ist
- PostgreSQL prüfen — Falls DB ausgefallen, Logs prüfen (
docker compose logs postgres/kubectl logs -n reva statefulset/postgres) - Aktuelles Backup prüfen — Sicherstellen, dass das neueste Backup existiert und nicht leer ist (siehe Backup-Verifizierung)
- Bei Bedarf wiederherstellen — Wiederherstellungsverfahren für Ihre Umgebung befolgen (Docker Compose oder Kubernetes)
- Health verifizieren —
curl /api/healthmuss"status": "ok"mit"db": truezurückgeben - MCP-Konnektivität verifizieren — Health-Antwort sollte
"connected": truefür Release und Jira zeigen - Bot testen — Testnachricht in Teams senden, um End-to-End-Funktionalität zu bestätigen
- Post-mortem — Ursache, Zeitverlauf und Folgemaßnahmen dokumentieren
Zeit ist entscheidend. Arbeiten Sie diese Checkliste sequenziell ab. Überspringen Sie nicht den Kommunikationsschritt — Stakeholder sollten informiert sein, bevor Sie mit der Wiederherstellung beginnen.
Datenverlust-Szenarien
Datenbank beschädigt oder verloren
Auswirkung: Alle Gesprächsverläufe, Benutzer-Erinnerungen, Benachrichtigungs-Abonnements und Aktivitätsprotokolle gehen verloren.
Wiederherstellung: Aus dem neuesten Backup wiederherstellen. Maximaler Datenverlust = 24 Stunden (RPO). Die Reva-Anwendung erstellt Tabellen beim Start automatisch, wenn sie fehlen — d.h. auch ohne Backup startet der Service, jedoch ohne historische Daten.
# Docker Compose: vollständige Datenbank-Neuerstellung
docker compose down postgres
docker volume rm reva_postgres-data # Beschädigtes Volume entfernen
docker compose up -d postgres # Neue PostgreSQL-Instanz
# Warten, bis Postgres bereit ist, dann wiederherstellen:
sleep 5
gunzip -c backups/reva_LATEST.sql.gz | docker exec -i reva-postgres psql -U postgres -d reva
docker compose up -d reva
Kein Backup verfügbar
Auswirkung: Vollständiger Datenverlust. Historische Gespräche und Erinnerungen können nicht wiederhergestellt werden.
Wiederherstellung: Neu starten. Die Anwendung erstellt alle erforderlichen Tabellen beim Start. Benutzer müssen Benachrichtigungen neu abonnieren. Externe Systeme (Release, Jira) sind nicht betroffen, da sie die Datenquelle für Release-/Issue-Daten sind.
docker compose down
docker volume rm reva_postgres-data
docker compose up -d
kubectl delete pvc postgres-data -n reva
kubectl rollout restart statefulset/postgres -n reva
kubectl rollout restart deployment/reva -n reva
Redis verloren oder beschädigt
Auswirkung: Minimal. Redis wird als flüchtiger Cache verwendet. Es tritt kein Datenverlust auf.
docker compose restart redis
kubectl rollout restart deployment/redis -n reva
MCP-Server nicht erreichbar
Auswirkung: Bot kann nicht mit Digital.ai Release oder Jira interagieren. Gespräche und Erinnerungen funktionieren weiterhin.
Wiederherstellung: MCP-Server verbinden sich automatisch wieder, sobald der Upstream-Dienst verfügbar ist. Netzwerkverbindung und Upstream-Service-Health prüfen.
# MCP-Status prüfen
curl -s http://localhost:3978/api/health | python3 -c \
"import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get('mcp',{}), indent=2))"
docker compose restart release-mcp jira-mcp
# MCP-Sidecars sind Teil des Reva-Pods
kubectl rollout restart deployment/reva -n reva
Ollama nicht verfügbar
Auswirkung: Bot kann keine Nachrichten verarbeiten (LLM-Inferenz offline). Kein Datenverlust.
Wiederherstellung: Ollama neustarten. Modelle sind auf der Festplatte gespeichert und bleiben über Neustarts erhalten. Falls die Modelldateien verloren gehen, werden sie bei der ersten Verwendung automatisch neu heruntergeladen.
docker compose restart ollama
sudo systemctl restart ollama
# Modellverfügbarkeit prüfen
curl -s http://localhost:11434/api/tags | python3 -c \
"import sys,json; [print(m['name']) for m in json.load(sys.stdin)['models']]"
DR-Tests
Zeitplan
Führen Sie vierterljährlich einen vollständigen DR-Test durch. Dokumentieren Sie die Ergebnisse im Incident-Log des Teams.
Testverfahren
- Test-Backup erstellen von der aktuellen Produktionsdatenbank.
- In separater Umgebung wiederherstellen (nicht auf Produktion testen).
# Testdatenbank neben Produktion erstellen docker exec reva-postgres psql -U postgres -c "CREATE DATABASE reva_dr_test;" gunzip -c backups/reva_LATEST.sql.gz | docker exec -i reva-postgres psql -U postgres -d reva_dr_test - Datenintegrität prüfen:
# Tabellenexistenz und Zeilenzahlen prüfen docker exec reva-postgres psql -U postgres -d reva_dr_test -c "\dt" docker exec reva-postgres psql -U postgres -d reva_dr_test -c " SELECT 'conversations' AS tbl, count(*) FROM conversations UNION ALL SELECT 'memories', count(*) FROM memories UNION ALL SELECT 'reva_subscriptions', count(*) FROM reva_subscriptions; " - pgvector-Erweiterung verifizieren:
docker exec reva-postgres psql -U postgres -d reva_dr_test \ -c "SELECT extname, extversion FROM pg_extension WHERE extname = 'vector';" - Aufräumen:
docker exec reva-postgres psql -U postgres -c "DROP DATABASE reva_dr_test;" - Ergebnisse dokumentieren: Datum, verwendete Backup-Datei, ob die Wiederherstellung erfolgreich war, aufgetretene Probleme und benötigte Zeit festhalten.
Was zu verifizieren ist
- Backup-Datei lässt sich fehlerfrei dekomprimieren
pg_dump-Wiederherstellung läuft fehlerfrei durch- Alle erwarteten Tabellen existieren mit plausiblen Zeilenzahlen
- pgvector-Erweiterung ist vorhanden und funktionsfähig
- Anwendung startet und besteht den Health Check nach der Wiederherstellung
Ein bestandener DR-Test bestätigt, dass Ihre Backup-Strategie durchgängig funktioniert. Falls ein Schritt fehlschlägt, untersuchen und beheben Sie das Problem vor dem nächsten vierterljährlichen Test.