Docker MySQL 自动备份与恢复教程(systemd 定时任务)
2026/6/27 2:58:57 网站建设 项目流程

Docker MySQL 自动备份与恢复教程(systemd 定时任务)

本文介绍如何为 Docker 中运行的 MySQL 数据库建立自动备份方案:

  • 使用mysqldump导出数据库;
  • 自动压缩为.sql.gz
  • 每 5 天备份一次;
  • 自动保留最近 30 天的备份;
  • 使用systemd timer设置开机自动启用;
  • 提供完整的数据库恢复流程。

本文统一使用MyProject作为示例项目代号。实际使用时,只需要替换项目名称、容器名、数据库名、密码和目录即可。


1. 需要替换的配置

请根据自己的服务器环境修改以下名称:

示例名称说明
MyProject项目名称或项目代号
myproject项目名称的小写形式
myproject-mysqlMySQL Docker 容器名称
myproject-backend后端 Docker 容器名称
myproject123456MySQL root 密码
/root/MyProject_Backup/mysql备份保存目录
/root/backup_myproject_mysql.sh自动备份脚本路径

先查看正在运行的 Docker 容器:

dockerps--format"table {{.Names}}\t{{.Status}}"

输出示例:

NAMES STATUS myproject-mysql Up 10 days myproject-backend Up 10 days

2. 为什么不要直接复制 MySQL 数据目录

MySQL 数据通常挂载在宿主机目录中,例如:

/root/MyProject_Web/data/mysql/

不要在 MySQL 正在运行时直接复制这个目录:

cp-a/root/MyProject_Web/data/mysql /root/mysql_backup

因为 MySQL 在运行过程中会持续写入表数据、日志和索引文件。直接复制可能产生不一致的数据副本,恢复时可能失败。

更可靠的方法是使用:

mysqldump

将数据库导出为 SQL 文件,再压缩为:

.sql.gz

这种备份方式可以在 MySQL 正常运行时执行,且更容易迁移、检查和恢复。


3. 创建独立备份目录

建议将备份保存在项目目录之外,避免项目目录被误删时连备份一起丢失。

mkdir-p/root/MyProject_Backup/mysqlchmod700/root/MyProject_Backup/mysql

以后生成的备份文件会保存在:

/root/MyProject_Backup/mysql/

文件名示例:

myproject_2026-06-26_200000.sql.gz

4. 创建 MySQL 自动备份脚本

创建脚本文件:

vi/root/backup_myproject_mysql.sh

将下面内容完整粘贴进去:

#!/usr/bin/env bashset-euopipefail# ========================================# MyProject Docker MySQL 自动备份脚本# ========================================# Docker 中 MySQL 容器名称CONTAINER_NAME="myproject-mysql"# 要备份的数据库名称DATABASE_NAME="myproject"# MySQL root 密码MYSQL_ROOT_PASSWORD="myproject123456"# 备份保存目录BACKUP_DIR="/root/MyProject_Backup/mysql"# 保留最近多少天的备份# 每 5 天备份一次,保留 30 天约等于保留 6 份RETENTION_DAYS=30# 创建备份目录mkdir-p"${BACKUP_DIR}"chmod700"${BACKUP_DIR}"# 检查 MySQL 容器是否正在运行if!dockerps--format'{{.Names}}'|grep-qx"${CONTAINER_NAME}";thenecho"[$(date'+%F %T')] 错误:MySQL 容器${CONTAINER_NAME}未运行。">&2exit1fi# 生成带时间戳的备份文件名TIMESTAMP=$(date+"%F_%H%M%S")BACKUP_FILE="${BACKUP_DIR}/${DATABASE_NAME}_${TIMESTAMP}.sql.gz"TMP_FILE="${BACKUP_FILE}.tmp"echo"[$(date'+%F %T')] 开始备份数据库:${DATABASE_NAME}"# 导出数据库并进行 gzip 压缩# --single-transaction:InnoDB 数据库可在不停机状态下进行一致性备份# --quick:减少大数据库备份时的内存占用dockerexec\-eMYSQL_PWD="${MYSQL_ROOT_PASSWORD}"\"${CONTAINER_NAME}"\mysqldump\-uroot\--single-transaction\--quick\--routines\--events\--triggers\--databases"${DATABASE_NAME}"\|gzip-c>"${TMP_FILE}"# 检查压缩包是否完整gzip-t"${TMP_FILE}"# 验证成功后,将临时文件改为正式备份文件mv"${TMP_FILE}""${BACKUP_FILE}"echo"[$(date'+%F %T')] 备份成功:${BACKUP_FILE}"# 删除超过保留期限的旧备份find"${BACKUP_DIR}"\-typef\-name"*.sql.gz"\-mtime+"${RETENTION_DAYS}"\-deleteecho"[$(date'+%F %T')] 已清理超过${RETENTION_DAYS}天的旧备份。"

