Docker化Django应用时PostgreSQL 5432端口连接拒绝问题排查
问题描述
原本运行正常的Django应用在Docker化后,执行docker-compose up -d --build,PostgreSQL容器正常启动,但Django容器抛出django.db.utils.OperationalError,提示无法连接localhost的5432端口。相关配置文件如下:
Dockerfile
# pull official base image FROM python:3.9-alpine3.13 # set work directory WORKDIR /usr/src/app # set environment variables ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1 # install psycopg2 dependencies RUN apk update \ && apk add linux-headers postgresql-dev gcc python3-dev musl-dev # install dependencies RUN pip install --upgrade pip COPY ./requirements.txt . COPY ./requirements.dev.txt . RUN pip install -r requirements.txt # copy entrypoint.sh COPY ./entrypoint.sh . RUN sed -i 's/\r$//g' /usr/src/app/entrypoint.sh RUN chmod +x /usr/src/app/entrypoint.sh # copy project COPY . . # run entrypoint.sh ENTRYPOINT ["/usr/src/app/entrypoint.sh"]
docker-compose.yml
version: '3.9' services: app: build: context: . args: - DEV=true ports: - "8000:8000" volumes: - .:/app command: > sh -c "python manage.py migrate && python app/manage.py runserver 192.168.1.135:8000" env_file: - variables.env depends_on: - db db: image: postgres:13-alpine container_name: postgres volumes: - dev-db-data:/var/lib/postgresql/data environment: - POSTGRES_DB=db - POSTGRES_USER=user - POSTGRES_PASSWORD=password ports: - '5432:5432' volumes: dev-db-data: dev-static-data:
settings.py数据库配置
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': environ.get("DATABASE_NAME"), 'USER': environ.get("DATABASE_USER"), 'PASSWORD': environ.get("DATABASE_PASSWORD"), 'HOST': environ.get("DATABASE_HOST"), 'PORT': environ.get("DATABASE_PORT"), } }
错误信息
django.db.utils.OperationalError: could not connect to server: Connection refused dwl_backend-app-1 | Is the server running on host "localhost" (127.0.0.1) and accepting dwl_backend-app-1 | TCP/IP connections on port 5432? dwl_backend-app-1 | could not connect to server: Address not available dwl_backend-app-1 | Is the server running on host "localhost" (::1) and accepting dwl_backend-app-1 | TCP/IP connections on port 5432?
解决方案
1. 修正数据库HOST配置
Docker Compose会为服务创建独立网络,容器间通过服务名通信,而非localhost。你的Django容器尝试连接自身的回环地址localhost,但PostgreSQL在另一个容器中,必须将数据库HOST设置为docker-compose中PostgreSQL服务的名称db。
打开variables.env文件修改配置:
DATABASE_NAME=db DATABASE_USER=user DATABASE_PASSWORD=password DATABASE_HOST=db # 替换原来的localhost或127.0.0.1 DATABASE_PORT=5432
2. 解决PostgreSQL启动延迟问题
depends_on仅保证PostgreSQL容器先启动,但不保证数据库服务完成初始化。Django容器启动时,PostgreSQL可能还在初始化,导致连接失败。
方法一:修改entrypoint.sh添加等待逻辑
更新entrypoint.sh,加入等待PostgreSQL就绪的代码:
#!/bin/sh # 等待PostgreSQL服务就绪 while ! pg_isready -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USER"; do echo "等待PostgreSQL服务启动..." sleep 2 done # 执行后续命令 exec "$@"
同时在Dockerfile中安装postgresql-client(pg_isready属于该包):
RUN apk update \ && apk add linux-headers postgresql-dev gcc python3-dev musl-dev postgresql-client
方法二:使用wait-for-it脚本
下载wait-for-it.sh到项目根目录,修改docker-compose的command:
command: > sh -c "./wait-for-it.sh db:5432 -- python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
给脚本添加执行权限:chmod +x wait-for-it.sh
3. 统一容器内路径配置
Dockerfile设置的工作目录是/usr/src/app,但docker-compose的volumes将本地代码挂载到/app,路径不一致可能导致找不到manage.py。
修改docker-compose的volumes配置,与Dockerfile的WORKDIR保持一致:
volumes: - .:/usr/src/app
同时修正command中的路径,使用0.0.0.0:8000让服务监听容器内所有接口:
command: > sh -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
4. 验证数据库配置一致性
确保docker-compose中PostgreSQL服务的环境变量与Django的env文件完全匹配:
POSTGRES_DB对应DATABASE_NAMEPOSTGRES_USER对应DATABASE_USERPOSTGRES_PASSWORD对应DATABASE_PASSWORD
内容的提问来源于stack exchange,提问作者mightycode Newton

