TeamVis Self-Host-Bundle v0.32.0
This commit is contained in:
@@ -12,6 +12,17 @@ docker login git.zfx.services # Benutzer: teamvis-pull · Passwort: <Im
|
||||
bash deploy/selfhost/install.sh # bei der DB-Frage Modus 2 = alles mitinstallieren
|
||||
```
|
||||
|
||||
## Aktualisieren
|
||||
|
||||
```bash
|
||||
bash deploy/selfhost/update.sh
|
||||
```
|
||||
|
||||
Macht ein DB-Backup, holt neue Migrationen + das aktuelle Image und spielt **nur
|
||||
die neu hinzugekommenen** Migrationen ein. **Wichtig:** Updates immer über
|
||||
`update.sh` laufen lassen — nicht selbst `git pull`, sonst können Migrationen
|
||||
übersprungen werden.
|
||||
|
||||
Vollständige Schritt-für-Schritt-Anleitung (von der nackten VM bis live):
|
||||
**`docs/SELFHOST-QUICKSTART.md`**. Hintergrund & Varianten:
|
||||
`deploy/selfhost/README.md` · Detail-Runbook: `docs/NEUKUNDE.md`.
|
||||
|
||||
Executable
+112
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env bash
|
||||
# =====================================================================
|
||||
# TeamVis — Update einer Self-Host-Instanz
|
||||
# =====================================================================
|
||||
# Aktualisiert eine bestehende Instanz in einem Rutsch:
|
||||
# 1. Pre-Update-Backup der Datenbank (Modus 2)
|
||||
# 2. `git pull` im Bundle → neue Migrationen + Skripte
|
||||
# 3. NUR die NEU hinzugekommenen Migrationen einspielen (git als Ledger:
|
||||
# welche Dateien seit dem letzten Stand dazukamen)
|
||||
# 4. neues App-Image ziehen + Container neu starten
|
||||
#
|
||||
# Warum git als Ledger? Die Migrationen sind append-only. `git diff` zwischen
|
||||
# altem und neuem Stand liefert exakt die neuen Migrationsdateien — kein
|
||||
# separater DB-Tracker nötig, kein erneutes Ausführen alter Migrationen.
|
||||
#
|
||||
# Aufruf: bash deploy/selfhost/update.sh [instanz-verzeichnis]
|
||||
# (ohne Argument: das Instanz-Verzeichnis wird automatisch erkannt, wenn
|
||||
# es genau eines gibt.)
|
||||
set -euo pipefail
|
||||
|
||||
c_bold=$'\033[1m'; c_grn=$'\033[32m'; c_red=$'\033[31m'; c_yel=$'\033[33m'; c_rst=$'\033[0m'
|
||||
say() { printf '%s\n' "$*"; }
|
||||
head() { printf '\n%s%s%s\n' "$c_bold" "$*" "$c_rst"; }
|
||||
ok() { printf '%s✓%s %s\n' "$c_grn" "$c_rst" "$*"; }
|
||||
warn() { printf '%s!%s %s\n' "$c_yel" "$c_rst" "$*"; }
|
||||
die() { printf '%s✗ %s%s\n' "$c_red" "$*" "$c_rst" >&2; exit 1; }
|
||||
|
||||
BUNDLE="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
cd "$BUNDLE"
|
||||
[ -d .git ] || die "Kein git-Repo in $BUNDLE — Updates laufen über 'git pull'. Bitte das Bundle per 'git clone' beziehen."
|
||||
command -v docker >/dev/null || die "docker fehlt."
|
||||
|
||||
# ── Instanz-Verzeichnis bestimmen (enthält docker-compose.yml + .env) ──
|
||||
INSTANCE="${1:-}"
|
||||
if [ -z "$INSTANCE" ]; then
|
||||
mapfile -t cands < <(
|
||||
for d in "$BUNDLE"/*/; do
|
||||
[ -f "${d}docker-compose.yml" ] && [ -f "${d}.env" ] && printf '%s\n' "${d%/}"
|
||||
done
|
||||
)
|
||||
if [ "${#cands[@]}" -eq 1 ]; then
|
||||
INSTANCE="${cands[0]}"
|
||||
elif [ "${#cands[@]}" -eq 0 ]; then
|
||||
die "Kein Instanz-Verzeichnis gefunden. Bitte als Argument angeben: bash deploy/selfhost/update.sh <verzeichnis>"
|
||||
else
|
||||
say "Mehrere Instanzen gefunden:"; printf ' %s\n' "${cands[@]}"
|
||||
die "Bitte das gewünschte Verzeichnis als Argument angeben."
|
||||
fi
|
||||
fi
|
||||
[ -f "$INSTANCE/docker-compose.yml" ] || die "In $INSTANCE liegt keine docker-compose.yml."
|
||||
ok "Instanz: $INSTANCE"
|
||||
|
||||
# Modus erkennen: eigener db-Service (Modus 2) oder externe Supabase (Modus 1).
|
||||
MODE2=0
|
||||
grep -qE '^[[:space:]]+db:' "$INSTANCE/docker-compose.yml" && MODE2=1
|
||||
|
||||
POSTGRES_DB="$(grep -E '^POSTGRES_DB=' "$INSTANCE/.env" 2>/dev/null | cut -d= -f2- || true)"
|
||||
POSTGRES_DB="${POSTGRES_DB:-postgres}"
|
||||
PGPW="$(grep -E '^POSTGRES_PASSWORD=' "$INSTANCE/.env" 2>/dev/null | cut -d= -f2- || true)"
|
||||
dbsql() { ( cd "$INSTANCE" && docker compose exec -T -e PGPASSWORD="$PGPW" db psql -v ON_ERROR_STOP=1 -U supabase_admin -d "$POSTGRES_DB" "$@" ); }
|
||||
|
||||
# ── 1. Pre-Update-Backup (nur Modus 2 — lokale DB) ────────────────────
|
||||
if [ "$MODE2" = "1" ]; then
|
||||
head "1) Datenbank-Backup"
|
||||
ts="$(date +%Y%m%d-%H%M%S)"
|
||||
dump="$INSTANCE/backup-db-$ts.sql"
|
||||
if ( cd "$INSTANCE" && docker compose exec -T -e PGPASSWORD="$PGPW" db pg_dump -U supabase_admin "$POSTGRES_DB" ) > "$dump" 2>/dev/null; then
|
||||
ok "Backup: $dump ($(wc -l < "$dump") Zeilen)"
|
||||
else
|
||||
warn "Backup fehlgeschlagen — trotzdem fortfahren? (Strg-C zum Abbrechen)"; read -r _ || true
|
||||
fi
|
||||
else
|
||||
warn "Externe Supabase (Modus 1): Backup macht dein Supabase-Anbieter. Kein lokaler Dump."
|
||||
fi
|
||||
|
||||
# ── 2. git pull → neue Migrationen/Skripte ────────────────────────────
|
||||
head "2) Bundle aktualisieren (git pull)"
|
||||
OLD="$(git rev-parse HEAD)"
|
||||
git pull --ff-only origin main || die "git pull fehlgeschlagen (abweichende Branches?). Notfalls: git fetch && git reset --hard origin/main"
|
||||
NEW="$(git rev-parse HEAD)"
|
||||
if [ "$OLD" = "$NEW" ]; then
|
||||
ok "Schon aktuell (keine neuen Commits)."
|
||||
else
|
||||
ok "Aktualisiert: ${OLD:0:8} → ${NEW:0:8}"
|
||||
fi
|
||||
|
||||
# ── 3. NUR neue Migrationen einspielen ────────────────────────────────
|
||||
head "3) Neue Migrationen"
|
||||
mapfile -t NEWMIG < <(git diff --diff-filter=A --name-only "$OLD" "$NEW" -- 'supabase/migrations/*.sql' 2>/dev/null | sort)
|
||||
if [ "${#NEWMIG[@]}" -eq 0 ]; then
|
||||
ok "Keine neuen Migrationen."
|
||||
elif [ "$MODE2" = "1" ]; then
|
||||
for m in "${NEWMIG[@]}"; do
|
||||
say "→ $m"
|
||||
dbsql < "$BUNDLE/$m"
|
||||
done
|
||||
ok "${#NEWMIG[@]} Migration(en) eingespielt."
|
||||
else
|
||||
warn "Externe Supabase: bitte diese neuen Migrationen EINMAL in Supabase Studio (SQL-Editor) ausführen:"
|
||||
for m in "${NEWMIG[@]}"; do say " $BUNDLE/$m"; done
|
||||
read -r -p " Enter drücken, sobald sie eingespielt sind … " _ || true
|
||||
fi
|
||||
|
||||
# ── 4. Neues Image ziehen + Container neu starten ─────────────────────
|
||||
head "4) App aktualisieren"
|
||||
( cd "$INSTANCE" && docker compose pull && docker compose up -d )
|
||||
ok "Container neu gestartet."
|
||||
|
||||
head "Fertig 🎉"
|
||||
SITE_URL="$(grep -E '^SITE_URL=|^NEXT_PUBLIC_SITE_URL=' "$INSTANCE/.env" 2>/dev/null | head -1 | cut -d= -f2-)"
|
||||
[ -n "$SITE_URL" ] && say " $SITE_URL"
|
||||
say " Bei Problemen Logs prüfen: ( cd $INSTANCE && docker compose logs -f app )"
|
||||
+12
-3
@@ -216,12 +216,21 @@ Patch + Minor sind DB-rückwärtskompatibel (altes Image läuft mit neuer DB).
|
||||
Image-Tag in Production **immer pinnen** (`teamvis:0.11.6`), nicht `:latest` —
|
||||
sonst zieht ein `compose pull` ungewollt einen Major-Sprung.
|
||||
|
||||
**Standard-Update:**
|
||||
**Standard-Update (Self-Host-Bundle, empfohlen):**
|
||||
```bash
|
||||
# Im Bundle-Verzeichnis (teamvis-selfhost) — erledigt Backup, neue Migrationen
|
||||
# (nur die NEUEN, git als Ledger) und Image-Update in einem Schritt:
|
||||
bash deploy/selfhost/update.sh
|
||||
```
|
||||
> Wichtig: Updates **immer** über `update.sh` — nicht selbst `git pull`, sonst
|
||||
> können Migrationen übersprungen werden.
|
||||
|
||||
**Manuell (externe Supabase ohne psql-Zugang / Sonderfall):**
|
||||
```bash
|
||||
# 1. Backup (siehe Abschnitt 8)
|
||||
# 2. Release-Notes / CHANGELOG.md prüfen
|
||||
# 3. fehlende Migration(en) aus supabase/migrations/ einspielen (nur die neuen!)
|
||||
# 4. Tag im docker-compose.yml bumpen
|
||||
# 3. NEUE Migration(en) aus supabase/migrations/ in Supabase Studio einspielen
|
||||
# 4. Image-Tag aktualisieren
|
||||
docker compose pull && docker compose up -d --force-recreate
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user