在容器中运行的mysql数据库定时备份脚本

单次备份直接跑:

1
docker exec -it mysql容器名/id mysqldump --all-databases -u用户 -p > ./mysql-backup/backup_$(date +%Y%m%d_%H%M).sql

命令行提示输入密码

注意使用--all-databases会连 mysql 本身内部数据库也导出。

批量定时让 AI 写了个脚本,改了几个版本,测试过没啥太大问题。

不过这个版本会把密码留在命令行里,我这里是单独建了个 localhost 能用的密码,不放心可以写临时文件/放环境变量等方法。

会创建当前时间的文件夹,里面按照每个数据库存放对应名字的 sql,设置了过期时间。

这个只能针对比较小的数据库备份,几 G 的无所谓,几十 G 上百 G 的就很慢了(这种业务量还是买云上的数据库吧)。

定时部分直接用 crontab 调这个脚本就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/bin/bash

# =================================================================
# Docker MySQL 数据库备份脚本
# - 为每次备份创建独立的、带时间戳的文件夹
# - 备份为纯 .sql 文件,不压缩
# - 仅在所有备份成功后,才清理旧的备份文件夹
# - 清理前,在日志中一次性记录所有将被删除的目录列表
# =================================================================

# --- 自定义配置 ---

# MySQL 容器名称
CONTAINER_NAME="your_mysql_container_name"

# MySQL 用户名 (推荐使用下面创建的 'backup' 用户)
MYSQL_USER="backup"

# MySQL 密码 (您为 'backup' 用户设置的密码)
MYSQL_PASSWORD="your_strong_password_here"

# 需要备份的数据库列表,多个数据库用空格隔开
# 例如: "db1 db2 db3"
DATABASE_NAMES="your_db_name1 your_db_name2"

# 备份文件存放的根目录
BACKUP_ROOT_DIR="/data/mysql_backups"

# 备份文件保留天数
RETENTION_DAYS=30

# 日志文件路径
LOG_FILE="${BACKUP_ROOT_DIR}/backup.log"

# --- 脚本主体 ---

# 1. 创建本次备份的专属文件夹
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
CURRENT_BACKUP_DIR="${BACKUP_ROOT_DIR}/${TIMESTAMP}"
mkdir -p ${CURRENT_BACKUP_DIR}

# --- 函数定义 ---
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> ${LOG_FILE}
}

# 2. 执行备份
log "开始备份任务,备份至目录: ${CURRENT_BACKUP_DIR}"
if [ -z "${DATABASE_NAMES}" ]; then
log "错误: 没有指定要备份的数据库 (DATABASE_NAMES 为空)。"
exit 1
fi

ALL_BACKUPS_SUCCEEDED=true
for DB_NAME in ${DATABASE_NAMES}
do
log "正在备份数据库: ${DB_NAME}"
BACKUP_FILE="${CURRENT_BACKUP_DIR}/${DB_NAME}.sql"
docker exec ${CONTAINER_NAME} /usr/bin/mysqldump -u${MYSQL_USER} -p${MYSQL_PASSWORD} --databases ${DB_NAME} --single-transaction > ${BACKUP_FILE}
if [ $? -eq 0 ]; then
log "数据库 ${DB_NAME} 备份成功, 文件: ${BACKUP_FILE}"
else
log "错误: 数据库 ${DB_NAME} 备份失败。"
ALL_BACKUPS_SUCCEEDED=false
rm -f ${BACKUP_FILE}
fi
done
log "所有数据库备份操作执行完毕"

# 3. 清理旧备份 (仅在所有备份都成功时执行)
if [ "${ALL_BACKUPS_SUCCEEDED}" = true ]; then
log "本次所有备份任务均成功,开始清理 ${RETENTION_DAYS} 天前的旧备份文件夹"

# --- 这里是修改的核心部分 ---
# 先找到所有要删除的目录,存入变量
DIRS_TO_DELETE=$(find ${BACKUP_ROOT_DIR} -type d -name "20[0-9][0-9]*_*" -mtime +${RETENTION_DAYS})

if [ -n "${DIRS_TO_DELETE}" ]; then
# 如果找到了需要删除的目录,则先记录日志,然后执行删除
log "将要删除以下旧备份目录:"
log "${DIRS_TO_DELETE}"
# 使用 xargs 来处理目录列表并删除
echo "${DIRS_TO_DELETE}" | xargs rm -rf
log "旧备份文件夹清理完成"
else
# 如果没有找到,也记录一下
log "没有找到需要清理的旧备份目录。"
fi
else
log "警告: 本次备份任务中存在失败项,将跳过清理旧备份的操作以确保数据安全。"
log "由于备份失败,本次创建的文件夹 ${CURRENT_BACKUP_DIR} 可能包含不完整的备份。"
fi

log "=========================================================="