Eingewebt von mana/scripts/deploy/haertung.mjs zwischen den Marken
`mana-deploy-haertung`. Von Hand geänderter Block ist beim nächsten Lauf
des Generators weg.
Anlass: drei Ausfälle auf seepuls.com in acht Tagen, zwei verschiedene
Ursachen, dasselbe Symptom — und keiner davon war im Skript abgesichert.
(a) 2026-08-04 compose benennt den Container mitten im Recreate um
und findet ihn nicht mehr → beide auf `Created`, 502.
Ein nackter zweiter Lauf heilt.
(b) 2026-08-11 Container ohne sein externes Netz → kommt nicht an die
geteilte Cluster-DB, ECONNREFUSED, Restart-Schleife.
Ein nackter zweiter Lauf heilt NICHT — aus compose-
Sicht ist der Container aktuell. Es braucht
--force-recreate.
Deshalb genau ein Wiederholversuch mit --force-recreate (deckt beide),
davor die Diagnose, die (b) sonst als „Postgres ist unten" verkleidet:
`docker ps -a` mit Netz-Spalte. Ohne -a ist ein `Created`-Container
unsichtbar.
Dazu die Tür: bisher konnte dieses Skript „✓ Deploy fertig" melden,
während die Seite 502 lieferte — der Health-Check prüft loopback,
zwischen Container und Leserin liegen cloudflared und Cloudflare.
Gezählt am 2026-08-11 über 64 deploy.sh im Bestand: 7 fassten die Tür an.
2xx UND 3xx zählen (pageta antwortet 307 auf die Anmeldung; ein strikter
200-Riegel hätte dessen Deploys blockiert). Kein Rollback — ein
Rand-Problem heilt kein Zurückdrehen, aber der Exit-Code sagt die
Wahrheit.
Geprüft ohne Deploy, mit gefälschten docker/curl-Binaries, drei
Szenarien je Skript:
alles gesund → exit 0, ein up, kein Wiederholversuch, Tür ✓
erstes up fällt → exit 0, zwei ups, „geheilt"
Tür liefert 502 → exit 1, „Tür antwortet 502"
Wirkt beim nächsten Deploy dieser App — das Skript wird auf dem Server
aus dem Checkout gelesen.
Sitzung: 5cc8dc6b
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
92 lines
4.4 KiB
Bash
Executable file
92 lines
4.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
||
# Server-seitiges Deploy von Pageta (API + Web) auf dem Mac Mini.
|
||
#
|
||
# Voller Flow:
|
||
# lokal: git push
|
||
# Server: ssh mana-server-remote 'zsh -lc "cd ~/projects/pageta && git pull --ff-only && ./deploy.sh"'
|
||
#
|
||
# Entschlüsselt die Secrets (SOPS/age) nach infrastructure/.env.production und
|
||
# baut/recreatet pageta-api + pageta-web. infrastructure/secrets.enc.env ist die
|
||
# SOT (verschlüsselt, committed); .env.production ist gitignored.
|
||
# age-Privat-Key: ~/.config/sops/age/keys.txt. Doku: mana/docs/SECRETS_MANAGEMENT.md.
|
||
#
|
||
# Fallen (siehe Deploy-Memory): -p pageta Pflicht; KEIN --remove-orphans
|
||
# (pageta-landing ist separat); --no-deps lässt postgres in Ruhe.
|
||
set -euo pipefail
|
||
fail() { echo "✗ Deploy fehlgeschlagen: $*" >&2; exit 1; }
|
||
trap 'fail "unerwarteter Fehler in Zeile $LINENO"' ERR
|
||
|
||
cd "$(dirname "$0")"
|
||
export PATH="/opt/homebrew/bin:/Applications/Docker.app/Contents/Resources/bin:$PATH"
|
||
export SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt"
|
||
|
||
if [ ! -f "$SOPS_AGE_KEY_FILE" ]; then
|
||
echo "FEHLER: age-Key $SOPS_AGE_KEY_FILE fehlt — siehe SECRETS_MANAGEMENT.md" >&2
|
||
exit 1
|
||
fi
|
||
|
||
echo "→ Secrets entschlüsseln (sops)…"
|
||
sops -d --input-type dotenv --output-type dotenv infrastructure/secrets.enc.env > infrastructure/.env.production.tmp
|
||
mv infrastructure/.env.production.tmp infrastructure/.env.production
|
||
chmod 600 infrastructure/.env.production
|
||
|
||
echo "→ Build (≤ 3× Retry bei transienten Pull-Timeouts)…"
|
||
__ok=0
|
||
for __i in 1 2 3; do
|
||
if docker compose -p pageta -f infrastructure/docker-compose.production.yml \
|
||
--env-file infrastructure/.env.production \
|
||
build pageta-api pageta-web; then __ok=1; break; fi
|
||
echo " ⚠ Build-Versuch $__i fehlgeschlagen — neuer Anlauf in 5s…" >&2
|
||
sleep 5
|
||
done
|
||
[ "$__ok" = 1 ] || fail "Build nach 3 Versuchen"
|
||
|
||
echo "→ Hochfahren + auf Bereitschaft warten…"
|
||
# >>> mana-deploy-haertung — GENERAT, nicht von Hand ändern (scripts/deploy/haertung.mjs)
|
||
docker compose -p pageta -f infrastructure/docker-compose.production.yml \
|
||
--env-file infrastructure/.env.production \
|
||
up -d --no-deps --wait --wait-timeout 150 pageta-api pageta-web || {
|
||
echo " ⚠ Nicht bereit. Zustand vor dem zweiten Anlauf:" >&2
|
||
# Ohne -a ist ein Container auf `Created` unsichtbar — es sieht aus,
|
||
# als wäre er verschwunden. Die Netz-Spalte entscheidet den anderen
|
||
# Fall: fehlt das externe Netz, ist die geteilte DB nicht erreichbar
|
||
# und das Log sagt ECONNREFUSED, als wäre Postgres unten.
|
||
docker ps -a --format ' {{.Names}} {{.Status}} [{{.Networks}}]' | grep -E 'pageta' >&2 || true
|
||
docker compose -p pageta -f infrastructure/docker-compose.production.yml \
|
||
--env-file infrastructure/.env.production \
|
||
logs --tail 40 pageta-api pageta-web >&2
|
||
echo " → zweiter Anlauf mit --force-recreate…" >&2
|
||
docker compose -p pageta -f infrastructure/docker-compose.production.yml \
|
||
--env-file infrastructure/.env.production \
|
||
up -d --force-recreate --no-deps --wait --wait-timeout 150 pageta-api pageta-web || {
|
||
docker compose -p pageta -f infrastructure/docker-compose.production.yml \
|
||
--env-file infrastructure/.env.production \
|
||
logs --tail 40 pageta-api pageta-web >&2
|
||
fail "Container nicht bereit, auch nach --force-recreate"
|
||
}
|
||
echo " ✓ zweiter Anlauf hat es geheilt — bitte trotzdem ansehen, warum der erste fiel." >&2
|
||
}
|
||
# <<< mana-deploy-haertung
|
||
|
||
# >>> mana-deploy-haertung — GENERAT, nicht von Hand ändern (scripts/deploy/haertung.mjs)
|
||
echo "→ Tür anfassen…"
|
||
# 2xx UND 3xx zählen als „die Tür antwortet". Gemessen 2026-08-11 über
|
||
# zwanzig Adressen: 19x 200, pageta 307 (Weiterleitung auf die
|
||
# Anmeldung). Ein strikter 200-Riegel hätte pagetas Deploys blockiert.
|
||
# Kein `|| echo 000`: curl schreibt die 000 bei Transportfehlern selbst
|
||
# schon auf stdout — angehängt stünde da 000000, und genau diese Zeile
|
||
# liest jemand im Ausfall.
|
||
__tuer=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 20 https://pageta.mana.how/) || true
|
||
__tuer=${__tuer:-000}
|
||
case "$__tuer" in
|
||
2??|3??) echo " ✓ https://pageta.mana.how/ → HTTP $__tuer" ;;
|
||
*)
|
||
echo " 🔴 https://pageta.mana.how/ → HTTP $__tuer. Container gesund, Seite nicht." >&2
|
||
echo " Container laufen weiter (nicht zurückgedreht) — ein Rand-Problem" >&2
|
||
echo " heilt kein Zurückdrehen. Nächster Blick: cloudflared + Cloudflare." >&2
|
||
fail "Tür antwortet $__tuer"
|
||
;;
|
||
esac
|
||
# <<< mana-deploy-haertung
|
||
|
||
echo "✓ Deploy fertig."
|