pageta/deploy.sh
Till JS e0b55f4e74 deploy: Selbstheilung + Tür-Check (Generat)
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>
2026-08-11 16:38:59 +02:00

92 lines
4.4 KiB
Bash
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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."