Add guarded pre-production deployment script

This commit is contained in:
2026-09-15 20:29:43 +02:00
parent d1bb184b17
commit 39af9ecdb4
2 changed files with 88 additions and 8 deletions
+22 -8
View File
@@ -86,20 +86,34 @@ Den Beispielpfad durch den tatsächlichen absoluten Pfad ersetzen, kein `~` in `
Vor Aktivierung bestätigen: Die vorhandene DB ist die Pre-Production-DB, keine lokalen Daten oder Sessions wurden importiert. Übernommene `sessions`, `push_devices` und `push_notifications` aus einem anderen Umfeld müssen vor Aktivierung gezielt bereinigt werden; dies nicht durch Kopieren lokaler Daten lösen. Für den Smoke-Test frisch in Pre-Production anmelden und das Gerät dort registrieren. Vor Aktivierung bestätigen: Die vorhandene DB ist die Pre-Production-DB, keine lokalen Daten oder Sessions wurden importiert. Übernommene `sessions`, `push_devices` und `push_notifications` aus einem anderen Umfeld müssen vor Aktivierung gezielt bereinigt werden; dies nicht durch Kopieren lokaler Daten lösen. Für den Smoke-Test frisch in Pre-Production anmelden und das Gerät dort registrieren.
Der bevorzugte reguläre Deployment-Weg im bestehenden Checkout ist nun:
```bash ```bash
git pull --ff-only ./scripts/deploy-preprod.sh
docker compose -f compose.yml -f compose.preprod.yml config --quiet ```
docker compose -f compose.yml -f compose.preprod.yml build web
docker compose -f compose.yml -f compose.preprod.yml run --rm --no-deps web \ Das Script verlangt Branch `main` und einen sauberen Working Tree, führt `git pull --ff-only origin main` aus und benutzt durchgehend `sudo docker compose -f compose.yml -f compose.preprod.yml`. Es prüft die Konfiguration still, baut nur das Web-Image und führt den erwarteten Service-Account-Preflight in einem temporären Container aus. Erst bei Exit-Code 0 und `PASS` aktualisiert es mit `up -d --no-deps web`; danach prüft es den laufenden Container. Zum Abschluss zeigt es Compose-Status, höchstens 100 Web-Logzeilen der letzten zwei Minuten und den deployten Commit. Build- oder Preflight-Fehler vor `up` lassen den laufenden Webcontainer unverändert. Das Script führt kein `down`, keine Volume-Operation, keinen erzwungenen Recreate und keine DB-Aktualisierung aus.
#### Manueller Fallback / Troubleshooting
Die einzelnen Schritte bleiben für Diagnose oder Script-Ausfall verfügbar. In allen Befehlen dieselben gegebenenfalls vorhandenen Server-Overrides ergänzen:
```bash
git status --short
git pull --ff-only origin main
sudo docker compose -f compose.yml -f compose.preprod.yml config --quiet
sudo docker compose -f compose.yml -f compose.preprod.yml build web
sudo docker compose -f compose.yml -f compose.preprod.yml run --rm --no-deps web \
python push_preflight.py \ python push_preflight.py \
--expected-service-account metalcircle-push-preprod@metalcircle-30d9b.iam.gserviceaccount.com --expected-service-account metalcircle-push-preprod@metalcircle-30d9b.iam.gserviceaccount.com
# Nur bei PASS fortsetzen. Das bestehende db-Service muss bereits laufen. # Nur bei PASS fortsetzen. Das bestehende db-Service muss bereits laufen.
docker compose -f compose.yml -f compose.preprod.yml up -d --no-deps web sudo docker compose -f compose.yml -f compose.preprod.yml up -d --no-deps web
docker compose -f compose.yml -f compose.preprod.yml exec -T web \ sudo docker compose -f compose.yml -f compose.preprod.yml exec -T web \
python push_preflight.py \ python push_preflight.py \
--expected-service-account metalcircle-push-preprod@metalcircle-30d9b.iam.gserviceaccount.com --expected-service-account metalcircle-push-preprod@metalcircle-30d9b.iam.gserviceaccount.com
docker compose -f compose.yml -f compose.preprod.yml ps sudo docker compose -f compose.yml -f compose.preprod.yml ps
docker compose -f compose.yml -f compose.preprod.yml logs --since=5m --tail=100 web sudo docker compose -f compose.yml -f compose.preprod.yml logs --since=2m --tail=100 --no-color web
git log -1 --format='%h %s'
``` ```
Zusätzliche bisher verwendete Server-Overrides bei diesen Befehlen beibehalten und ihre endgültigen Werte kontrollieren. Keine neue DB anlegen, kein `down -v`, kein Entwicklungs-Reload-Mount. `config --quiet` prüft ohne Ausgabe der interpolierten Secrets; vollständige `compose config`-/`docker inspect`-Ausgaben nicht teilen. Der normale FastAPI-Start führt die vorhandene Schema-Prüfung aus; diese Push-Konfiguration benötigt keine neue Migration. Zusätzliche bisher verwendete Server-Overrides bei diesen Befehlen beibehalten und ihre endgültigen Werte kontrollieren. Keine neue DB anlegen, kein `down -v`, kein Entwicklungs-Reload-Mount. `config --quiet` prüft ohne Ausgabe der interpolierten Secrets; vollständige `compose config`-/`docker inspect`-Ausgaben nicht teilen. Der normale FastAPI-Start führt die vorhandene Schema-Prüfung aus; diese Push-Konfiguration benötigt keine neue Migration.
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env bash
set -Eeuo pipefail
trap 'status=$?; printf "FEHLER: Deployment in Zeile %s abgebrochen (Exit %s).\n" "$LINENO" "$status" >&2' ERR
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd -P)"
cd -- "$REPO_ROOT"
if ! TOP_LEVEL="$(git rev-parse --show-toplevel 2>/dev/null)" || [[ "$(cd -- "$TOP_LEVEL" && pwd -P)" != "$REPO_ROOT" ]]; then
printf 'FEHLER: %s liegt nicht in einem Git-Repository-Checkout.\n' "$REPO_ROOT" >&2
exit 1
fi
BRANCH="$(git branch --show-current)"
if [[ "$BRANCH" != "main" ]]; then
printf 'FEHLER: Deployment ist nur von Branch main erlaubt (aktuell: %s).\n' "${BRANCH:-unbekannt}" >&2
exit 1
fi
if [[ -n "$(git status --porcelain --untracked-files=all)" ]]; then
printf 'FEHLER: Working Tree ist nicht sauber. Änderungen zuerst committen oder entfernen.\n' >&2
exit 1
fi
printf 'Aktualisiere main mit Fast-Forward ...\n'
git pull --ff-only origin main
compose() {
sudo docker compose -f compose.yml -f compose.preprod.yml "$@"
}
run_preflight() {
local output
output="$("$@" python push_preflight.py \
--expected-service-account metalcircle-push-preprod@metalcircle-30d9b.iam.gserviceaccount.com)"
printf '%s\n' "$output"
if [[ "$output" != PASS:* ]]; then
printf 'FEHLER: Push-Preflight hat kein PASS geliefert.\n' >&2
return 1
fi
}
printf 'Prüfe Pre-Production-Compose-Konfiguration ...\n'
compose config --quiet
printf 'Baue Web-Image ...\n'
compose build web
printf 'Prüfe Firebase-Credential im temporären Container ...\n'
run_preflight compose run --rm --no-deps web
printf 'Aktualisiere ausschließlich den Webcontainer ...\n'
compose up -d --no-deps web
printf 'Prüfe Firebase-Credential im laufenden Webcontainer ...\n'
run_preflight compose exec -T web
printf '\nCompose-Status:\n'
compose ps
printf '\nWeb-Logs der letzten 2 Minuten (maximal 100 Zeilen):\n'
compose logs --since=2m --tail=100 --no-color web
printf '\nDeployter Git-Commit:\n'
git log -1 --format='%h %s'