minecraft: add hourly world backup CronJob with 3-day local retention

This commit is contained in:
Hermes Agent service account
2026-07-19 17:48:53 -05:00
parent 4cde540e70
commit 1aa6b4234a
2 changed files with 136 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
---
# Minecraft world backup — hourly CronJob, 3-day local retention
#
# Strategy (two-tier):
# Short-term : this CronJob — hourly tarballs on papermc-backups PVC, 72-hour retention
# Long-term : Pure FlashArray protection group snapshots on utilidor (managed separately)
#
# Backup sequence:
# 1. RCON save-all — flush all dirty chunks to disk
# 2. RCON save-off — pause auto-save to keep the world consistent during tar
# 3. tar world directories to /backups/world-YYYY-MM-DDTHH-MM.tar.gz
# 4. RCON save-on — re-enable auto-save
# 5. Prune backups older than 3 days
#
# RCON password sourced from the papermc-rcon Secret (ESO-managed, same as server).
# The backup pod mounts both PVCs read-write; world-data is safe because the
# server has already quiesced saves via RCON before the tar runs.
#
# Note: both PVCs are RWO. The backup job runs only while the main server pod is
# running (RCON is reachable), so there is no volume attach conflict — they are
# mounted on the same node by the scheduler. If the server pod is down, the backup
# job will fail at the RCON step, which is correct behavior (nothing to back up).
apiVersion: batch/v1
kind: CronJob
metadata:
name: minecraft-backup
namespace: minecraft
labels:
app.kubernetes.io/name: minecraft
app.kubernetes.io/component: backup
spec:
schedule: "0 * * * *" # every hour on the hour
concurrencyPolicy: Forbid # skip if a previous backup is still running
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
backoffLimit: 0 # don't retry — a partial backup is worse than no backup
template:
metadata:
labels:
app.kubernetes.io/name: minecraft
app.kubernetes.io/component: backup
spec:
restartPolicy: Never
securityContext:
runAsNonRoot: false
fsGroup: 1000
containers:
- name: backup
image: itzg/rcon-cli:latest
imagePullPolicy: IfNotPresent
env:
- name: RCON_HOST
value: "journey-into-imagination.minecraft.svc.cluster.local"
- name: RCON_PORT
value: "25575"
- name: RCON_PASSWORD
valueFrom:
secretKeyRef:
name: papermc-rcon
key: rcon-password
command:
- /bin/sh
- -c
- |
set -e
TIMESTAMP=$(date -u +%Y-%m-%dT%H-%M)
BACKUP_FILE="/backups/world-${TIMESTAMP}.tar.gz"
RETAIN_DAYS=3
echo "[backup] Starting backup at ${TIMESTAMP}"
# Step 1: quiesce the world
echo "[backup] Flushing chunks (save-all)..."
rcon-cli save-all
echo "[backup] Pausing auto-save (save-off)..."
rcon-cli save-off
# Step 2: archive world directories
echo "[backup] Archiving world to ${BACKUP_FILE}..."
tar -czf "${BACKUP_FILE}" \
-C /data \
world \
world_nether \
world_the_end \
whitelist.json \
ops.json \
banned-players.json \
banned-ips.json
echo "[backup] Archive complete: $(du -sh ${BACKUP_FILE} | cut -f1)"
# Step 3: resume auto-save
echo "[backup] Resuming auto-save (save-on)..."
rcon-cli save-on
# Step 4: prune old backups
echo "[backup] Pruning backups older than ${RETAIN_DAYS} days..."
find /backups -name "world-*.tar.gz" -mtime +${RETAIN_DAYS} -delete
REMAINING=$(find /backups -name "world-*.tar.gz" | wc -l)
echo "[backup] Done. ${REMAINING} backup(s) retained."
volumeMounts:
- name: world-data
mountPath: /data
readOnly: true
- name: backups
mountPath: /backups
volumes:
- name: world-data
persistentVolumeClaim:
claimName: papermc-world-data
- name: backups
persistentVolumeClaim:
claimName: papermc-backups

View File

@@ -0,0 +1,19 @@
---
# Minecraft backup storage — local hourly backups, 3-day retention
# Sized for ~72 backup tarballs; world data compresses well (~90% reduction typical)
# Long-term retention handled by Pure FlashArray protection group snapshots (utilidor)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: papermc-backups
namespace: minecraft
labels:
app.kubernetes.io/name: minecraft
app.kubernetes.io/component: backup
spec:
accessModes:
- ReadWriteOnce
storageClassName: px-fa-direct-access
resources:
requests:
storage: 10Gi