保存并退出vi

按 Esc 输入 :wq 按 Enter

为脚本添加执行权限:

chmod700/root/backup_myproject_mysql.sh

检查权限:

ls-l/root/backup_myproject_mysql.sh

正常应看到类似:

-rwx------ 1 root root ... /root/backup_myproject_mysql.sh

其中x表示脚本具有执行权限。


5. 手动测试备份

先手动运行一次脚本,确认配置正确:

/root/backup_myproject_mysql.sh

正常情况下会输出类似:

[2026-06-26 20:00:00] 开始备份数据库:myproject [2026-06-26 20:00:01] 备份成功:/root/MyProject_Backup/mysql/myproject_2026-06-26_200000.sql.gz [2026-06-26 20:00:01] 已清理超过 30 天的旧备份。

查看备份文件:

ls-lh/root/MyProject_Backup/mysql/

正常会看到:

myproject_2026-06-26_200000.sql.gz

建议先确认手动备份成功,再配置自动定时任务。


6. 创建 systemd 服务

创建service文件:

cat>/etc/systemd/system/myproject-mysql-backup.service<<'EOF' [Unit] Description=MyProject MySQL Backup After=docker.service Requires=docker.service [Service] Type=oneshot ExecStart=/root/backup_myproject_mysql.sh EOF

查看服务文件:

cat/etc/systemd/system/myproject-mysql-backup.service

正常应显示:

[Unit] Description=MyProject MySQL Backup After=docker.service Requires=docker.service [Service] Type=oneshot ExecStart=/root/backup_myproject_mysql.sh

7. 创建每 5 天执行一次的 systemd 定时器

创建 timer 文件:

cat>/etc/systemd/system/myproject-mysql-backup.timer<<'EOF' [Unit] Description=Run MyProject MySQL backup every 5 days [Timer] # 定时器启动后,每隔 5 天执行一次 OnUnitActiveSec=5d # 服务器关机期间错过任务时,恢复运行后补做 Persistent=true [Install] WantedBy=timers.target EOF

参数说明:

OnUnitActiveSec=5d

表示定时器启动后,每隔 5 天运行一次备份服务。

Persistent=true

表示若服务器在计划执行时关机,系统恢复后会补做错过的备份任务。


8. 启用定时器并设置开机自动启动

执行:

systemctl daemon-reload systemctlenable--nowmyproject-mysql-backup.timer systemctl restart myproject-mysql-backup.timer

检查定时器状态:

systemctl status myproject-mysql-backup.timer

正常会显示类似:

Loaded: loaded (...; enabled; ...) Active: active (waiting) Trigger: ...

其中:

  • enabled:服务器重启后,定时器会自动启动;
  • active (waiting):定时器正在等待下一次执行;
  • Trigger:下一次自动备份的时间。

查看下次运行时间:

systemctl list-timers--all|grepmyproject-mysql-backup

检查是否已设置为开机启动:

systemctl is-enabled myproject-mysql-backup.timer

正常应输出:

enabled

9. 测试 systemd 是否能正常调用备份脚本

手动触发一次 systemd 备份:

systemctl start myproject-mysql-backup.service

查看日志:

journalctl-umyproject-mysql-backup.service-n30--no-pager

正常会看到类似:

Starting MyProject MySQL Backup... 开始备份数据库:myproject 备份成功:/root/MyProject_Backup/mysql/myproject_2026-06-26_200000.sql.gz 已清理超过 30 天的旧备份。 Finished MyProject MySQL Backup.

这说明 systemd 可以正常调用备份脚本。


10. 常用备份管理命令

查看所有备份文件

ls-lh/root/MyProject_Backup/mysql/

手动立即备份

/root/backup_myproject_mysql.sh

