
作为 DBA,万一一场“你以为的备份”没有发生,就可能让业务在一秒内崩塌。怎样才能保证备份脚本一键跑起、有问题及时知晓、恢复流程随时可演练?这篇文章将从“备份策略”“脚本编写”到“恢复演练”三个知识节点,带你一步一步彻底搞定 MySQL 自动化备份与恢复。
在正式操作之前,我们先回顾一下整个环境里都有哪些组件,它们之间是什么关系,日常命令应该在什么地方执行。
服务器 | 容器名称 | MySQL 角色 | 职责与关系 | 命令执行环境 |
|---|---|---|---|---|
master | mysql-master | 主库 | 负责所有写操作并生成 binlog,用于从库同步。需要在备份脚本里从主库导出数据,然后把备份文件存到宿主机或远程存储。 | 在 master宿主机终端执行 Docker 相关命令,脚本也写在宿主机里,通过 docker exec进入容器执行 mysqldump。 |
node1 | mysql-node1 | 从库1 | 从主库实时读取 binlog,保持数据同步;一般只读。备份时可针对从库做逻辑备份(可选)。 | 在 node1宿主机终端执行 Docker 命令,若需要从容器里做恢复演练,可进入容器执行 mysql 命令。 |
node2 | mysql-node2 | 从库2 | 同上,从主库读取 binlog。 | 与 node1 相同。 |
docker exec mysql-master进入容器,调用 mysqldump导出数据。提示:后面所有涉及到
docker、mysqldump、gzip、tar、mysql等命令的操作,都分别在宿主机(安装 Docker、脚本存放地)或容器内(数据库操作)执行。文中会在每个命令块前标注“执行场景:xxx”。
如果随意把备份文件放在 /root、/home里,一旦磁盘满了或者误删,就会非常麻烦。
建议把所有脚本、备份文件都放在一个统一目录,比如:
/home/dba/backup-scripts # 脚本、日志
/home/dba/mysql-backups # 真正的备份数据存放
按照“每日一份”、“周全备”、“月全备” 的方式命名子目录:
/home/dba/mysql-backups/daily/YYYY-MM-DD/
/home/dba/mysql-backups/weekly/YYYY-MM-DD/
/home/dba/mysql-backups/monthly/YYYY-MM/
在 master 宿主机终端执行:
# 创建脚本存放目录
mkdir-p /home/dba/backup-scripts
# 创建备份文件统一存放目录
mkdir-p /home/dba/mysql-backups/{daily,weekly,monthly}
# 查看目录结构
ls-R /home/dba
bash: mkdir: 未找到命令,说明系统基础工具缺失,需要执行:
sudo yum install-y coreutils
sudo,或切换到 root用户再操作。创建日志目录和权限检查:
mkdir-p /home/dba/backup-scripts/logs
ls-ld /home/dba/backup-scripts /home/dba/mysql-backups
确保目录权限为 dba:dba用户组可读写,避免在脚本执行时因为写文件权限报错。
下面我们将一步步写一个脚本:backup_mysql_automation.sh,放在 /home/dba/backup-scripts/下,实现每日备份+压缩+清理旧备份功能。
执行场景:在 master 宿主机终端执行
cd /home/dba/backup-scripts
vim backup_mysql_automation.sh
提示:如果报 bash: vim: 未找到命令,可以先安装 vim或用更简单的 vi:
sudo yum install-yvim
或者:
vi backup_mysql_automation.sh
在 backup_mysql_automation.sh里,粘贴并写好以下内容,每行代码都加注释,方便小白理解。
#!/bin/bash
# ===========================================================================
# backup_mysql_automation.sh —— MySQL 自动化备份脚本
# 环境:AlmaLinux 8.x + Docker + MySQL (主库容器名称:mysql-master)
# 目标:每日凌晨2点做一次逻辑备份,保留7天的备份,按日期分类存放
# ===========================================================================
# —— 一、变量定义 ——
# 数据库容器名称(必须与实际容器名保持一致)
CONTAINER_NAME="mysql-master"
# 备份存放根目录(宿主机路径)
BACKUP_ROOT="/home/dba/mysql-backups"
# 日志目录,用于记录备份过程
LOG_DIR="/home/dba/backup-scripts/logs"
# 保留天数(超过此天数的备份自动删除)
RETENTION_DAYS=7
# 当前日期,用于生成目录和文件名
DATE=$(date +"%F")
TIME=$(date +"%H%M")
# 当天的备份目录,如 /home/dba/mysql-backups/daily/2025-06-10
TODAY_DIR="${BACKUP_ROOT}/daily/${DATE}"
# 备份文件名称,如 mysql_master_2025-06-10_0200.sql.gz
BACKUP_FILE="${TODAY_DIR}/mysql_master_${DATE}_${TIME}.sql.gz"
# 日志文件,如 /home/dba/backup-scripts/logs/backup_2025-06-10.log
LOG_FILE="${LOG_DIR}/backup_${DATE}.log"
# —— 二、命令检查 ——
# 确保宿主机上有 docker、gzip、tar 等命令,否则脚本无法正常执行
forcmdindockergziptar;do
command-v$cmd>/dev/null 2>&1
if[$?-ne0];then
echo"[ERROR] 未检测到命令:$cmd,请先安装后再运行脚本。"|tee-a"$LOG_FILE"
echo"[INFO] 安装命令示例:sudo yum install -y $cmd"|tee-a"$LOG_FILE"
exit1
fi
done
# —— 三、创建当天备份目录和日志目录 ——
mkdir-p"$TODAY_DIR"
if[$?-ne0];then
echo"[ERROR] 创建目录 $TODAY_DIR 失败,请检查权限。"|tee-a"$LOG_FILE"
exit1
fi
mkdir-p"$LOG_DIR"
if[$?-ne0];then
echo"[ERROR] 创建目录 $LOG_DIR 失败,请检查权限。"|tee-a"$LOG_FILE"
exit1
fi
# —— 四、备份开始 ——
echo"[$(date +"%F %T")] 开始备份 MySQL 主库 ($CONTAINER_NAME)"|tee-a"$LOG_FILE"
# 在宿主机上执行 docker exec 进入容器并调用 mysqldump,然后通过管道 gzip 压缩输出到备份文件
# 执行场景:宿主机终端
dockerexec$CONTAINER_NAME\
sh-c"mysqldump -uroot -p'你的密码' --all-databases --single-transaction --quick"\
|gzip>"$BACKUP_FILE"
# 检查备份是否成功
if[$?-eq0];then
echo"[$(date +"%F %T")] 备份成功:$BACKUP_FILE"|tee-a"$LOG_FILE"
else
echo"[$(date +"%F %T")] 备份失败"|tee-a"$LOG_FILE"
exit1
fi
# —— 五、清理过期备份 ——
echo"[$(date +"%F %T")] 开始清理 ${RETENTION_DAYS} 天前的备份"|tee-a"$LOG_FILE"
find"$BACKUP_ROOT/daily"-maxdepth1-type d -mtime +$RETENTION_DAYS\
-execrm-rf{}\;\
-print|tee-a"$LOG_FILE"
echo"[$(date +"%F %T")] 清理完成"|tee-a"$LOG_FILE"
# —— 六、结束 ——
echo"[$(date +"%F %T")] MySQL 备份脚本执行结束"|tee-a"$LOG_FILE"
exit0

