Docker容器无法互连:Django-Rest与PostgreSQL连接失败排查
问题分析与解决方案
问题原因
Docker Compose 中的 depends_on 仅能确保 db 容器在 backend 容器之前启动,但无法保证 PostgreSQL 服务已经完成初始化并处于就绪状态。PostgreSQL 启动时需要完成数据库创建、用户权限配置等操作,这个过程需要几秒时间;而 backend 容器启动后会立即尝试连接数据库,此时 Postgres 尚未准备好,就会抛出连接拒绝错误。
解决方案
方案1:为后端容器添加启动等待脚本
在 Django 容器的启动流程中加入等待 Postgres 就绪的逻辑,确认数据库可连接后再启动 Django 服务。
方法A:自定义检查脚本
在你的 Django 项目目录(./api 下)创建一个 wait-for-postgres.sh 脚本:
#!/bin/bash set -e host="$1" port="$2" shift 2 cmd="$@" until pg_isready -h "$host" -p "$port"; do >&2 echo "Postgres 未就绪 - 等待1秒" sleep 1 done >&2 echo "Postgres 已就绪 - 启动服务" exec $cmd
给脚本添加执行权限:
chmod +x wait-for-postgres.sh
修改 ./api/Dockerfile 的启动命令:
CMD ["./wait-for-postgres.sh", "db", "5432", "--", "python", "manage.py", "runserver", "0.0.0.0:8000"]
注意:需确保 Django 容器中安装了 postgresql-client,可在 Dockerfile 中添加:RUN apt-get update && apt-get install -y postgresql-client
方法B:直接在启动命令中写循环检查
如果不想额外添加脚本,可直接修改 Dockerfile 的启动命令:
CMD sh -c "until pg_isready -h db -p 5432; do sleep 1; done; python manage.py runserver 0.0.0.0:8000"
方案2:利用 Docker Compose 健康检查
通过给 db 服务添加健康检查,让 backend 容器等待 db 服务进入健康状态后再启动。
修改 docker-compose.yml:
version: '3.9' services: db: image: postgres:latest restart: always ports: - "5432:5432" environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=85842475DB - POSTGRES_DB=sports_center_db - POSTGRES_PORT=5432 # 添加健康检查配置 healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d sports_center_db"] interval: 5s timeout: 5s retries: 5 backend: build: ./api depends_on: # 等待db服务进入健康状态 db: condition: service_healthy ports: - "8000:8000" environment: - DB_NAME=sports_center_db - DB_USER_NAME=postgres - DB_PASSWORD=85842475DB - DB_HOST=db - DB_PORT=5432
方案3:让 Django 自动重试数据库连接
修改 manage.py,在启动服务前添加数据库连接重试逻辑:
import time import sys from django.db import connections from django.db.utils import OperationalError def wait_for_db(): while True: try: db_conn = connections['default'] db_conn.ensure_connection() break except OperationalError: print('数据库未就绪,等待1秒...') time.sleep(1) if __name__ == "__main__": wait_for_db() from django.core.management import execute_from_command_line execute_from_command_line(sys.argv)
这样启动 Django 时会自动循环尝试连接数据库,直到成功再执行后续命令。
内容的提问来源于stack exchange,提问作者Abdur Rahman
相关产品推荐
相关产品推荐

