deploy/truenas/compose.yaml:
- 4 services: db (postgres:17), api (.NET), frontend (nginx), backup sidecar
- Named volumes as NAS bind-mounts (paths configured in .env)
- Healthchecks: db pg_isready, api /health, frontend waits on api
- ANTHROPIC_API_KEY placeholder for FEAT-12a AI stub
deploy/truenas/.env.example: POSTGRES_PASSWORD, PORT, REGISTRY, dataset paths
deploy/truenas/scripts/:
- entrypoint.sh: installs daily 03:00 cron, starts crond in foreground
- backup.sh: pg_dump -> .sql + tar czf photos -> .tar.gz + rotation
- restore.sh: psql < dump + tar xzf photos; confirmation prompt (-f to skip)
Predecessor logic (commit 6a37f9e) translated from PowerShell to POSIX sh
for Alpine containers. Same pg_dump/restore semantics, same KEEP_DAYS rotation.
.gitea/workflows/ci.yml (DRAFT -- inactive until Julian confirms Actions):
dotnet test + npm test/build on push/PR to main;
docker build+push to Gitea registry on main push only
docs/ops.md:
German ops guide -- architecture diagram, first-install checklist,
start/stop/update commands, backup runbook (manual + auto), ZFS-snapshot
layering strategy, CI activation steps, open questions, troubleshooting table
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
57 lines
2.1 KiB
Bash
57 lines
2.1 KiB
Bash
#!/bin/sh
|
|
# GerbilManager Backup-Skript (Container-Welt)
|
|
# Laeuft als Cron-Job im backup-Sidecar-Container.
|
|
# Volumes: /data/photos (read-only), /backups (read-write)
|
|
# Umgebungsvariablen: PGPASSWORD, POSTGRES_HOST, POSTGRES_USER, POSTGRES_DB, BACKUP_KEEP_DAYS
|
|
set -e
|
|
|
|
TIMESTAMP=$(date +%Y-%m-%d_%H-%M)
|
|
BACKUP_DIR="/backups/$TIMESTAMP"
|
|
DB_DUMP="$BACKUP_DIR/gerbilmanager_${TIMESTAMP}.sql"
|
|
PHOTO_ARCHIVE="$BACKUP_DIR/photos_${TIMESTAMP}.tar.gz"
|
|
KEEP_DAYS="${BACKUP_KEEP_DAYS:-7}"
|
|
HOST="${POSTGRES_HOST:-db}"
|
|
USER="${POSTGRES_USER:-postgres}"
|
|
DB="${POSTGRES_DB:-gerbilmanager}"
|
|
|
|
log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"; }
|
|
|
|
log "=== Backup gestartet ($TIMESTAMP) ==="
|
|
mkdir -p "$BACKUP_DIR"
|
|
|
|
# --- Datenbank-Dump ---
|
|
log "Erstelle pg_dump fuer $DB@$HOST..."
|
|
if ! pg_dump -h "$HOST" -U "$USER" -d "$DB" --clean --if-exists --format=plain \
|
|
> "$DB_DUMP" 2>/tmp/pg_err; then
|
|
log "FEHLER bei pg_dump: $(cat /tmp/pg_err)"
|
|
exit 1
|
|
fi
|
|
DUMP_SIZE=$(du -k "$DB_DUMP" | cut -f1)
|
|
log "Dump erstellt: $DB_DUMP (${DUMP_SIZE} KB)"
|
|
|
|
# Validierung: mindestens CREATE TABLE muss vorhanden sein
|
|
if ! grep -q "CREATE TABLE" "$DB_DUMP" 2>/dev/null; then
|
|
log "WARNUNG: Dump sieht ungueltig aus -- bitte $DB_DUMP pruefen"
|
|
fi
|
|
|
|
# --- Fotos archivieren ---
|
|
if [ -d /data/photos ] && [ "$(ls -A /data/photos 2>/dev/null)" ]; then
|
|
PHOTO_COUNT=$(find /data/photos -type f | wc -l)
|
|
log "Archiviere $PHOTO_COUNT Fotos..."
|
|
tar czf "$PHOTO_ARCHIVE" -C /data photos/ 2>/tmp/tar_err || {
|
|
log "WARNUNG: Foto-Archiv fehlgeschlagen: $(cat /tmp/tar_err)"
|
|
}
|
|
PHOTO_SIZE=$(du -k "$PHOTO_ARCHIVE" 2>/dev/null | cut -f1)
|
|
log "Foto-Archiv erstellt: $PHOTO_ARCHIVE (${PHOTO_SIZE} KB)"
|
|
else
|
|
log "Keine Fotos gefunden -- Foto-Backup uebersprungen"
|
|
fi
|
|
|
|
# --- Rotation: alte Backups loeschen ---
|
|
log "Rotiere Backups (behalte $KEEP_DAYS Tage)..."
|
|
find /backups -maxdepth 1 -type d -name '????-??-??_??-??' \
|
|
-mtime "+$KEEP_DAYS" -exec rm -rf {} + 2>/dev/null || true
|
|
REMAINING=$(find /backups -maxdepth 1 -type d -name '????-??-??_??-??' | wc -l)
|
|
log "Backup abgeschlossen. Vorhandene Sicherungen: $REMAINING"
|
|
log "=== Ende ==="
|