或:

systemctl start myproject-mysql-backup.service

查看自动备份状态

systemctl status myproject-mysql-backup.timer

查看下一次备份时间

systemctl list-timers--all|grepmyproject-mysql-backup

查看备份日志

journalctl-umyproject-mysql-backup.service-n50--no-pager

停止自动备份

systemctl disable--nowmyproject-mysql-backup.timer

重新启用自动备份

systemctlenable--nowmyproject-mysql-backup.timer

11. 如何恢复某一份数据库备份

假设需要恢复以下备份:

/root/MyProject_Backup/mysql/myproject_2026-06-26_200000.sql.gz

恢复会将当前数据库替换为历史备份版本。开始前请确认选中的备份文件正确。


11.1 先备份当前数据库

恢复前先生成一份当前数据库备份:

/root/backup_myproject_mysql.sh

这样即使恢复了错误版本,也可以回退到恢复操作前的状态。


11.2 停止项目后端容器

先查看运行中的容器:

dockerps

假设后端容器名称为:

myproject-backend

停止后端:

dockerstop myproject-backend

myproject-backend是示例名称,请替换为实际后端容器名称。
MySQL 容器myproject-mysql不需要停止。


11.3 删除当前数据库

dockerexec-it\-eMYSQL_PWD="myproject123456"\myproject-mysql\mysql-uroot-e"DROP DATABASE IF EXISTS myproject;"

这条命令会删除当前的myproject数据库,因此必须确认前一步的备份已成功完成。


11.4 导入指定备份

gunzip-c/root/MyProject_Backup/mysql/myproject_2026-06-26_200000.sql.gz\|dockerexec-i\-eMYSQL_PWD="myproject123456"\myproject-mysql\mysql-uroot

导入过程可能没有额外输出;只要没有报错,一般表示恢复成功。


11.5 检查恢复结果

查看数据库:

dockerexec-it\-eMYSQL_PWD="myproject123456"\myproject-mysql\mysql-uroot-e"SHOW DATABASES;"

查看恢复后的表:

dockerexec-it\-eMYSQL_PWD="myproject123456"\myproject-mysql\mysql-uroot-e"USE myproject; SHOW TABLES;"

能够正常显示表名,通常说明恢复成功。


11.6 启动后端容器

dockerstart myproject-backend

myproject-backend替换成实际后端容器名称。


12. 完整恢复流程

# 1. 备份恢复前的当前数据库/root/backup_myproject_mysql.sh# 2. 查看所有备份文件,确认需要恢复哪一份ls-lh/root/MyProject_Backup/mysql/# 3. 停止项目后端容器dockerstop myproject-backend# 4. 删除当前数据库dockerexec-it\-eMYSQL_PWD="myproject123456"\myproject-mysql\mysql-uroot-e"DROP DATABASE IF EXISTS myproject;"# 5. 恢复指定备份gunzip-c/root/MyProject_Backup/mysql/myproject_2026-06-26_200000.sql.gz\|dockerexec-i\-eMYSQL_PWD="myproject123456"\myproject-mysql\mysql-uroot# 6. 检查恢复后的数据表dockerexec-it\-eMYSQL_PWD="myproject123456"\myproject-mysql\mysql-uroot-e"USE myproject; SHOW TABLES;"# 7. 启动项目后端容器dockerstart myproject-backend

13. 备份策略总结

项目设置
MySQL 容器myproject-mysql
数据库名称myproject
备份目录/root/MyProject_Backup/mysql
备份脚本/root/backup_myproject_mysql.sh
自动备份频率每 5 天一次
备份保留时间30 天
预计保留份数约 6 份
备份格式.sql.gz
自动删除旧备份
开机自动启用定时器

14. 进一步建议

本文中的备份文件仍然存放在同一台服务器,因此可以防止:

  • 数据库误删;
  • 错误更新或错误覆盖;
  • 项目升级失败;
  • 项目目录被误删;
  • 数据库表被错误修改。

但它无法防止:

  • 服务器硬盘损坏;
  • 整台服务器不可用;
  • 云服务器被删除;
  • 勒索软件或严重系统故障。

对于重要数据库,建议定期将以下目录同步到另一块硬盘、NAS、对象存储或另一台服务器:

/root/MyProject_Backup/mysql/

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询