系统实践
Docker 中 MySQL 的备份、恢复与恢复验证
从 2017 年的一组导入导出命令出发,整理一套更可靠的 MySQL 容器逻辑备份流程:导出、校验、恢复和验证缺一不可。

本文最初发布于 2017 年。旧文解决了一个关键问题:如何从 MySQL 容器把 SQL 导出到宿主机,以及为什么恢复时要用
-i而不是-it。新版保留这个经验,并补上凭据、压缩、校验和恢复验证。
先理解重定向发生在哪里
下面的 > 是宿主机 Shell 执行的,所以 SQL 文件会写到宿主机当前目录,而不是容器里:
docker exec mysql mysqldump -u backup_user -p app_db > app_db.sql
不要把数据库密码直接写进命令历史。交互执行时可以只写 -p,让客户端提示输入;自动任务则应使用权限受限的配置文件或秘密管理机制。
一次可恢复的逻辑备份
先确认容器名和数据库状态:
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
docker exec mysql mysqladmin ping -u backup_user -p
对于以 InnoDB 为主的普通业务库,可以这样导出:
docker exec mysql mysqldump \
-u backup_user -p \
--single-transaction \
--routines \
--events \
--triggers \
--set-gtid-purged=OFF \
app_db \
| gzip > app_db-$(date +%F).sql.gz
--single-transaction 能减少 InnoDB 逻辑备份期间的锁影响,但它不是所有存储引擎、所有一致性要求的万能方案。生产库需要结合数据量、引擎、复制和恢复目标设计备份策略。
备份后立即做三项检查
test -s app_db-$(date +%F).sql.gz
gzip -t app_db-$(date +%F).sql.gz
shasum -a 256 app_db-$(date +%F).sql.gz > app_db-$(date +%F).sql.gz.sha256
这只能证明文件存在、压缩包可读且以后能检查传输损坏,不能证明数据库一定可以恢复。
恢复到独立测试库
先创建一个不影响生产的目标库:
docker exec -it mysql mysql -u root -p \
-e 'CREATE DATABASE IF NOT EXISTS app_db_restore CHARACTER SET utf8mb4;'
再进行恢复:
gunzip -c app_db-2026-07-16.sql.gz \
| docker exec -i mysql mysql -u root -p app_db_restore
这里必须使用 docker exec -i,不能使用 -it。标准输入来自管道,不需要伪终端;旧文里记录的 cannot enable tty mode on non tty input 正是由此造成。
恢复成功不等于验证完成
至少检查:
docker exec mysql mysql -u root -p app_db_restore \
-e 'SHOW TABLES;'
docker exec mysql mysql -u root -p app_db_restore \
-e 'SELECT COUNT(*) FROM 关键表;'
更可靠的流程还应包含:
- 抽查关键表行数、时间范围和业务约束。
- 检查存储过程、事件、触发器和视图。
- 用测试应用连接恢复库,跑一次核心读取流程。
- 定期在独立环境演练,而不是等事故发生才第一次恢复。
- 将备份复制到与数据库主机故障域不同的位置,并设置保留周期。
什么时候不只用 mysqldump
mysqldump 适合可读、通用的逻辑备份,但大数据库可能耗时较长、恢复较慢。MySQL 官方也建议评估 MySQL Shell dump utilities,它支持并行导出、压缩和进度展示。若要求更短的恢复时间、增量恢复或时间点恢复,还需要结合物理备份与二进制日志。
备份工作的完成标准不是“生成了一个 SQL 文件”,而是“在目标时间内恢复出了可用的数据”。
参考:MySQL 官方的使用 mysqldump 备份、恢复 SQL 格式备份和Docker 部署下的备份说明。

