Docker Compose依赖失效:首次启动web服务无法连接PostgreSQL
解决Docker Compose中Django服务首次启动因PostgreSQL未就绪导致迁移失败的问题
核心问题在于:depends_on 仅能保证 db 服务先于 web 服务启动,但无法确保PostgreSQL完成初始化(比如创建默认库、用户,完成内部启动流程)并处于可连接状态。首次启动时PostgreSQL初始化耗时较长,web 服务直接执行迁移就会因连接失败退出;第二次启动时PostgreSQL已完成初始化,能快速就绪,因此迁移正常执行。
以下是几种实用解决方案:
方案1:使用等待脚本前置检查
编写一个shell脚本,在执行迁移前轮询PostgreSQL的就绪状态,直到可连接后再继续执行后续命令。
- 创建
entrypoint.sh脚本:
#!/bin/sh # 等待PostgreSQL服务就绪 until pg_isready -h db -U postgres; do echo "等待PostgreSQL服务就绪..." sleep 2 done # 执行数据库迁移 python manage.py migrate # 启动Django服务 exec "$@"
- 给脚本添加执行权限:
chmod +x entrypoint.sh
- 修改Dockerfile,确保安装
postgresql-client(提供pg_isready命令)并复制脚本:
FROM python:3.11-slim # 安装PostgreSQL客户端 RUN apt-get update && apt-get install -y --no-install-recommends postgresql-client && rm -rf /var/lib/apt/lists/* WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 复制等待脚本 COPY entrypoint.sh . COPY . . ENTRYPOINT ["./entrypoint.sh"] CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
- 调整docker-compose.yml(无需修改
depends_on,脚本已处理等待逻辑):
services: web: build: . depends_on: - db ports: - "8000:8000" db: image: postgres:latest environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: your_password POSTGRES_DB: your_db_name
方案2:配置Docker健康检查
给db服务添加健康检查,让web服务仅在db健康检查通过后才启动。
修改docker-compose.yml:
services: web: build: . command: sh -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000" depends_on: db: condition: service_healthy ports: - "8000:8000" db: image: postgres:latest environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: your_password POSTGRES_DB: your_db_name healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5
service_healthy 条件会让web服务等待db的健康检查连续通过5次(每次间隔5秒)后再启动,确保PostgreSQL完全就绪。
方案3:迁移命令自动重试(快速测试用)
如果是开发环境,可直接在启动命令中加入重试逻辑,无需额外脚本或配置:
services: web: build: . command: sh -c "until python manage.py migrate; do echo '迁移失败,重试中...'; sleep 2; done && python manage.py runserver 0.0.0.0:8000" depends_on: - db ports: - "8000:8000" db: image: postgres:latest environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: your_password POSTGRES_DB: your_db_name
这个方法会循环执行迁移命令,直到成功为止,适合快速验证场景。
内容的提问来源于stack exchange,提问作者watch-this
相关产品推荐
相关产品推荐

