disaster-backup: Minecraft flush-not-stop, update descriptions
Minecraft instances are flushed to disk (save-all) and snapshotted while the server keeps running — no player disruption. All other services stop briefly for filesystem-consistent database snapshots, then restart. Also update file header, install banner, schedule description, and README. https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
This commit is contained in:
@@ -72,7 +72,7 @@ Update them any time with `sudo ./setup.sh configure`.
|
||||
| `cameras` | `frigate`, `frigate-audio`, `frigate-notify`, `sky-cam` |
|
||||
| `gaming` | `js99er`, `minecraft`, `wolf`, `wolf-pair` |
|
||||
| `extras` | `silent-send`, `sync-cc` |
|
||||
| `backup` | `backup` — Kopia (game saves/world data, no service downtime); `disaster-backup` — full `~/docker/<service>/` dirs (stop/snap/start, databases included) |
|
||||
| `backup` | `backup` — Kopia (Minecraft world data + gaming saves, runs without stopping services); `disaster-backup` — complete recovery backup: entire `~/docker/<service>/` for every service (Minecraft: flush+snap, no downtime; all others: stop/snap/start for DB consistency) |
|
||||
|
||||
Run `./setup.sh --list` to see descriptions.
|
||||
|
||||
|
||||
+57
-31
@@ -1,17 +1,19 @@
|
||||
#!/bin/bash
|
||||
# services/disaster-backup.sh — Full Docker-service disaster-recovery backups.
|
||||
# services/disaster-backup.sh — Complete disaster-recovery backup via Kopia.
|
||||
# Part of the modular post-install system (sourced by setup.sh).
|
||||
#
|
||||
# Backs up entire ~/docker/<service>/ directories (stop → snapshot → start)
|
||||
# with Kopia. Different services can go to different drives / Kopia repos.
|
||||
# Backs up each entire ~/docker/<service>/ directory (compose file, config, data,
|
||||
# databases — everything needed to restore from nothing). Per-service behaviour:
|
||||
# Minecraft instances — flush world to disk (save-all), snapshot, no downtime
|
||||
# All other services — stop, snapshot, restart (seconds of downtime each)
|
||||
#
|
||||
# Different services can be routed to different Kopia repos / drives.
|
||||
# New services are auto-discovered on every run — no reconfiguration needed.
|
||||
#
|
||||
# Creates: ~/docker/disaster-backup/
|
||||
# disaster-backup.conf settings + per-service destination map
|
||||
# disaster-backup.sh worker (run directly or via systemd timer)
|
||||
# restore/<dest>/ restore_kopia_backup.sh + backup.conf per destination
|
||||
#
|
||||
# Complementary to the 'backup' service (gaming saves). This one is the
|
||||
# comprehensive "restore entire service from scratch" solution.
|
||||
|
||||
register_service disaster-backup backup "Disaster-recovery backup (full ~/docker service dirs, stop/start)"
|
||||
|
||||
@@ -31,13 +33,14 @@ install_disaster_backup() {
|
||||
echo "║ Full ~/docker/<service>/ snapshots via Kopia ║"
|
||||
echo "╚═══════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo " Backs up each entire service directory — config, data, databases,"
|
||||
echo " compose files, everything needed to restore a service from scratch."
|
||||
echo " Each service is stopped briefly before snapshotting, then restarted,"
|
||||
echo " ensuring consistent database state."
|
||||
echo " Backs up each entire service directory — compose file, config, data,"
|
||||
echo " databases, everything needed to restore a service from scratch."
|
||||
echo ""
|
||||
echo " Minecraft: world flushed to disk (save-all), snapshot, NO downtime."
|
||||
echo " Everything else: stopped briefly, snapshotted, restarted."
|
||||
echo ""
|
||||
echo " Different services can go to different drives / Kopia repos."
|
||||
echo " New services installed later are auto-detected on the next backup run."
|
||||
echo " New services are auto-detected on every run — no reconfiguration needed."
|
||||
echo ""
|
||||
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
@@ -167,7 +170,8 @@ install_disaster_backup() {
|
||||
echo " SCHEDULE & RETENTION"
|
||||
echo "═══════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
echo " Services are stopped briefly per snapshot — schedule for off-peak hours."
|
||||
echo " Minecraft runs uninterrupted; other services stop briefly (seconds each)."
|
||||
echo " Schedule for off-peak hours."
|
||||
echo ""
|
||||
echo " 1) Daily at 02:00 (recommended)"
|
||||
echo " 2) Every 12 hours"
|
||||
@@ -271,7 +275,9 @@ install_disaster_backup() {
|
||||
cat > "$WORKER" << 'WORKEREOF'
|
||||
#!/bin/bash
|
||||
# Generated by the disaster-backup installer.
|
||||
# Backs up full ~/docker/<service>/ directories via Kopia (stop → snap → start).
|
||||
# Backs up full ~/docker/<service>/ directories via Kopia.
|
||||
# Minecraft instances: flush to disk (save-all) then snapshot — no downtime.
|
||||
# All other services: stop → snapshot → restart for consistency.
|
||||
#
|
||||
# sudo ./disaster-backup.sh run a full backup cycle
|
||||
# sudo ./disaster-backup.sh snapshots list all snapshots (all repos)
|
||||
@@ -305,6 +311,9 @@ dest_for_svc() {
|
||||
echo "${!var:-${DEST_DEFAULT:-default}}"
|
||||
}
|
||||
|
||||
# Detect itzg Minecraft instances by their Dockerfile signature.
|
||||
is_minecraft() { [ -f "${1}Dockerfile" ] && grep -qs itzg "${1}Dockerfile"; }
|
||||
|
||||
case "${1:-run}" in
|
||||
snapshots)
|
||||
for dest in ${DEST_NAMES:-default}; do
|
||||
@@ -332,26 +341,43 @@ for svc_dir in "$DOCKER_DIR"/*/; do
|
||||
_repo_var="DEST_${dest}_REPO"
|
||||
[ -n "${!_repo_var:-}" ] || { log "SKIP $svc — dest '$dest' not configured in conf"; continue; }
|
||||
|
||||
STOPPED=false
|
||||
if docker ps --format '{{.Names}}' 2>/dev/null | grep -qx "$svc"; then
|
||||
log "Stopping $svc..."
|
||||
docker compose -f "${svc_dir}docker-compose.yml" down 2>/dev/null \
|
||||
|| docker stop "$svc" 2>/dev/null \
|
||||
|| log "WARNING: could not stop $svc — snapshotting live (consistency not guaranteed)"
|
||||
STOPPED=true
|
||||
fi
|
||||
|
||||
log "Snapshotting $svc (dest: $dest)..."
|
||||
if kp_for "$dest" snapshot create --description="disaster: $svc" "$svc_dir"; then
|
||||
log "OK $svc"
|
||||
if is_minecraft "$svc_dir"; then
|
||||
# ── Minecraft: flush world to disk, snapshot without stopping ────────
|
||||
if docker ps --format '{{.Names}}' 2>/dev/null | grep -qx "$svc"; then
|
||||
log "Flushing Minecraft world '$svc' (save-all, no downtime)..."
|
||||
docker exec "$svc" mc-send-to-console save-all flush 2>/dev/null \
|
||||
|| docker exec "$svc" rcon-cli save-all 2>/dev/null || true
|
||||
sleep 5
|
||||
fi
|
||||
log "Snapshotting $svc (dest: $dest)..."
|
||||
if kp_for "$dest" snapshot create --description="disaster: $svc" "$svc_dir"; then
|
||||
log "OK $svc (Minecraft, no downtime)"
|
||||
else
|
||||
log "WARNING: snapshot failed for $svc"; rc=1
|
||||
fi
|
||||
else
|
||||
log "WARNING: snapshot failed for $svc"; rc=1
|
||||
fi
|
||||
# ── All other services: stop → snapshot → restart ─────────────────
|
||||
STOPPED=false
|
||||
if docker ps --format '{{.Names}}' 2>/dev/null | grep -qx "$svc"; then
|
||||
log "Stopping $svc..."
|
||||
docker compose -f "${svc_dir}docker-compose.yml" down 2>/dev/null \
|
||||
|| docker stop "$svc" 2>/dev/null \
|
||||
|| log "WARNING: could not stop $svc — snapshotting live (consistency not guaranteed)"
|
||||
STOPPED=true
|
||||
fi
|
||||
|
||||
if [ "$STOPPED" = true ]; then
|
||||
log "Starting $svc..."
|
||||
docker compose -f "${svc_dir}docker-compose.yml" up -d 2>/dev/null \
|
||||
|| log "WARNING: could not restart $svc — start it manually: docker compose -f ${svc_dir}docker-compose.yml up -d"
|
||||
log "Snapshotting $svc (dest: $dest)..."
|
||||
if kp_for "$dest" snapshot create --description="disaster: $svc" "$svc_dir"; then
|
||||
log "OK $svc"
|
||||
else
|
||||
log "WARNING: snapshot failed for $svc"; rc=1
|
||||
fi
|
||||
|
||||
if [ "$STOPPED" = true ]; then
|
||||
log "Starting $svc..."
|
||||
docker compose -f "${svc_dir}docker-compose.yml" up -d 2>/dev/null \
|
||||
|| log "WARNING: could not restart $svc — run: docker compose -f ${svc_dir}docker-compose.yml up -d"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
Reference in New Issue
Block a user