Docker环境下Django与Postgres分容器部署出现连接重置错误
问题根因
- 容器启动时序不匹配:docker-compose的
depends_on仅控制容器的启动先后顺序,不会等待Postgres内部服务初始化完成。从你提供的Postgres日志可以看到,Postgres容器进程启动后,还需要执行数据恢复、端口监听等步骤,约200ms后才会正式对外提供服务。Django容器启动后会立刻发起数据库连接请求,此时Postgres还未就绪,就会抛出连接被关闭的异常。你手动进入Django容器执行psql命令时,距离容器启动已经过了足够时间,Postgres已经完成初始化,所以可以正常连接。
- 容器启动时序不匹配:docker-compose的
- 数据库连接路径冗余:你当前应该是在Django的
settings.py中配置了HOST=host.docker.internal、PORT=8003,走宿主机端口转发访问数据库。同docker-compose集群内的服务可以直接通过内部网桥访问,绕宿主机转发容易受端口映射规则、防火墙策略、网络波动影响,会提升连接失败的概率。
- 数据库连接路径冗余:你当前应该是在Django的
- 缺少连接重试机制:Django默认没有配置数据库连接自动重试逻辑,首次连接失败就会直接抛出异常终止启动流程。
解决方案
1. 修正Django数据库配置
在settings.py的DATABASES配置项中,将HOST改为docker-compose中定义的数据库服务名db,PORT改为Postgres内部监听的5432端口,走Docker内部网桥通信,避免绕宿主机转发:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': '你的数据库名称', 'USER': 'postgres', 'PASSWORD': '你设置的数据库密码', 'HOST': 'db', 'PORT': '5432', } }
如果使用Django 3.2及以上版本,可以额外开启连接健康检测和长连接配置,自动检测无效连接并重试:
DATABASES['default']['CONN_HEALTH_CHECKS'] = True DATABASES['default']['CONN_MAX_AGE'] = 60
2. 调整启动逻辑,等待Postgres就绪
可以从两种方案中选一种适配你的场景:
方案A:启动前端口检测
在Django启动前新增端口检测逻辑,等待Postgres的5432端口可访问后再启动服务。
首先如果你的Django镜像没有内置netcat工具,在Dockerfile中新增安装命令:
RUN apt-get update && apt-get install -y --no-install-recommends netcat-openbsd && rm -rf /var/lib/apt/lists/*
然后修改docker-compose中web服务的启动命令:
command: ["/bin/sh", "-c", "until nc -z db 5432; do echo '等待Postgres服务就绪...'; sleep 1; done; python manage.py runserver 0.0.0.0:8000"]
方案B:添加容器健康检查
给db服务新增健康检查规则,让depends_on等待Postgres健康检查通过后再启动web服务:
db: build: ./databasedata/ ports: - "8003:5432" volumes: - type: volume source: db target: /var/lib/postgresql/data # 新增健康检查配置 healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 2s timeout: 5s retries: 10 web: build: . ports: - "8000:80" depends_on: # 修改db的依赖条件,等待健康检查通过 db: condition: service_healthy rasa_server: condition: service_started rasa_actions_server: condition: service_started redis: condition: service_started extra_hosts: - "host.docker.internal:host-gateway" volumes: - type: bind source: . target: /code command: [ "python", "manage.py", "runserver" ,"0.0.0.0:8000" ]
3. 临时调试方案
如果是本地开发临时验证,不想修改配置,可以先单独启动db服务,等待Postgres完全初始化后再启动web服务:
# 只启动数据库服务 docker-compose up -d db # 等待30秒确保Postgres就绪 sleep 30 # 启动其余服务 docker-compose up -d
内容的提问来源于stack exchange,提问作者user994165
相关产品推荐
相关产品推荐

