mysql容器化迁移前必须确认的三件事:一是数据权限须匹配容器mysql用户uid 999,避免启动失败;二是初始化脚本须精确copy至/docker-entrypoint-initdb.d/并按序命名;三是字符集需在my.cnf、连接字符串中显式设为utf8mb4,确保端到端一致。

MySQL容器化迁移前必须确认的三件事
直接用 Dockerfile 打包旧数据库不是“把 mysqld 服务跑起来”就完事——数据没进容器、权限不对、启动就挂,是高频失败点。
-
mysqldump导出的是逻辑备份,不能直接替换/var/lib/mysql下的物理文件;混用会导致容器启动报Table 'mysql.user' doesn't exist - MySQL 容器默认以用户
mysql(UID 999)运行,宿主机导出的数据若属 root,挂载进容器后会因权限拒绝初始化 -
ENTRYPOINT或CMD启动mysqld时若未加--datadir或--socket参数,容易沿用镜像内置路径,和你挂载的数据目录错位
用 Dockerfile 构建带预置数据的 MySQL 镜像(非 volume 方式)
适合 CI/CD 流水线固定环境或离线部署,数据随镜像分发,但镜像体积大、更新成本高。
- 基础镜像选
mysql:8.0而非mysql:latest,避免因 minor 版本升级导致mysql_upgrade自动触发失败 - 把
schema.sql和data.sql放在/docker-entrypoint-initdb.d/目录下,MySQL 容器首次启动时自动执行(仅当/var/lib/mysql为空时) - 别用
COPY . /,而要精确COPY schema.sql /docker-entrypoint-initdb.d/,否则可能覆盖镜像内关键脚本 - 示例片段:
COPY schema.sql /docker-entrypoint-initdb.d/1-schema.sql COPY data.sql /docker-entrypoint-initdb.d/2-data.sql
注意文件名按字典序执行,1-前缀确保先建表再插数据
挂载宿主机数据目录时的权限与 SELinux 陷阱
用 -v /path/on/host:/var/lib/mysql 是常见做法,但 Linux 上极易卡在启动阶段。
- 宿主机目录需属主 UID=999(即镜像中
mysql用户),可用chown -R 999:999 /path/on/host修复;chmod 700比755更安全 - SELinux 启用时(如 CentOS/RHEL),即使权限正确也会报
Permission denied on '/var/lib/mysql',加:Z标签解决:-v /path/on/host:/var/lib/mysql:Z - Mac/Windows Docker Desktop 不受 SELinux 影响,但要注意 macOS 的
osxfs文件系统对fsync()的模拟不完全,大量写入时可能丢事务,生产慎用
迁移后连接验证与字符集一致性检查
容器里 mysql -u root -p 能连上,不代表应用能正常读写——最常漏掉的是客户端和服务端字符集不一致。
- 检查容器内 MySQL 实际生效配置:
mysql -e "SHOW VARIABLES LIKE 'character_set%';",重点看character_set_server和collation_server - 如果原库用
utf8mb4,但 Dockerfile 中没指定my.cnf,MySQL 8.0 默认仍是utf8mb3,需显式挂载配置:[mysqld] character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci
- 应用连接字符串里必须带
?charset=utf8mb4(PHP PDO)或characterEncoding=utf8mb4(JDBC),光靠服务端设置不够
docker-compose.yml 直接扔进生产,却没意识到其中 initdb 脚本只在第一次生效,后续重启不会重跑。