命令检查:
command -v docker:判断宿主机是否安装 Docker。bash: docker: 未找到命令,执行:
sudo yum install-y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install-y docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
sudo systemctl enabledocker
gzip或 tar缺失,可执行 sudo yum install -y gzip tar。进入容器执行 mysqldump:
--single-transaction保证 InnoDB 表一致性备份;--quick减少内存占用;--single-transaction能避免锁表时间过长。docker exec $CONTAINER_NAME sh -c "mysqldump ...":mysqldump(极少见,因为官方镜像自带),进入容器后安装:
dockerexec-it mysql-master bash
# 在容器内部
yum install-y mysql
清理旧版本目录:
-mtime +7:找到 7 天前的目录;-maxdepth 1:只在一级子目录查找;-print:打印删除的目录路径,便于日志记录。find "$BACKUP_ROOT/daily" -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \;日志记录:
tee -a "$LOG_FILE"同时输出到终端和日志。兼容性与权限:
/home/dba/mysql-backups和 /home/dba/backup-scripts对 dba用户可读写,否则脚本执行时会报“Permission denied”。chown -R dba:dba /home/dba来设置权限。写完脚本后,还需让它 每天凌晨自动执行,否则“手动记得跑”就没用。这里我们用系统自带的 crontab来做。
执行场景:在 master 宿主机终端运行
# 检查 crond 服务状态
systemctl status crond
# 如果返回类似 “Unit crond.service could not be found” 或 inactive
sudo yum install-y cronie
sudo systemctl start crond
sudo systemctl enable crond
bash: systemctl: 未找到命令,说明没有安装或环境问题。先安装 systemd,一般操作系统自带,无需额外安装。若实在缺失,需联系系统管理员。
crontab-e
如果是第一次,会让你选择编辑器,推荐 vim或 nano。
在打开的编辑器里添加一行(示例:每天凌晨 2:00 执行):
0 2 * * * /home/dba/backup-scripts/backup_mysql_automation.sh >> /home/dba/backup-scripts/logs/cron_backup.log 2>&1
0 2 * * *:表示每天 02:00>> /home/dba/backup-scripts/logs/cron_backup.log 2>&1:把脚本所有输出(含错误)追加到 cron_backup.log,便于后续排查保存退出 (:wq),然后执行:
crontab-l
确认输出里包含刚才添加的任务。
注意:如果执行 crontab -e报错 bash: crontab: 未找到命令,则需要安装 cronie:
sudo yum install-y cronie
sudo systemctl start crond
sudo systemctl enable crond
备份如果没有经过恢复演练,就相当于“没有备份”。下面演示如何把一个备份文件恢复到一个新容器或现有容器,确保流程可行。
执行场景:master 宿主机终端执行
# 下载并运行一个临时测试容器(与生产环境隔离)
docker run -d\
--name mysql-test \
-eMYSQL_ROOT_PASSWORD=testpwd \
-p3307:3306 \
mysql:8.0
# 等待容器启动
sleep10
# 检查容器状态
dockerps|grep mysql-test
bash: docker: 未找到命令,参考上文命令安装 Docker。假设最新的备份目录是 /home/dba/mysql-backups/daily/2025-06-10,文件名是 mysql_master_2025-06-10_0200.sql.gz。
# 为方便操作,把备份文件复制到一个统一的 restore 目录
mkdir-p /home/dba/restore-test
cp /home/dba/mysql-backups/daily/2025-06-10/mysql_master_2025-06-10_0200.sql.gz /home/dba/restore-test/
进入容器
dockerexec-it mysql-test bash
容器内安装必要工具(如果缺少)
# 确保容器里有 gzip 和 mysql 客户端
command-vgzip>/dev/null 2>&1|| yum install-ygzip
command-v mysql >/dev/null 2>&1|| yum install-y mysql
yum: 未找到命令,说明基础镜像可能是非 yum 系统或缺少 repos。一般官方 mysql:8.0 镜像自带了基本工具,无需额外安装。若出现问题,可跳过,直接在宿主机解压后复制到容器再导入。在容器内创建一个目录用于放置备份文件
mkdir-p /tmp/restore/
把宿主机的备份文件拷贝到容器内退出容器(exit),然后在宿主机执行:
dockercp /home/dba/restore-test/mysql_master_2025-06-10_0200.sql.gz mysql-test:/tmp/restore/
bash: docker: 未找到命令,同样先安装 Docker。再次进入容器
dockerexec-it mysql-test bash
解压并导入备份文件
cd /tmp/restore
# 解压文件
gzip-d mysql_master_2025-06-10_0200.sql.gz
# 解压后的文件名默认为 mysql_master_2025-06-10_0200.sql
# 导入到 MySQL
mysql -uroot -p'testpwd'< mysql_master_2025-06-10_0200.sql
# 如果导入成功,终端无报错
bash: gzip: 未找到命令,在容器内执行:
yum install-ygzip
bash: mysql: 未找到命令,在容器内执行:
yum install-y mysql
在同一个容器内执行 MySQL 客户端:
mysql -uroot -p'testpwd'
# 进入后查看数据库列表
SHOW DATABASES;
# 进入某个业务数据库,比如 testdb
USE testdb;
SHOW TABLES;
# 随便查一条数据
SELECT * FROM users LIMIT 5;
如果能看到期望的表和数据,说明恢复成功。
如果需要把备份恢复到现有从库(谨慎操作,建议先停止从库同步后再恢复):
停止从库容器里的 MySQL 服务
dockerexec-it mysql-node1 bash
mysql -uroot-p# 进入 MySQL
STOP SLAVE;# 停止复制线程
exit# 退出 MySQL
exit# 退出容器 shell
在宿主机停止容器
docker stop mysql-node1
清空容器内旧数据(注意:此操作会删除所有数据,请务必先备份)
# 删除容器内部数据文件夹(示例路径,具体视挂载情况而定)
dockerexec-it mysql-node1 bash
rm-rf /var/lib/mysql/*
exit
把备份导入到从库容器
/tmp/restore/dockerexec-it mysql-node1 bash
cd /tmp/restore
gzip-d mysql_master_2025-06-10_0200.sql.gz
mysql -uroot -p'yourpassword'< mysql_master_2025-06-10_0200.sql
重设主从复制位置
dockerexec-it mysql-node1 bash
mysql -uroot-p
RESET SLAVE;# 清空 relay log 等
CHANGE MASTER TO
MASTER_HOST='主库IP',
MASTER_USER='repl',
MASTER_PASSWORD='repl_password',
MASTER_LOG_FILE='mysql-bin.000005', # 需要根据 master 最新的 binlog 文件名
MASTER_LOG_POS=120;# 根据 SHOW MASTER STATUS 输出
START SLAVE;
SHOW SLAVE STATUS\G # 确认 Slave_IO_Running 和 Slave_SQL_Running 都是 Yes
exit
exit
重启从库容器
docker start mysql-node1
验证主从同步是否恢复
dockerexec-it mysql-node1 bash
mysql -uroot-p-e"SHOW SLAVE STATUS\G"
如果两项都正常,说明恢复到从库也成功了。
原因:宿主机未安装 Docker。
解决:
sudo yum install-y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install-y docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
sudo systemctl enabledocker
完成后执行 docker version,确认安装成功。
原因:尝试在宿主机上直接运行 mysqldump,但它在容器内。
解决方案:
docker exec mysql-master mysqldump ...sudo yum install-y mysql
mysqldump -h 主库IP -P3306-uroot -p'yourpassword' --all-databases > backup.sql
原因:脚本里用了 gzip或 tar,但系统没有安装。
解决:
sudo yum install-ygziptar
mysql命令恢复。-p'你的密码'是否正确;