Не удалось подключиться к серверу postgres в докере из докеризованного приложения

Я хотел бы запустить докеризованное приложение Django с докеризированным postgres.

Я запускаю докеризованное приложение Django, используя:

docker run --rm --env-file /path/to/variables -d -p 8000:8000 django_app:test

Я запускаю докеризованный postgres, используя:

docker run --rm -d --env-file /path/to/secrets/variables -p 5432:5432 \
    -v "$PWD/my-postgres.conf":/etc/postgresql/postgresql.conf \
    --mount src=/path/to/db/data,dst=/var/lib/postgresql/data,type=bind \
    postgres:alpine -c 'config_file=/etc/postgresql/postgresql.conf'

моя конфигурация postgres является конфигурацией по умолчанию, которая предлагается в документации контейнера docker postgres. По сути, это файл конфигурации, который содержит listen_addresses = '*'

Я использую одинаковые переменные среды для обоих контейнеров:

DJANGO_SETTINGS_MODULE=settings.module
PROJECT_KEY=xxyyzzabcdefg
DB_ENGINE=django.db.backends.postgresql
POSTGRES_DB=db_name
POSTGRES_USER=db_user
POSTGRES_PASSWORD=verydifficultpassword
POSTGRES_HOST=localhost # I've also tried to use 0.0.0.0
POSTGRES_PORT=5432

Мой модуль настроек Django для базы данных:

 DATABASES = {
    'default': {
        'ENGINE': os.environ.get('DB_ENGINE'),
        'NAME': os.environ.get('POSTGRES_DB'),
        'USER': os.environ.get('POSTGRES_USER'),
        'PASSWORD': os.environ.get('POSTGRES_PASSWORD'),
        'HOST': os.environ.get('POSTGRES_HOST'),
        'PORT': os.environ.get('POSTGRES_PORT')
        }
  }

Тем не менее, я продолжаю получать:

django.db.utils.OperationalError: could not connect to server: Connection refused
    Is the server running on host "0.0.0.0" and accepting
    TCP/IP connections on port 5432?

Файлы Docker для моего приложения django выглядят так:

FROM python:alpine3.7
COPY --from=installer /app /app
# required for postgres
COPY --from=installer /usr/lib /usr/lib
COPY --from=installer /usr/local/bin /usr/local/bin
COPY --from=installer /usr/local/lib /usr/local/lib
ARG SETTINGS_MODULE
WORKDIR /app
ENTRYPOINT python manage.py migrate &&\
           python manage.py test &&\
           python manage.py create_default_groups &&\
           python manage.py set_screen_permissions &&\
           python manage.py create_test_users &&\
           python manage.py init_core &&\
           python manage.py runserver 0.0.0.0:8000

Еще один интересный факт заключается в том, что если я запускаю приложение локально python manage.py runserver и у меня работает контейнер postgres, приложение работает.

Может ли кто-нибудь помочь мне попытаться выяснить, почему мне отказывают в соединении? Заранее спасибо!


person m4rk4l    schedule 29.12.2018    source источник
comment
вы, ребята, дали (почти) один и тот же ответ одновременно. Извините, пришлось выбрать один =( спс за уточнение сетевой команды =)   -  person m4rk4l    schedule 30.12.2018


Ответы (3)


Просто используйте пользовательскую сеть мостов. Во-первых, используйте свои знания, прочитав краткое объяснение различных типов сетей в Docker: https://docs.docker.com/network/bridge/

Во-вторых, определите свою собственную сеть

docker network create foo

Затем запустите свои контейнеры, подключенные к этой сети:

docker run --rm --env-file /path/to/variables -d --network foo django_app:test
docker run --rm -d ... --network foo postgres:alpine ...

Обратите внимание на обе команды --network foo. Также вам не нужно открывать порты в этом случае - внутри пользовательских сетей это делается автоматически:

Контейнеры, подключенные к одной и той же определяемой пользователем мостовой сети, автоматически открывают друг другу все порты, но никакие порты не открываются внешнему миру. Это позволяет контейнерным приложениям легко взаимодействовать друг с другом, не открывая случайно доступ к внешнему миру.

В-третьих, дайте своим контейнерам удобочитаемые имена хостов с помощью --name bar

docker run ... --network foo --name my-django django_app:test ...
docker run ... --network foo --name my-postgres postgres:alpine ...

И, наконец, исправьте строку подключения — измените localhost на имя контейнера, например my-postgres:

...
POSTGRES_HOST=my-postgres
...
person grapes    schedule 29.12.2018

В вашем док-контейнере с Django нет Postgres, работающего на локальном хосте. вам нужно указать на док-контейнер Postgres, указав имя контейнера вместо localhost. Кроме того, контейнер Postgres и ваше приложение должны находиться в одной сети. см. https://docs.docker.com/network/

Чтобы создать сетевой запуск:

docker network create --driver bridge my-network

Для запуска контейнера Docker в сети используйте:

docker run --network my-network -it container_name

Чтобы настроить Postgres в контейнере с Django:

POSTGRES_HOST=postgres-container-name
person Igor Litvinovich    schedule 29.12.2018

В вашем случае вы не указываете имена контейнеров. При установке POSTGRES_HOST=localhost вы указываете контейнеру django подключаться к самому себе. Что, естественно, потерпит неудачу, поскольку в контейнере django нет сервера postgres.

Два ваших контейнера используют сеть bridge по умолчанию (docker0). В мостовой сети имена контейнеров используются в качестве имен хостов.

Это означает, что из вашего контейнера django вы можете получить доступ к контейнеру postgres, используя его имя в качестве имени хоста.

Чтобы иметь возможность подключиться к postgres из вашего приложения django, вам необходимо:

  1. Дайте имена своим контейнерам, используя расширение --name option. Пример: docker run --rm --name mypostgresdb -d ... postgres:alpine -c ...
  2. Сначала создайте контейнер postgres и дождитесь его загрузки. Затем создайте базу данных и пользователя/пароль.
  3. Только когда postgres работает, создайте контейнер django. Если контейнер postgres не запущен, ваш контейнер django завершится ошибкой, поскольку он пытается выполнить миграцию в точке входа.
  4. Переменная env POSTGRES_HOST в вашем контейнере django должна получить имя контейнера postgres в качестве значения. Пример: POSTGRES_HOST=mypostgresdb

Чтобы проверить соединение с контейнером postgres, вы можете пропинговать его из контейнера django.

person Mark    schedule 29.12.2018