You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Docker Compose中先执行Alembic迁移再启动FastAPI

解决方案:Docker Compose 中实现 PostgreSQL 就绪后执行 Alembic 迁移再启动 FastAPI

核心问题分析

你遇到的连接拒绝/表不存在问题,本质是PostgreSQL 容器启动后并非立刻能接受连接,直接用 && 串联命令会导致迁移或 API 提前执行,无法等待数据库完全就绪。

实现步骤

1. 编写启动脚本(推荐 Shell 脚本)

创建 start.sh 脚本,负责等待 PostgreSQL 就绪、执行迁移、启动 API:

#!/bin/bash

# 等待 PostgreSQL 就绪(使用官方工具 pg_isready)
echo "等待 PostgreSQL 启动..."
until pg_isready -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER"; do
  sleep 2
done

# 执行 Alembic 迁移(已存在表会自动跳过)
echo "PostgreSQL 就绪,执行数据库迁移..."
alembic upgrade head

# 启动 FastAPI 应用
echo "迁移完成,启动 API 服务..."
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

给脚本添加执行权限:

chmod +x start.sh

2. 修改 Dockerfile

确保镜像包含 postgresql-client(用于 pg_isready),并将脚本设置为容器启动命令:

FROM python:3.11-slim

WORKDIR /app

# 安装系统依赖(含 pg_isready)和 Python 依赖
COPY requirements.txt .
RUN apt-get update && apt-get install -y --no-install-recommends postgresql-client \
    && rm -rf /var/lib/apt/lists/* \
    && pip install --no-cache-dir -r requirements.txt

# 复制应用代码、Alembic 配置和启动脚本
COPY . .
COPY start.sh .

# 设置容器启动命令
CMD ["./start.sh"]

3. 配置 Docker Compose

添加 PostgreSQL 健康检查,确保 API 容器仅在数据库完全就绪后启动:

version: '3.8'

services:
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: your_db_user
      POSTGRES_PASSWORD: your_db_password
      POSTGRES_DB: your_db_name
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    # 健康检查:检测数据库是否可正常连接
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U your_db_user -d your_db_name"]
      interval: 5s
      timeout: 5s
      retries: 5

  api:
    build: .
    environment:
      DB_HOST: db
      DB_PORT: 5432
      DB_USER: your_db_user
      DB_PASSWORD: your_db_password
      DB_NAME: your_db_name
    ports:
      - "8000:8000"
    volumes:
      - .:/app  # 开发环境热重载用
    # 依赖数据库容器,且仅在数据库健康后启动
    depends_on:
      db:
        condition: service_healthy

volumes:
  postgres_data:

4. 确保 Alembic 读取环境变量

修改 alembic/env.py,从环境变量获取数据库连接信息,避免硬编码:

from sqlalchemy import create_engine
import os
from alembic import context

# 从环境变量读取数据库配置
db_user = os.getenv("DB_USER")
db_password = os.getenv("DB_PASSWORD")
db_host = os.getenv("DB_HOST")
db_port = os.getenv("DB_PORT")
db_name = os.getenv("DB_NAME")

# 设置 Alembic 数据库连接 URL
config = context.config
config.set_main_option(
    "sqlalchemy.url",
    f"postgresql://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}"
)

替代方案:用 Python 脚本等待数据库

如果不想安装 postgresql-client,可以写一个 Python 脚本 wait_for_db.py:

import time
import os
from sqlalchemy import create_engine

db_url = f"postgresql://{os.getenv('DB_USER')}:{os.getenv('DB_PASSWORD')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"

while True:
    try:
        engine = create_engine(db_url)
        with engine.connect():
            print("PostgreSQL 已就绪")
            break
    except Exception as e:
        print(f"等待数据库中:{str(e)}")
        time.sleep(2)

然后修改启动命令为:

python wait_for_db.py && alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

内容的提问来源于stack exchange,提问作者TheGreatO96

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 20:22:43