minecraft: add hourly world backup CronJob with 3-day local retention
This commit is contained in:
117
cluster/applications/minecraft/backup-cronjob.yaml
Normal file
117
cluster/applications/minecraft/backup-cronjob.yaml
Normal 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
|
||||
19
cluster/applications/minecraft/backup-pvc.yaml
Normal file
19
cluster/applications/minecraft/backup-pvc.yaml
Normal 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
|
||||
Reference in New Issue
Block a user