官方MySQL镜像(如mysql:8.0)经生产验证,只需通过环境变量(启动时传入,禁用Dockerfile硬编码)、/etc/mysql/conf.d/下自定义my.cnf、/docker-entrypoint-initdb.d/中初始化脚本即可安全扩展,配合时区设置与配置生效验证, fully 满足生产需求。

直接用官方镜像加自定义配置就能满足生产需求,没必要从零编译或重写 entrypoint。 官方 mysql:8.0 或 mysql:5.7 镜像已通过大量生产验证,关键在怎么安全、可控地扩展它。
环境变量必须只用于初始化,不能硬编码密码
官方镜像支持 MYSQL_ROOT_PASSWORD、MYSQL_DATABASE 等变量,但它们仅在容器首次启动且数据目录为空时生效。生产中若反复重建容器,硬编码会导致密码泄露或初始化失败。
- 开发/测试阶段可临时写进
Dockerfile的ENV,但上线前必须删掉 - 生产部署统一用
docker run -e MYSQL_ROOT_PASSWORD=xxx或docker-compose.yml的environment字段传入 - 敏感值优先走 Docker secrets(Swarm)或 Kubernetes Secret,避免出现在进程列表或日志里
my.cnf 要放在 /etc/mysql/conf.d/ 下,别覆盖主配置
官方镜像默认加载 /etc/mysql/conf.d/*.cnf 和 /etc/mysql/mysql.conf.d/*.cnf,直接 COPY 到这些路径即可生效,无需修改 /etc/mysql/my.cnf 主文件。
- 新建
my_custom.cnf,只写你真正要改的项,比如:max_connections=1000、character-set-server=utf8mb4 - 不要写
[client]段落里的password—— 这会把密码明文留在配置文件里 - MySQL 8.0+ 默认启用
skip-name-resolve,如果应用依赖主机名解析,得显式关掉它
初始化脚本必须用 .sql 或 .sh,且只能在首次启动执行
官方镜像会自动运行 /docker-entrypoint-initdb.d/ 下所有 .sql、.sql.gz、.sh 文件,但仅当 /var/lib/mysql 为空时才触发。这点常被误以为“每次重启都执行”。
-
init.sql适合建库、建表、INSERT 基础数据;init.sh适合条件判断或调用 mysql 命令行工具 - 脚本里别用
mysql -uroot -p$MYSQL_ROOT_PASSWORD—— 密码可能被 shell history 或 ps 看到;改用mysql --defaults-extra-file=/tmp/.my.cnf配置文件方式 - 如果初始化后还要做迁移或补丁,得靠外部工具(如 Flyway、Liquibase),不是镜像该管的事
镜像构建后务必验证配置是否真实生效
很多人 COPY 了 my.cnf 却没检查 MySQL 是否真读取了它,结果性能参数没起作用,连接数还是默认 151。
- 构建完先
docker run --rm -it mysql-production:latest mysqld --verbose --help | grep "Default options",确认配置路径包含你的/etc/mysql/conf.d/ - 启动容器后进容器执行
mysql -uroot -p -e "SHOW VARIABLES LIKE 'max_connections';",看输出是否是你设的值 - 用
docker exec -it mysql-container cat /proc/1/cmdline查看 mysqld 启动命令,确认没被意外覆盖参数
最易被忽略的是:MySQL 容器内时区默认是 UTC,而业务日志、定时任务、NOW() 函数全依赖它。哪怕只加一行 TZ=Asia/Shanghai 到 environment,也比在 SQL 里到处写 CONVERT_TZ() 可靠得多。


















