chg: pkg: add backup/restore scripts #15
Deploy to Production / deploy (push) Successful in 3m26s

This commit is contained in:
Lang
2026-08-18 17:41:43 +02:00
parent 2be49ebdf1
commit 558c8a3bad
9 changed files with 758 additions and 547 deletions
+42
View File
@@ -0,0 +1,42 @@
#!/bin/sh
set -eu
PROJECT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
cd "$PROJECT_DIR"
CONTAINER_ID=$(docker compose ps -q minio)
if [ -z "$CONTAINER_ID" ]; then
echo "Error: The MineSeeker MinIO service is not running."
exit 1
fi
VOLUME_NAME=$(docker inspect "$CONTAINER_ID" --format '{{range .Mounts}}{{if eq .Destination "/data"}}{{.Name}}{{end}}{{end}}')
if [ -z "$VOLUME_NAME" ]; then
echo "Error: Could not determine the MinIO data volume."
exit 1
fi
BACKUP_DIR=${1:-"$PROJECT_DIR/backups"}
mkdir -p "$BACKUP_DIR"
BACKUP_DIR=$(CDPATH= cd -- "$BACKUP_DIR" && pwd)
TIMESTAMP=$(date +%Y-%m-%d.%H%M%S)
BACKUP_FILE="mineseeker-minio.${TIMESTAMP}.tar.gz"
BACKUP_PATH="$BACKUP_DIR/$BACKUP_FILE"
umask 077
restart_minio() {
docker compose start minio || echo "Warning: Failed to restart MinIO."
}
trap restart_minio EXIT
echo "Stopping MinIO for a consistent backup..."
docker compose stop minio
echo "Creating MinIO backup: $BACKUP_PATH"
docker run --rm \
--volume "$VOLUME_NAME:/data:ro" \
--volume "$BACKUP_DIR:/backup" \
busybox tar czf "/backup/$BACKUP_FILE" -C /data .
echo "Backup complete: $BACKUP_PATH"
+41
View File
@@ -0,0 +1,41 @@
#!/bin/sh
set -eu
PROJECT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
cd "$PROJECT_DIR"
CONTAINER_ID=$(docker compose ps -q db)
if [ -z "$CONTAINER_ID" ]; then
echo "Error: The MineSeeker PostgreSQL service is not running."
exit 1
fi
DB_USER=$(docker inspect "$CONTAINER_ID" --format '{{range .Config.Env}}{{println .}}{{end}}' | sed -n 's/^POSTGRES_USER=//p')
DB_NAME=$(docker inspect "$CONTAINER_ID" --format '{{range .Config.Env}}{{println .}}{{end}}' | sed -n 's/^POSTGRES_DB=//p')
if [ -z "$DB_USER" ] || [ -z "$DB_NAME" ]; then
echo "Error: Could not read PostgreSQL credentials from the db service."
exit 1
fi
BACKUP_DIR=${1:-"$PROJECT_DIR/backups"}
mkdir -p "$BACKUP_DIR"
BACKUP_DIR=$(CDPATH= cd -- "$BACKUP_DIR" && pwd)
TIMESTAMP=$(date +%Y-%m-%d.%H%M%S)
BACKUP_FILE="mineseeker-postgres.${TIMESTAMP}.dump"
BACKUP_PATH="$BACKUP_DIR/$BACKUP_FILE"
TEMP_PATH="$BACKUP_PATH.tmp"
umask 077
trap 'rm -f "$TEMP_PATH"' EXIT
echo "Creating PostgreSQL backup: $BACKUP_PATH"
docker exec "$CONTAINER_ID" pg_dump \
--username="$DB_USER" \
--format=custom \
--create \
"$DB_NAME" > "$TEMP_PATH"
mv "$TEMP_PATH" "$BACKUP_PATH"
trap - EXIT
echo "Backup complete: $BACKUP_PATH"
+61
View File
@@ -0,0 +1,61 @@
#!/bin/sh
set -eu
PROJECT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
cd "$PROJECT_DIR"
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <backup-file>"
echo "Example: $0 backups/mineseeker-minio.2026-08-18.120000.tar.gz"
exit 1
fi
BACKUP_FILE=$1
if [ ! -f "$BACKUP_FILE" ]; then
echo "Error: Backup file not found: $BACKUP_FILE"
exit 1
fi
BACKUP_DIR=$(CDPATH= cd -- "$(dirname -- "$BACKUP_FILE")" && pwd)
BACKUP_NAME=$(basename "$BACKUP_FILE")
CONTAINER_ID=$(docker compose ps -q minio)
if [ -z "$CONTAINER_ID" ]; then
echo "Error: The MineSeeker MinIO service is not running."
exit 1
fi
VOLUME_NAME=$(docker inspect "$CONTAINER_ID" --format '{{range .Mounts}}{{if eq .Destination "/data"}}{{.Name}}{{end}}{{end}}')
if [ -z "$VOLUME_NAME" ]; then
echo "Error: Could not determine the MinIO data volume."
exit 1
fi
echo "Verifying MinIO archive..."
docker run --rm \
--volume "$BACKUP_DIR:/backup:ro" \
busybox tar -tzf "/backup/$BACKUP_NAME" > /dev/null
echo "Archive OK."
printf 'WARNING: This erases all current MineSeeker MinIO data. Type yes to continue: '
read -r CONFIRM
if [ "$CONFIRM" != 'yes' ]; then
echo "Aborted."
exit 1
fi
restart_minio() {
docker compose start minio || echo "Warning: Failed to restart MinIO."
}
trap restart_minio EXIT
echo "Stopping MinIO before restore..."
docker compose stop minio
echo "Restoring MinIO backup: $BACKUP_FILE"
docker run --rm \
--volume "$VOLUME_NAME:/data" \
--volume "$BACKUP_DIR:/backup:ro" \
busybox sh -c 'find /data -mindepth 1 -maxdepth 1 -exec rm -rf {} + && tar xzf "/backup/$1" -C /data' sh "$BACKUP_NAME"
echo "Restore complete."
+65
View File
@@ -0,0 +1,65 @@
#!/bin/sh
set -eu
PROJECT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
cd "$PROJECT_DIR"
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <backup-file>"
echo "Example: $0 backups/mineseeker-postgres.2026-08-18.120000.dump"
exit 1
fi
BACKUP_FILE=$1
if [ ! -f "$BACKUP_FILE" ]; then
echo "Error: Backup file not found: $BACKUP_FILE"
exit 1
fi
CONTAINER_ID=$(docker compose ps -q db)
if [ -z "$CONTAINER_ID" ]; then
echo "Error: The MineSeeker PostgreSQL service is not running."
exit 1
fi
DB_USER=$(docker inspect "$CONTAINER_ID" --format '{{range .Config.Env}}{{println .}}{{end}}' | sed -n 's/^POSTGRES_USER=//p')
if [ -z "$DB_USER" ]; then
echo "Error: Could not read POSTGRES_USER from the db service."
exit 1
fi
echo "Verifying PostgreSQL archive..."
docker exec -i "$CONTAINER_ID" pg_restore --list < "$BACKUP_FILE" > /dev/null
echo "Archive OK."
printf 'WARNING: This replaces the current MineSeeker database. Type yes to continue: '
read -r CONFIRM
if [ "$CONFIRM" != 'yes' ]; then
echo "Aborted."
exit 1
fi
APP_WAS_RUNNING=0
SCHEDULER_WAS_RUNNING=0
[ -n "$(docker compose ps -q app)" ] && APP_WAS_RUNNING=1
[ -n "$(docker compose ps -q scheduler)" ] && SCHEDULER_WAS_RUNNING=1
restart_services() {
[ "$APP_WAS_RUNNING" -eq 1 ] && docker compose start app || true
[ "$SCHEDULER_WAS_RUNNING" -eq 1 ] && docker compose start scheduler || true
}
trap restart_services EXIT
echo "Stopping MineSeeker services that use PostgreSQL..."
docker compose stop app scheduler
echo "Restoring PostgreSQL backup: $BACKUP_FILE"
docker exec -i "$CONTAINER_ID" pg_restore \
--username="$DB_USER" \
--dbname=postgres \
--clean \
--create \
--if-exists \
--exit-on-error < "$BACKUP_FILE"
echo "Restore complete."