feat: 每日自动备份数据库到 MinIO
- CronJob: daily-minio-backup, 每天 UTC 3:00 执行 - 备份 SQLite DB 到 minio-api.oci.euphon.net/oil-backups/ - 文件名: oil_calculator_YYYYMMDD.db - 滚动保留最近 30 份,自动删除旧备份 - 使用 Python minio SDK 上传 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
96
deploy/minio-backup-cronjob.yaml
Normal file
96
deploy/minio-backup-cronjob.yaml
Normal file
@@ -0,0 +1,96 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: minio-backup-creds
|
||||
namespace: oil-calculator
|
||||
type: Opaque
|
||||
stringData:
|
||||
MINIO_ALIAS: "oci"
|
||||
MINIO_URL: "https://minio-api.oci.euphon.net"
|
||||
MINIO_ACCESS_KEY: "admin"
|
||||
MINIO_SECRET_KEY: "HpYMIVH0WN79VkzF4L4z8Zx1"
|
||||
MINIO_BUCKET: "oil-backups"
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: daily-minio-backup
|
||||
namespace: oil-calculator
|
||||
spec:
|
||||
schedule: "0 3 * * *" # Daily at 3:00 UTC
|
||||
successfulJobsHistoryLimit: 3
|
||||
failedJobsHistoryLimit: 2
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: backup
|
||||
image: registry.oci.euphon.net/oil-calculator:latest
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
set -e
|
||||
DATE=$(date +%Y%m%d)
|
||||
export BACKUP_FILE="oil_calculator_${DATE}.db"
|
||||
|
||||
echo "=== Oil Calculator Daily Backup ==="
|
||||
echo "Date: ${DATE}"
|
||||
|
||||
# 1. Copy SQLite database (app does WAL checkpoint every 5min)
|
||||
cp /data/oil_calculator.db /tmp/${BACKUP_FILE}
|
||||
SIZE=$(du -h /tmp/${BACKUP_FILE} | cut -f1)
|
||||
echo "Backup created: ${BACKUP_FILE} (${SIZE})"
|
||||
|
||||
# 2. Upload to minio and cleanup using Python minio SDK
|
||||
pip install -q minio 2>/dev/null
|
||||
cat > /tmp/upload_backup.py << 'PYEOF'
|
||||
import os
|
||||
from minio import Minio
|
||||
url = os.environ['MINIO_URL'].replace('https://','').replace('http://','')
|
||||
client = Minio(url, access_key=os.environ['MINIO_ACCESS_KEY'], secret_key=os.environ['MINIO_SECRET_KEY'], secure='https' in os.environ['MINIO_URL'])
|
||||
bucket = os.environ['MINIO_BUCKET']
|
||||
bf = os.environ['BACKUP_FILE']
|
||||
client.fput_object(bucket, bf, '/tmp/' + bf)
|
||||
print('Uploaded:', bf)
|
||||
objs = sorted(client.list_objects(bucket, prefix='oil_calculator_'), key=lambda o: o.object_name, reverse=True)
|
||||
for o in objs[30:]:
|
||||
client.remove_object(bucket, o.object_name)
|
||||
print('Deleted:', o.object_name)
|
||||
print('Total backups:', min(len(objs), 30))
|
||||
PYEOF
|
||||
python3 /tmp/upload_backup.py
|
||||
echo "=== Done ==="
|
||||
env:
|
||||
- name: MINIO_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: minio-backup-creds
|
||||
key: MINIO_URL
|
||||
- name: MINIO_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: minio-backup-creds
|
||||
key: MINIO_ACCESS_KEY
|
||||
- name: MINIO_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: minio-backup-creds
|
||||
key: MINIO_SECRET_KEY
|
||||
- name: MINIO_BUCKET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: minio-backup-creds
|
||||
key: MINIO_BUCKET
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: oil-calculator-data
|
||||
restartPolicy: OnFailure
|
||||
imagePullSecrets:
|
||||
- name: regcred
|
||||
Reference in New Issue
Block a user