106 lines
2.9 KiB
Bash
106 lines
2.9 KiB
Bash
#!/bin/bash
|
||
|
||
# Memory 数据库备份脚本
|
||
# 功能:备份 SQLite 数据库到 R2,保留最近 7 天的备份
|
||
|
||
set -e
|
||
|
||
# ============ 配置区域 ============
|
||
# R2 配置
|
||
R2_ACCOUNT_ID="ebf33b5ee4eb26f32af0c6e06102e000"
|
||
R2_ACCESS_KEY_ID="8acbc8a9386d60d0e8dac6bd8165c618"
|
||
R2_ACCESS_KEY_SECRET="72935e23b5b4be8fda99008e75285e8ac778f8926656c42780b25785bb149443"
|
||
R2_BUCKET_NAME="memory"
|
||
R2_BACKUP_PATH="memory-backup"
|
||
|
||
# 数据库路径
|
||
DB_PATH="/amos/memory/data/memory.db"
|
||
|
||
# 备份保留天数
|
||
KEEP_DAYS=7
|
||
|
||
# 日志文件
|
||
LOG_FILE="/var/log/memory-backup.log"
|
||
|
||
# ============ 函数定义 ============
|
||
|
||
log() {
|
||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
|
||
}
|
||
|
||
# 上传备份到 R2
|
||
upload_backup() {
|
||
local backup_file=$1
|
||
local remote_name=$2
|
||
|
||
AWS_ACCESS_KEY_ID=$R2_ACCESS_KEY_ID \
|
||
AWS_SECRET_ACCESS_KEY=$R2_ACCESS_KEY_SECRET \
|
||
aws s3 cp "$backup_file" "s3://${R2_BUCKET_NAME}/${R2_BACKUP_PATH}/${remote_name}" \
|
||
--endpoint-url "https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com"
|
||
}
|
||
|
||
# 清理旧备份,只保留最近 N 天
|
||
cleanup_old_backups() {
|
||
log "清理旧备份..."
|
||
|
||
# 列出所有备份文件,按时间倒序排列
|
||
local backup_list=$(AWS_ACCESS_KEY_ID=$R2_ACCESS_KEY_ID \
|
||
AWS_SECRET_ACCESS_KEY=$R2_ACCESS_KEY_SECRET \
|
||
aws s3 ls "s3://${R2_BUCKET_NAME}/${R2_BACKUP_PATH}/" \
|
||
--endpoint-url "https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com" \
|
||
| grep "memory-.*\.db" \
|
||
| sort -r \
|
||
| awk '{print $4}')
|
||
|
||
# 跳过前 N 个(最新的),删除其余的
|
||
local count=0
|
||
for backup in $backup_list; do
|
||
count=$((count + 1))
|
||
if [ $count -gt $KEEP_DAYS ]; then
|
||
log " 删除: $backup"
|
||
AWS_ACCESS_KEY_ID=$R2_ACCESS_KEY_ID \
|
||
AWS_SECRET_ACCESS_KEY=$R2_ACCESS_KEY_SECRET \
|
||
aws s3 rm "s3://${R2_BUCKET_NAME}/${R2_BACKUP_PATH}/${backup}" \
|
||
--endpoint-url "https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com"
|
||
fi
|
||
done
|
||
|
||
if [ $count -le $KEEP_DAYS ]; then
|
||
log " 无需清理,当前共 ${count} 个备份"
|
||
else
|
||
log " 已清理 $((count - KEEP_DAYS)) 个旧备份"
|
||
fi
|
||
}
|
||
|
||
# ============ 主流程 ============
|
||
|
||
log "========== 开始备份 =========="
|
||
|
||
# 检查数据库文件是否存在
|
||
if [ ! -f "$DB_PATH" ]; then
|
||
log "❌ 数据库文件不存在: $DB_PATH"
|
||
exit 1
|
||
fi
|
||
|
||
# 生成备份文件名(带日期)
|
||
DATE=$(date '+%Y-%m-%d')
|
||
BACKUP_NAME="memory-${DATE}.db"
|
||
TEMP_BACKUP="/tmp/${BACKUP_NAME}"
|
||
|
||
# 使用 sqlite3 的 .backup 命令进行热备份(避免数据损坏)
|
||
log "备份数据库..."
|
||
sqlite3 "$DB_PATH" ".backup '$TEMP_BACKUP'"
|
||
|
||
# 上传到 R2
|
||
log "上传到 R2..."
|
||
upload_backup "$TEMP_BACKUP" "$BACKUP_NAME"
|
||
|
||
# 清理临时文件
|
||
rm -f "$TEMP_BACKUP"
|
||
|
||
# 清理旧备份
|
||
cleanup_old_backups
|
||
|
||
log "✅ 备份完成: ${BACKUP_NAME}"
|
||
log "========== 备份结束 =========="
|