【问题标题】:How to connect a django app to a dockerized postgres db, both from a dockerized django and non-dockerized django using same DATABASE_HOST如何使用相同的 DATABASE_HOST 从 dockerized django 和 non-dockerized django 将 django 应用程序连接到 dockerized postgres db
【发布时间】:2020-11-18 05:31:20
【问题描述】:

我有一个 postgres 容器,docker-compose.yml:

services:
  db:
    container_name: db
    expose:
      - "5432"
    ports:
      - 5432:5432
    volumes:
      - postgres_data:/var/lib/postgresql/data/

还有一个带有 settings.py 的 django 项目:

DATABASES = {
    'default': {
        'HOST': os.environ.get('POSTGRES_HOST', '127.0.0.1')
        # etc
    }
}

.env

POSTGRES_HOST_DJANGO=db

当我使用 manage.py runserver 0.0.0.0:8000 在本地运行我的 django 应用程序时,它可以正常连接,使用默认的 POSTGRES_HOST=127.0.0.1,因为未加载 .env。

我有时也会在容器中运行我的 django 应用程序:

docker-compose.yml:

   web:
    #restart: unless-stopped
    build: .
    env_file: .env
    command: bash -c "cd /app/src/ && python manage.py runserver 0.0.0.0:8000
    volumes: 
      - .:/app
    ports:
      - 8000:8000
    links: 
      - db:db

但它使用 .env 文件并与 POSTGRES_HOST=db 连接

如果我尝试使用POSTGRES_HOST=db 连接本地运行的 django 应用程序,它会失败:

django.db.utils.OperationalError:无法将主机名“db”转换为地址:名称或服务未知

如果我尝试在带有POSTGRES_HOST=127.0.0.1 的容器中运行 django 应用程序,它会以同样的方式失败。

我怎样才能让他们使用相同的POSTGRES_HOST?

【问题讨论】:

  • 你没有;你需要在不同的环境中设置不同的环境变量,这就是.env文件的用途。
  • 你是说不可能吗?两者都读取相同的 .env 文件,所以即使我有两个 .env 文件,我如何让 settings.py 文件知道要读取哪个文件?
  • 由于您有两种不同的设置和两种不同的主机名方案,您应该能够使用两个不同的.env 文件。您可以在 docker-compose.yml 文件中指定备用 env_file:,或将不同的配置文件绑定挂载到您的容器中。

标签: django postgresql docker docker-compose django-settings


【解决方案1】:

问题似乎出在网络配置中。我没有看到。

docker-compose 的默认行为是它为每个 compose 文件创建一个网络 - 默认情况下,名称是带有 '_default' 的文件夹名称。

Django App 在不同的网络中,Postgres 在不同的网络中

如果您的 Django 应用程序和 Postgres 容器位于不同的 docker-compose 文件中,则使用容器名称来解析主机将不起作用(默认情况下,可以使用自定义网络配置完成),因为它们位于两个不同的网络中。

由于你已经完成了端口绑定,你可以通过在容器中提供宿主机的私有 ip 和端口 5432 来直接访问 Postgres,这样通信是通过宿主网络进行的。

如果您发现需要让容器直接相互通信,请确保它们在同一个 docker 网络上

【讨论】:

  • 它们在同一个 docker-compose 文件中。我对容器相互交谈没有任何问题。问题是当我尝试在容器外部本地运行 django 时,它只会使用 127.0.0.1 而不是 db 连接到 postgres 容器。我想要一种方法让它适用于两种连接方式:通过 Web 容器,以及在容器外部本地运行
  • 是您的网络 cmets,它们能够连接,因为所有端口都映射出 5342:5342 等。但这显然是糟糕的设计,因为它暴露了每个服务,所以我删除了端口映射并按照此处的建议重新配置我的服务以使用前端和后端网络:docker.com/blog/containerized-python-development-part-2 感谢您提示我正确的方向!
【解决方案2】:

我想出了怎么做。不是让他们使用相同的变量,而是让他们根据运行方式读取不同的变量。所以:

来自 docker-compose.yml

   web:
    build: .
    command: bash -c "cd /app/src/ && python manage.py runserver 0.0.0.0:8000
    env_file: .env
    environment:
      POSTGRES_HOST: db  # takes precendent over .env file

在 .env 中:

POSTGRES_HOST=127.0.0.1

现在,当我使用 ./manage.py runserver 在本地运行时,它使用 .env 文件并在 127.0.0.1:5342 正确连接到 db 容器

但是如果我运行docker-compose up web,即使它也读取了.env文件,compose文件中提供的环境变量优先,它使用POSTGRES_HOST: db并连接到db容器!

【讨论】:

  • 很好的解释。关键是POSTGRES_HOST: db 优先于 .env 文件!!!
猜你喜欢
  • 2019-11-06
  • 1970-01-01
  • 2018-06-10
  • 1970-01-01
  • 2017-12-29
  • 2020-06-15
  • 2020-06-07
  • 2021-07-30
  • 2020-11-10
相关资源
最近更新 更多