在构建Docker镜像时如何通过Alembic自动生成并应用数据库迁移
在构建Docker镜像时如何通过Alembic自动生成并应用数据库迁移
我懂你这种痛点——每次改完模型还要手动敲Alembic命令、重新构建镜像,在开发环境里确实有点折腾人。针对你的需求,我给你梳理了一套适合个人开发的方案,能自动处理迁移,不用再手动重复操作:
核心思路说明
首先得明确两个关键逻辑:
- Alembic的
revision --autogenerate只需要对比模型定义和现有迁移脚本,不需要连接数据库,所以可以在构建镜像阶段或者容器启动阶段执行; - 而
upgrade head需要连接到可用的数据库,所以只能在容器启动阶段执行(毕竟构建镜像时你的数据库大概率还没跑起来)。
下面给你具体的实现步骤:
方案一:用启动脚本处理(推荐,灵活度高)
直接在Dockerfile里写复杂命令不够灵活,不如写个shell脚本,让容器启动时先处理迁移,再启动FastAPI服务。
步骤1:创建启动脚本
在项目根目录新建start.sh文件,内容如下:
#!/bin/bash # 生成自动迁移脚本(如果模型有变化) echo "检查模型变化,生成迁移脚本..." alembic revision --autogenerate -m "Auto-generated migration on container start" # 应用最新迁移到数据库 echo "应用数据库迁移到最新版本..." alembic upgrade head # 启动FastAPI服务 echo "启动FastAPI应用..." uvicorn app.main:app --host 0.0.0.0 --port 8000
步骤2:修改Dockerfile
把原来的CMD替换成执行这个脚本,还要给脚本加执行权限:
# Use official Python image FROM python:3.11-slim # Set environment variables ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 # Set work directory WORKDIR /app # Install dependencies COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # Copy project files COPY . . # 给启动脚本添加执行权限 RUN chmod +x start.sh # Expose port EXPOSE 8000 # 替换原来的CMD,执行启动脚本 CMD ["./start.sh"]
步骤3:确保Alembic能正确加载模型和环境变量
打开alembic/env.py,在顶部添加加载.env和导入模型基类的代码,不然Alembic找不到你的模型变化:
from dotenv import load_dotenv import os from logging.config import fileConfig from sqlalchemy import engine_from_config from sqlalchemy import pool from alembic import context # 这里替换成你项目中模型的基类路径,比如所有模型都继承自app.models.base.Base from app.models.base import Base # 加载.env文件里的数据库配置 load_dotenv() # 读取.env里的DB_URL,覆盖alembic.ini里的配置 config = context.config config.set_main_option("sqlalchemy.url", os.getenv("DB_URL")) # 下面保留原来的alembic env.py代码... # 还要确保target_metadata指向你的模型基类的metadata target_metadata = Base.metadata
另外,把python-dotenv加到requirements.txt里,不然加载不了.env文件。
方案二:构建阶段生成迁移脚本(镜像包含迁移文件)
如果你希望迁移脚本被直接打包到镜像里,而不是容器启动时临时生成,可以在Dockerfile的构建阶段执行迁移生成命令:
修改后的Dockerfile片段:
# Copy project files COPY . . # 构建阶段生成迁移脚本(如果模型有变化) RUN alembic revision --autogenerate -m "Auto-generated migration during image build" # 给启动脚本加执行权限 RUN chmod +x start.sh # Expose port EXPOSE 8000 # 启动脚本只做迁移应用和服务启动 CMD ["./start.sh"]
对应的start.sh可以简化,去掉生成迁移的步骤:
#!/bin/bash echo "应用数据库迁移..." alembic upgrade head echo "启动FastAPI服务..." uvicorn app.main:app --host 0.0.0.0 --port 8000
这个方案的好处是,迁移脚本会被包含在镜像里,你可以从镜像里把迁移文件拷出来备份;缺点是每次构建镜像都会执行一次生成命令,不过如果模型没变化,Alembic会输出No changes in schema detected,不会生成多余的文件。
关键注意事项(一定要看!)
- 只适合开发环境:我必须强调,这种自动生成+应用迁移的方式绝对不能用在生产环境!生产环境的迁移需要手动生成、仔细检查、测试后再应用,自动生成的迁移可能漏了索引、约束的变化,甚至会破坏数据。
- 数据库连接要正常:容器启动时,数据库必须是可访问的(比如用Docker Compose把app和DB容器放在同一个网络里),不然
alembic upgrade head会失败。 - 优化.dockerignore:把
myenv/、__pycache__/这些不需要的文件加到.dockerignore里,减少镜像体积:
myenv/ __pycache__/ *.pyc *.pyo *.pyd .env.local
测试方法
- 修改一个模型(比如给某个模型加个新字段);
- 构建镜像:
docker build -t my-fastapi-app .; - 运行容器:
docker run -p 8000:8000 --env-file .env my-fastapi-app; - 查看容器日志,你会看到Alembic生成迁移、应用迁移,然后启动FastAPI的过程。如果模型没变化,生成迁移的步骤会提示没有变化,直接跳过,然后启动服务。
这样你就不用每次改模型都手动敲命令啦,开发效率能提不少~
内容来源于stack exchange
相关产品推荐
相关产品推荐

