核心思路是将迁移动作从应用启动后补救转为服务就绪前强制校验,依托容器生命周期接管而非人工执行;分三种方式:官方镜像初始化(仅首次)、专用迁移容器(推荐生产)、应用内嵌迁移(适配框架);必须配套安全防错措施。
核心思路是把迁移动作从“应用启动后补救”转为“服务就绪前强制校验”,靠容器生命周期接管,而不是靠人去记得执行。
用官方镜像的初始化机制(适合MySQL/PostgreSQL首次部署)
这是最轻量、最稳妥的入门方式,适用于全新环境或CI测试环境:
- 把SQL迁移脚本放在 ./migrations/ 目录下,命名如
V1__init.sql、V2__add_status_column.sql - 在
docker-compose.yml中挂载到官方镜像的初始化路径:volumes:- ./migrations:/docker-entrypoint-initdb.d(MySQL)- ./migrations:/docker-entrypoint-initdb.d(PostgreSQL) - 注意:该机制只在数据库数据目录为空时触发(即首次启动或删掉volume重来),不适用于已有数据的增量升级
用专用迁移容器(推荐用于生产与CI/CD)
把迁移逻辑独立出来,和主应用解耦,失败不影响主服务启动,也便于审计和回滚:
- 写一个极简Dockerfile,基于
flyway/flyway或ghcr.io/golang-migrate/migrate镜像 - COPY 迁移脚本(如
migrations/*.sql)进镜像,或通过 volume 挂载 - ENTRYPOINT 设为迁移命令,例如:
flyway -url=jdbc:postgresql://db:5432/app -user=postgres migrate - 在 docker-compose.yml 中定义该服务,并用
depends_on: { db: { condition: service_healthy } }确保等数据库真正可连再跑
在主应用容器内嵌迁移逻辑(适合简单项目或框架集成)
适合已用 Laravel、Spring Boot、Django 等自带迁移能力的框架,只需控制执行时机:
- 修改应用镜像的 entrypoint.sh,开头加等待+迁移逻辑:
until pg_isready -h db -U postgres -d app; do sleep 2; donepython manage.py migrate --noinput(Django)php artisan migrate --force(Laravel) - 确保迁移命令带
--noinput或--force,避免交互卡住 - 迁移成功后再
exec "$@"启动真正的应用进程(如 gunicorn、java -jar) - 关键点:迁移失败必须退出容器(exit 1),不能静默跳过
安全与防错必须同步配置
自动化迁移一旦出错,修复窗口极短,所以这些不是“可选”,而是“必须”:
- 所有迁移脚本配对提供 .up.sql 和 .down.sql,哪怕 down 是空操作
- CI 流水线里加一步 schema diff 校验:用
sqldef diff或mysqldump --no-data对比当前库与基线,不一致就中断发布 - 生产环境迁移容器启动时加
--rm和超时限制(如timeout 300),防止卡死 - 迁移镜像版本号严格绑定 Git Tag(如
myapp-migrator:v2.3.0),禁止 latest 标签











