#!/bin/sh # Sichert das Docker-Volume "api-data" (Ereignis-Logs, Snapshots, Anhänge, Nutzer) als # komprimiertes Tar-Archiv. Läuft über einen kurzlebigen Alpine-Container mit Zugriff auf das # Volume - kein direkter Host-Pfad, seit das Volume kein Bind-Mount mehr ist (siehe # docker-compose.yml: Dokploy-Redeploys klonen das Repo neu, ein Bind-Mount relativ zum # Checkout würde dabei geleert, siehe TODO.md 10.2.4). # # Der volle Docker-Volume-Name ist "_api-data" - bei einem lokalen # "cd docker && docker compose up" ist das "docker_api-data" (Default unten), bei Dokploy der # App-Slug, z.B. "lehrerapp-syncserver-xyz_api-data". Im Zweifel prüfen mit: # docker volume ls | grep api-data # und den echten Namen per LEHRERAPP_DATA_VOLUME übergeben: # LEHRERAPP_DATA_VOLUME=lehrerapp-syncserver-xyz_api-data /pfad/zu/docker/backup.sh # # Aufruf z.B. per Cron: # 0 3 * * * LEHRERAPP_DATA_VOLUME=... /pfad/zu/docker/backup.sh >> /pfad/zu/docker/backup.log 2>&1 set -eu SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" BACKUP_DIR="$SCRIPT_DIR/backups" TIMESTAMP="$(date +%Y%m%d-%H%M%S)" KEEP_DAYS=30 VOLUME_NAME="${LEHRERAPP_DATA_VOLUME:-docker_api-data}" if ! docker volume inspect "$VOLUME_NAME" >/dev/null 2>&1; then echo "Docker-Volume '$VOLUME_NAME' nicht gefunden (docker volume ls | grep api-data) - nichts zu sichern." >&2 exit 1 fi mkdir -p "$BACKUP_DIR" docker run --rm \ -v "$VOLUME_NAME":/data:ro \ -v "$BACKUP_DIR":/backup \ alpine:3 \ tar -czf "/backup/lehrerapp-data-$TIMESTAMP.tar.gz" -C /data . # Alte Backups jenseits von KEEP_DAYS aufräumen, damit das Verzeichnis nicht unbegrenzt wächst. find "$BACKUP_DIR" -name 'lehrerapp-data-*.tar.gz' -mtime "+$KEEP_DAYS" -delete echo "Backup erstellt: $BACKUP_DIR/lehrerapp-data-$TIMESTAMP.tar.gz"