在 docker-compose 中运行 Django 应用程序:与 postgres db 的连接第一次拒绝但之后可以工作
Posted
技术标签:
【中文标题】在 docker-compose 中运行 Django 应用程序:与 postgres db 的连接第一次拒绝但之后可以工作【英文标题】:Running Django app in docker-compose: connection to postgres db refuses the first time but works afterwards 【发布时间】:2017-12-16 05:27:53 【问题描述】:我有一个奇怪的问题,可以用 Docker 的simple tutorial 重现。
如果我完全按照教程进行操作,一切都会正常工作,即在docker-compose up
命令之后,Web 容器将运行并很好地连接到 db 容器。
但是,如果我选择在主机上创建相同的 Django 项目,请更改其 postgres 数据库的设置,并将其复制到其 Dockerfile 中的 Web 映像,而不是将主机目录安装到容器并执行这些操作如教程中所示(使用命令docker-compose run web django-admin.py startproject composeexample .
,然后更改生成并位于主机上的挂载目录中的设置文件),我第一次运行docker-compose up
时,Web容器连接到db,报错如下
web_1 | psycopg2.OperationalError:无法连接到服务器:连接被拒绝 web_1 |服务器是否在主机“db”(172.18.0.2)上运行并接受 web_1 |端口 5432 上的 TCP/IP 连接?
但是,如果我使用 docker-compose down 停止撰写,然后使用 docker-compose up 再次运行它,Web 容器将成功连接到数据库而没有问题。
“连接被拒绝”在这里似乎不是一个罕见的问题,但我已经检查并验证了所有设置是否正确以及常见的原因,例如端口号错误、端口未公开或将主机设置为“本地”而不是“数据库” ' 等不是这种情况下的问题。
注意:FWIW,我在主机中使用 CNTLM 作为系统代理,必须为 web 图像设置环境变量,它适用于其他场景。
编辑: 请在下面找到更多信息。
在主机目录中,我有以下文件和目录
composeexample(由另一个容器按照相同的教程生成并复制到此处) manage.py(由另一个容器生成并复制到这里) requirements.txt(与教程中的完全相同) Dockerfile(对教程中的文件稍作修改) docker-compose.yml(根据教程中的稍作修改)composeexample/settings.py:
.........
DATABASES =
'default':
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'postgres',
'USER': 'postgres',
'HOST': 'db',
'PORT': 5432,
.........
Dockerfile(大体相同,添加了环境变量):
FROM python:3.5
ENV PYTHONUNBUFFERED 1
ENV http_proxy "http://172.17.0.1:3128"
ENV https_proxy "http://172.17.0.1:3128"
ENV HTTP_PROXY "http://172.17.0.1:3128"
ENV HTTPS_PROXY "http://172.17.0.1:3128"
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
docker-compose(我删除了挂载的卷 .:/code,因为项目文件在构建时已经复制到 Web 映像中。我测试过将其保留在原始文件中,但没有任何区别):
version: '3'
services:
db:
image: postgres
web:
build: .
command: python3 manage.py runserver 0.0.0.0:8000
ports:
- "8000:8000"
depends_on:
- db
【问题讨论】:
你能用你的 docker-compose、dockerfile 和设置 de django 更新帖子吗? 似乎你的 django 容器与你的 db 容器没有正确的连接 谢谢,我已经为数据库添加了 docker-compose、dockerfile 和 Django 设置。是的,我一次又一次地检查以确保与数据库的连接设置正确。事实上,正如问题中所说,如果我停止并再次启动撰写,它将毫无问题地连接到数据库。所以我假设连接设置一定是正确的? 为什么不尝试几秒钟来启动 django 容器,我不确定这是否有问题,但你试试command: /bin/bash -c "sleep 7; python3 manage.py runserver -h 0.0.0.0 -p 9000 -r -d"
非常感谢。将sleep 5
添加到 Web 容器的命令中已经解决了我的问题。我已经读过这个,但我从来没有想到这实际上是问题所在。不过,这对我来说还是有点奇怪,因为我希望一旦您设置了depends_on
,Web 容器会等待数据库完全准备好后再尝试连接它?
【参考方案1】:
使用wait-for-it.sh 等待 Postgres 准备就绪:
下载这个众所周知的脚本:https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh
version: '3'
services:
db:
image: postgres
web:
build: .
command: /wait-for-it.sh db:5432 -- python3 manage.py runserver 0.0.0.0:8000
volumes:
- ./wait-for-it.sh:/wait-for-it.sh
ports:
- "8000:8000"
depends_on:
- db
它会一直等到db端口打开,不会再浪费了。
【讨论】:
谢谢,我接受了朱利安的回答,因为它确实帮助我快速而简单地解决了我的问题。我也做了一些研究,这个解决方案对我来说是一个更合适的解决方案,因此我赞成。【参考方案2】:正如文档所说 depends_ondepends_on
它表达了容器之间的依赖关系,但这并不意味着一个容器将等待其他容器准备好,一个可能的解决方案是在docker-compose
中添加一点睡眠,例如这个:
command: /bin/bash -c "sleep 7; python3 manage.py runserver -h 0.0.0.0 -p 9000 -r -d"
【讨论】:
【参考方案3】:您可以使用healthcheck。
示例来自:peter-evans/docker-compose-healthcheck: How to wait for container X before starting Y using docker-compose healthcheck
version: '3'
services:
db:
image: postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 3s
timeout: 30s
retries: 3
web:
build: .
command: python3 manage.py runserver 0.0.0.0:8000
ports:
- "8000:8000"
depends_on:
db:
condition: service_healthy
【讨论】:
docker compose file version 3 或更高版本不再支持这种方式以上是关于在 docker-compose 中运行 Django 应用程序:与 postgres db 的连接第一次拒绝但之后可以工作的主要内容,如果未能解决你的问题,请参考以下文章
在 gitlab ci 中查找在 docker-compose 中运行的容器的 url/ip
如何使用 pycharm 调试在 docker-compose 中运行的进程
如何在 AWS CodeBuild 上运行 docker-compose?