【问题标题】:Running Django app in docker-compose: connection to postgres db refuses the first time but works afterwards在 docker-compose 中运行 Django 应用程序:与 postgres db 的连接第一次拒绝但之后可以工作
【发布时间】: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 容器会等待数据库完全准备好后再尝试连接它?

标签: django postgresql docker docker-compose


【解决方案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 或更高版本不再支持这种方式
    猜你喜欢
    • 2021-05-26
    • 1970-01-01
    • 2021-10-12
    • 2020-06-04
    • 2020-02-13
    • 2023-01-04
    • 2020-09-08
    • 2019-01-02
    • 2017-08-06
    相关资源
    最近更新 更多