Fix #196: one-command operator backup (pg_dump + MinIO)
Move backup from a documented procedure to `deploy/backup.sh`: dumps Postgres (pg_dump --clean --if-exists, gzipped) and archives the MinIO /data directory into a single timestamped bundle under backups/. Reads config from the compose .env with the same defaults the stack uses; optional BACKUP_RETAIN_DAYS prunes old bundles (cron-friendly). BACKUP.md documents usage + the restore procedure (kept manual/documented rather than an untested destructive script). Closes #196 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Justin Paul <justin@jpaul.me>
This commit is contained in:
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# One-command backup of a Provenance deployment: the Postgres database and the
|
||||
# MinIO object store, into a single timestamped bundle under ./backups/.
|
||||
#
|
||||
# ./backup.sh # write backups/provenance-backup-<UTC>.tar
|
||||
# BACKUP_RETAIN_DAYS=30 ./backup.sh # also prune bundles older than 30 days
|
||||
#
|
||||
# Run it from the host where `docker compose` manages the stack (i.e. this
|
||||
# deploy/ directory). Restore steps are in BACKUP.md.
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")" # the deploy/ directory (where docker-compose.yml lives)
|
||||
|
||||
# Config comes from the compose .env (same file the stack uses); fall back to
|
||||
# the compose defaults so a vanilla stack still backs up.
|
||||
if [ -f .env ]; then set -a; . ./.env; set +a; fi
|
||||
PGUSER="${POSTGRES_USER:-provenance}"
|
||||
PGDB="${POSTGRES_DB:-provenance}"
|
||||
|
||||
dc() { docker compose "$@"; }
|
||||
|
||||
ts="$(date -u +%Y%m%dT%H%M%SZ)"
|
||||
work="backups/.work-$ts"
|
||||
mkdir -p "$work" backups
|
||||
|
||||
cleanup() { rm -rf "$work"; }
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "→ Dumping Postgres database '$PGDB'…"
|
||||
dc exec -T postgres pg_dump -U "$PGUSER" -d "$PGDB" --no-owner --clean --if-exists \
|
||||
| gzip > "$work/db.sql.gz"
|
||||
|
||||
echo "→ Archiving MinIO object store…"
|
||||
# Tar MinIO's data directory straight from the container (objects + bucket
|
||||
# metadata). Restored by extracting back into the miniodata volume.
|
||||
dc exec -T minio tar czf - -C /data . > "$work/minio-data.tar.gz"
|
||||
|
||||
cat > "$work/MANIFEST.txt" <<EOF
|
||||
Provenance backup
|
||||
created: $ts
|
||||
database: $PGDB (pg_dump --clean --if-exists, gzip)
|
||||
objects: MinIO /data (tar.gz)
|
||||
restore: see deploy/BACKUP.md
|
||||
EOF
|
||||
|
||||
bundle="backups/provenance-backup-$ts.tar"
|
||||
# Contents are already gzipped, so the outer archive is a plain tar.
|
||||
tar cf "$bundle" -C "$work" db.sql.gz minio-data.tar.gz MANIFEST.txt
|
||||
|
||||
echo "✓ Backup written: $bundle ($(du -h "$bundle" | cut -f1))"
|
||||
|
||||
if [ -n "${BACKUP_RETAIN_DAYS:-}" ]; then
|
||||
echo "→ Pruning bundles older than ${BACKUP_RETAIN_DAYS} days…"
|
||||
find backups -maxdepth 1 -name 'provenance-backup-*.tar' -type f \
|
||||
-mtime "+${BACKUP_RETAIN_DAYS}" -print -delete
|
||||
fi
|
||||
Reference in New Issue
Block a user