feat(ops): Automatisches Backup (DB + Dateien, 30 Tage) (v1.8.11)
Schliesst den offenen Punkt: die Datenschutzerklärung nannte "bis zu 30 Tage", real fehlte ein Backup. - Neuer backup-Container (postgres:16-alpine) in docker-compose.yml und deploy/portainer-stack.yml: täglich pg_dump (custom/komprimiert) + tar der MinIO-Dateien, Prune > 30 Tage, im Volume backups_data - Konfigurierbar: BACKUP_RETENTION_DAYS, BACKUP_INTERVAL_HOURS (.env.example ergänzt) - scripts/restore.sh + docs/BACKUP.md (Einrichtung, Off-Site-Hinweis, Restore DB+Dateien, Restore-Test-Tabelle) - TOM-Doku aktualisiert (Backup vorhanden) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -84,6 +84,49 @@ services:
|
||||
volumes:
|
||||
- ./prisma:/app/prisma
|
||||
|
||||
# Automatisches Backup: täglicher Postgres-Dump + Datei-Backup (MinIO), 30 Tage Aufbewahrung.
|
||||
# Backups liegen im Volume "backups_data" (für Off-Site: unten auf einen Host-Pfad umstellen).
|
||||
backup:
|
||||
image: postgres:16-alpine
|
||||
container_name: lageplan-backup
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
PGHOST: db
|
||||
PGUSER: ${POSTGRES_USER:-lageplan}
|
||||
PGPASSWORD: ${POSTGRES_PASSWORD:-lageplan_secret}
|
||||
PGDATABASE: ${POSTGRES_DB:-lageplan}
|
||||
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-30}
|
||||
BACKUP_INTERVAL_HOURS: ${BACKUP_INTERVAL_HOURS:-24}
|
||||
volumes:
|
||||
- backups_data:/backups
|
||||
- minio_data:/minio:ro
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
echo "[backup] Start - alle $${BACKUP_INTERVAL_HOURS}h, Aufbewahrung $${BACKUP_RETENTION_DAYS} Tage";
|
||||
while true; do
|
||||
TS=$$(date +%Y-%m-%d_%H%M%S);
|
||||
mkdir -p /backups;
|
||||
echo "[backup] $$TS Datenbank sichern...";
|
||||
if pg_dump -h "$$PGHOST" -U "$$PGUSER" -d "$$PGDATABASE" -Fc -f "/backups/db_$$TS.dump"; then
|
||||
echo "[backup] DB ok: db_$$TS.dump";
|
||||
else
|
||||
echo "[backup] DB FEHLGESCHLAGEN"; rm -f "/backups/db_$$TS.dump";
|
||||
fi;
|
||||
if [ -d /minio ]; then
|
||||
tar czf "/backups/files_$$TS.tar.gz" -C /minio . 2>/dev/null && echo "[backup] Dateien ok: files_$$TS.tar.gz" || echo "[backup] Dateien uebersprungen";
|
||||
fi;
|
||||
find /backups -name "db_*.dump" -mtime +$$BACKUP_RETENTION_DAYS -delete 2>/dev/null || true;
|
||||
find /backups -name "files_*.tar.gz" -mtime +$$BACKUP_RETENTION_DAYS -delete 2>/dev/null || true;
|
||||
echo "[backup] fertig - naechstes in $${BACKUP_INTERVAL_HOURS}h";
|
||||
sleep $$(( BACKUP_INTERVAL_HOURS * 3600 ));
|
||||
done
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
minio_data:
|
||||
backups_data:
|
||||
|
||||
Reference in New Issue
Block a user