mysql迁移到docker需规避数据丢失、io性能断崖、启动依赖失效三类风险:必须挂载数据卷(命名卷或绑定挂载并赋权)、配置healthcheck确保服务就绪、调优存储层io参数及mysql配置、正确挂载配置目录并显式设置字符集。

MySQL迁移到Docker不是“换个运行方式”那么简单,核心风险集中在数据丢失、IO性能断崖、启动依赖失效这三类——它们都可在启动前用几行命令规避,但一旦出事,恢复成本远高于预防成本。
挂载卷没配对,删容器=删库
这是新手踩得最多、后果最重的坑:容器一删,所有数据清零。根本原因不是Docker不持久,而是你没把数据目录 /var/lib/mysql 显式挂到宿主机或命名卷上。
- ❌ 错误示范:
docker run -d mysql:8.0(没任何-v参数,数据全在容器可写层) - ✅ 命名卷方案(推荐):
docker volume create mysql-data,再启动时加-v mysql-data:/var/lib/mysql - ✅ 绑定挂载方案(需手动赋权):
chown -R 999:999 /ssd/mysql-data(MySQL官方镜像固定UID=999),再挂-v /ssd/mysql-data:/var/lib/mysql - ⚠️ 禁止挂到
/tmp或/home下的默认ext4分区——没调优过IO参数,小文件刷盘延迟高
MySQL容器启动了,但应用连不上
depends_on 只等容器进程起来,不等MySQL服务真正就绪。首次启动要初始化数据目录、加载系统表,常耗时15~40秒,期间TCP端口虽通,mysql 进程拒绝连接。
- 必须配
healthcheck:在docker-compose.yml中加healthcheck:<br> test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]<br> timeout: 20s<br> retries: 10
- 应用服务侧用
condition: service_healthy替代depends_on - 避免在启动脚本里硬写
sleep 30——不可靠,且掩盖真实就绪状态
查询变慢、慢日志暴增,其实是存储层卡住
不是MySQL配置错了,而是Docker卷挂载方式触发了底层IO瓶颈:OverlayFS+ext4在随机小IO场景下元数据锁争用严重,尤其宿主机是机械盘或未调优时。
- Mac/Windows Docker Desktop 用户:文件共享机制引入30%+延迟,生产环境禁用;本地开发可接受,但别拿它压测
- Linux宿主机务必检查挂载参数:
mount | grep $(df . | tail -1 | awk '{print $1}'),确认含noatime,barrier=0(SSD适用) - 容器内验证是否走Direct I/O:
cat /proc/$(pgrep mysqld)/stack | grep dio,无输出说明还在buffered write,大量脏页堆积 - MySQL配置关键项:
innodb_flush_method=O_DIRECT_NO_FSYNC(8.0.17+)、innodb_io_capacity=2000(按SSD实测IOPS设)
配置文件被覆盖、字符集乱码、权限报错
Docker官方镜像启动时会自动检测 /etc/mysql/my.cnf 是否存在,若不存在则生成默认配置;若存在但路径挂载错误(比如挂成文件而非目录),MySQL直接启动失败。
- 挂配置必须用目录挂载:
-v /host/conf:/etc/mysql/conf.d(推荐),而非-v /host/my.cnf:/etc/mysql/my.cnf - conf.d下新建
custom.cnf,内容以[mysqld]开头,避免覆盖基础配置 - 字符集必须显式设全:
character-set-server=utf8mb4+collation-server=utf8mb4_unicode_ci,仅客户端设不够 - 宿主机配置文件权限:确保非root用户也能读(MySQL容器内以UID 999运行),
chmod 644 /host/conf/custom.cnf
最容易被忽略的是:命名卷的物理路径无法调优,而绑定挂载的目录你必须自己做XFS格式化、fallocate预分配、禁用atime——这些操作不在Docker文档里,但决定着上线后查一条SELECT要不要等2秒。











