Add guarded pre-production deployment script
This commit is contained in:
+22
-8
@@ -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.
|
||||||
|
|||||||
Executable
+66
@@ -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'
|
||||||
Reference in New Issue
Block a user