Разрешить Docker контейнеру подключаться к локальной / хостовой базе данных postgres

Недавно я играл с Docker и QGIS и установил контейнер, следуя инструкциям в этом руководстве.

Все отлично работает, хотя я не могу подключиться к локальной базе данных postgres, которая содержит все мои ГИС-данные. Я полагаю, это потому, что моя база данных postgres не настроена на прием удаленных подключений и редактирует файлы conf postgres, чтобы разрешить удаленные подключения, используя инструкции из этой статьи.

Я все еще получаю сообщение об ошибке, когда пытаюсь подключиться к своей базе данных, работающей с QGIS в Docker: не могу подключиться к серверу: Connection refused Is the server running on host "localhost" (::1) and accepting TCP/IP connections to port 5433?Сервер postgres работает, и я отредактировал мой файл pg_hba.conf, чтобы разрешить подключения с диапазона IP-адресов (172.17.0.0/32). Ранее я запрашивал IP-адрес контейнера Docker, используя docker ps и хотя IP-адрес меняется, он до сих пор всегда находился в диапазоне 172.17.0.x

Есть идеи, почему я не могу подключиться к этой базе данных? Наверное, что-то очень простое я представляю!

Я использую Ubuntu 14.04; Postgres 9,3

15 ответов

Решение

TL;DR

  1. использование 172.17.0.0/16 как диапазон IP-адресов, а не 172.17.0.0/32,
  2. Не использовать localhost для подключения к базе данных PostgreSQL на вашем хосте, но вместо IP-адреса хоста. Чтобы сохранить контейнер переносимым, запустите контейнер с --add-host=database:<host-ip> пометить и использовать database в качестве имени хоста для подключения к PostgreSQL.
  3. Убедитесь, что PostreSQL настроен на прослушивание соединений по всем IP-адресам, а не только по localhost, Ищите настройки listen_addresses в файле конфигурации PostgreSQL, обычно находится в /etc/postgresql/9.3/main/postgresql.conf (кредиты @DazmoNorton).

Длинная версия

172.17.0.0/32 это не диапазон IP-адресов, а один адрес 172.17.0.0). Ни один контейнер Docker никогда не получит этот адрес, потому что это сетевой адрес моста Docker (docker0) интерфейс.

Когда Docker запускается, он создает новый сетевой мостовой интерфейс, который вы можете легко увидеть при вызове ip a:

$ ip a
...
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
    link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever

Как вы можете видеть, в моем случае docker0 интерфейс имеет IP-адрес 172.17.42.1 с сетевой маской /16 (или же 255.255.0.0). Это означает, что сетевой адрес 172.17.0.0/16,

IP-адрес назначается случайным образом, но без какой-либо дополнительной настройки он всегда будет 172.17.0.0/16 сеть. Для каждого контейнера Docker будет назначен случайный адрес из этого диапазона.

Это означает, что если вы хотите предоставить доступ из всех возможных контейнеров к вашей базе данных, используйте 172.17.0.0/16,

Простое решение для Mac:

Новейшая версия Docker (18.03) предлагает встроенное решение для переадресации портов. Внутри вашего docker-контейнера просто установите для хоста db значение host.docker.internal, Это будет перенаправлено на хост, на котором работает контейнер докеров.

Документация для этого здесь: https://docs.docker.com/docker-for-mac/networking/

Решение Docker для Mac

17.06 года

Благодаря комментарию @Birchlabs, теперь это специальное DNS-имя доступно только для Mac:

docker run -e DB_PORT=5432 -e DB_HOST=docker.for.mac.host.internal

От 17.12.0-кд-mac46, docker.for.mac.host.internal следует использовать вместо docker.for.mac.localhost, См. Примечание к выпуску для деталей.

Старая версия

Ответ @helmbert хорошо объясняет проблему. Но Docker для Mac не предоставляет мостовую сеть, поэтому мне пришлось сделать этот трюк, чтобы обойти ограничение:

$ sudo ifconfig lo0 alias 10.200.10.1/24

открыто /usr/local/var/postgres/pg_hba.conf и добавьте эту строку:

host    all             all             10.200.10.1/24            trust

открыто /usr/local/var/postgres/postgresql.conf и редактировать изменения listen_addresses:

listen_addresses = '*'

Перезагрузите сервис и запустите свой контейнер:

$ PGDATA=/usr/local/var/postgres pg_ctl reload
$ docker run -e DB_PORT=5432 -e DB_HOST=10.200.10.1 my_app 

То, что делает этот обходной путь, в основном совпадает с ответом @helmbert, но использует IP-адрес, который прикреплен к lo0 вместо docker0 сетевой интерфейс.

Простое решение

Просто добавь --network=host в docker run, Это все!

Таким образом, контейнер будет использовать сеть хоста, поэтому localhost а также 127.0.0.1 будет указывать на хост (по умолчанию они указывают на контейнер). Пример:

docker run -d --network=host \
  -e "DB_DBNAME=your_db" \
  -e "DB_PORT=5432" \
  -e "DB_USER=your_db_user" \
  -e "DB_PASS=your_db_password" \
  -e "DB_HOST=127.0.0.1" \
  --name foobar foo/bar

Представленное здесь решение не работает для меня. Поэтому я отправляю этот ответ, чтобы помочь кому-то, кто столкнулся с аналогичной проблемой.

ОС: Ubuntu 18
PostgreSQL: 9.5 (размещено на Ubuntu)
Docker: серверное приложение (которое подключается к PostgreSQL)

Я использую docker-compose.yml для создания приложения.

ШАГ 1: Добавьтеhost.docker.internal:<docker0 IP>

version: '3'
services:
  bank-server:
    ...
    depends_on:
      ....
    restart: on-failure
    ports:
      - 9090:9090
    extra_hosts:
      - "host.docker.internal:172.17.0.1"

Чтобы найти IP докера i.e. 172.17.0.1 (in my case) вы можете использовать:

$> ifconfig docker0
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255

ИЛИ

$> ip a
1: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever

ШАГ 2: В postgresql.conf измените listen_addresses наlisten_addresses = '*'

ШАГ 3: Добавьте в pg_hba.conf эту строку

host    all             all             0.0.0.0/0               md5

ШАГ 4: Теперь перезапустите службу postgresql, используя,sudo service postgresql restart

ШАГ 5: Используйтеhost.docker.internalимя хоста для подключения к базе данных из серверного приложения.
Пример:jdbc:postgresql://host.docker.internal:5432/bankDB

Наслаждаться!!

ты можешь пройти --network=hostв течение docker runкоманда для доступа localhostвнутри контейнера.

Бывший:

      docker run --network=host docker-image-name:latest

Если вы хотите передать переменные env с использованием localhost --env-fileпараметр для доступа к переменным среды внутри контейнера.

Бывший:

      docker run --network=host --env-file .env-file-name docker-image-name:latest

Примечание. Передайте параметры перед именем образа докера, иначе параметры не будут работать. (Я столкнулся с этим, так что держите голову!)

Для docker-compose вы можете попробовать просто добавить

network_mode: "host"

пример:

version: '2'
services:
  feedx:
    build: web
    ports:
    - "127.0.0.1:8000:8000"
    network_mode: "host"

https://docs.docker.com/compose/compose-file/

Позвольте мне попытаться объяснить, что я сделал.

Postgresql

Прежде всего, я выполнил настройку, необходимую, чтобы убедиться, что моя база данных Postgres принимает подключения извне.

открыто pg_hba.conf и добавьте в конце следующую строку:

      host    all             all             0.0.0.0/0               md5

открыто postgresql.conf и ищи listen_addresses и измените там вот так:

      listen_addresses = '*'

Убедитесь, что в строке выше нет комментария #

-> Перезагрузите базу данных

OBS : это не рекомендуемая конфигурация для производственной среды.

Затем я поискал своего хозяина ip. Я использовал ip localhosts 127.0.0.1, но контейнер его не видит, поэтому сообщение об отказе в подключении появляется при запуске контейнера. После долгого поиска в Интернете по этому поводу я прочитал, что контейнер видит внутренний IP-адрес из вашей локальной сети (тот, который ваш маршрутизатор приписывает каждому устройству, которое к нему подключается, я не говорю об IP-адресе, который дает вам доступ к Интернет). Тем не менее, я открыл терминал и сделал следующее:

Ищите ip локальной сети

Откройте терминал или CMD

(MacOS / Linux)

      $ ifconfig

(Windows)

      $ ipconfig

Эта команда покажет информацию о конфигурации вашей сети. И выглядит так:

      en4: 
    ether d0:37:45:da:1b:6e 
    inet6 fe80::188d:ddbe:9796:8411%en4 prefixlen 64 secured scopeid 0x7 
    inet 192.168.0.103 netmask 0xffffff00 broadcast 192.168.0.255
    nd6 options=201<PERFORMNUD,DAD>
    media: autoselect (100baseTX <full-duplex>)
    status: active

Ищите тот, который активен.

В моем случае IP-адрес моей локальной сети был 192.168.0.103

После этого я запустил контейнер.

Докер

Запустите контейнер с --add-host параметр, например:

      $ docker run --add-host=aNameForYourDataBaseHost:yourLocalNetWorkIp --name containerName -di -p HostsportToBind:containerPort imageNameOrId

В моем случае я сделал:

      $ docker run --add-host=db:192.168.0.103 --name myCon -di -p 8000:8000 myImage

я использую Django, Итак 8000 порт по умолчанию.

Приложение Django

Конфигурация доступа к базе данных была:

В settings.py

      DATABASES = {
    'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': ‘myDataBaseName',
            'USER': ‘username',
            'PASSWORD': '123456',
            'HOST': '192.168.0.103',
            'PORT': 5432,
    }
}

Рекомендации

О -pфлаг: подключение с использованием сопоставления сетевых портов

О docker run: Документация по запуску Docker

Интересная статья: Совет Docker #35: подключитесь к базе данных, работающей на вашем хосте Docker

Чтобы настроить что-то простое, что позволяет устанавливать соединение Postgresql из контейнера докеров с моим локальным хостом, я использовал это в postgresql.conf:

listen_addresses = '*'

И добавил этот pg_hba.conf:

host    all             all             172.17.0.0/16           password

Затем сделайте перезагрузку. Мой клиент из контейнера докеров (который был на 172.17.0.2) мог затем подключиться к Postgresql, запущенному на моем локальном хосте, используя host: пароль, базу данных, имя пользователя и пароль.

РЕШЕНИЕ В 3 ШАГА

1. Обновите файл docker-compose

Во-первых, поскольку база данных является локальной, нам нужно привязать хост-сеть к контейнеру, добавив следующую конфигурацию в службу контейнера.

      services:
    ...
    my-web-app:
        ...
        extra_hosts:
          -  "host.docker.internal:host-gateway"
        ...
    ...

2. Обновите файл /etc/postgresql/12/main/pg_hba.conf.

Если файл не существует в этом каталоге, используйтеfind / -name 'pg_hba.conf'найти его.

Добавьте следующую строку под тегом комментария# IPv4 local connections:

      host    all             all             172.17.0.1/16           md5

3. Обновить/etc/postgresql/12/main/postgresql.conf

Если файл не существует в этом каталоге, используйтеfind / -name 'postgresql.conf'найти его.

найдите следующую строку (строка может быть закомментирована)

      #listen_addresses = 'localhost'

И измените его на следующую строку, чтобы иметь возможность подключаться к postgres с локального хоста и172.17.0.1

      listen_addresses = 'localhost,172.17.0.1'

Вы также можете изменить его на следующее. Но это не рекомендуется для производства, так как база данных будет открыта для всего мира (это означает, что любой IP-адрес может подключиться к базе данных).

      listen_addresses = '*'

Наконец, не забудьте:

  1. Перезапустите службу postgres, используяsudo systemctl restart postgresql
  2. Обновите узел строки подключения доhost.docker.internal

Вы можете добавить несколько адресов для прослушивания для большей безопасности.

      listen_addresses = 'localhost,172.17.0.1'

Добавление listen_addresses = '*' не лучший вариант, который очень опасен и подвергает вашу базу данных postgresql дикой природе.

В Ubuntu:

Сначала вы должны проверить, доступен ли порт базы данных Docker в вашей системе, с помощью следующей команды -

sudo iptables -L -n

Образец ВЫХОДА:

Chain DOCKER (1 references)
target     prot opt source               destination         
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.2           tcp dpt:3306
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.3           tcp dpt:80
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.3           tcp dpt:22

Вот 3306 используется в качестве порта базы данных Docker на 172.17.0.2 IP, если этот порт недоступен, выполните следующую команду -

sudo iptables -A INPUT -p tcp --dport 3306 -j ACCEPT

Теперь вы можете легко получить доступ к базе данных Docker из вашей локальной системы, следуя конфигурации

  host: 172.17.0.2 
  adapter: mysql
  database: DATABASE_NAME
  port: 3307
  username: DATABASE_USER
  password: DATABASE_PASSWORD
  encoding: utf8

В CentOS:

Сначала вы должны проверить, доступен ли порт базы данных Docker в вашем брандмауэре, выполнив следующую команду:

sudo firewall-cmd --list-all

Образец ВЫХОДА:

  target: default
  icmp-block-inversion: no
  interfaces: eno79841677
  sources: 
  services: dhcpv6-client ssh
  **ports: 3307/tcp**
  protocols: 
  masquerade: no
  forward-ports: 
  sourceports: 
  icmp-blocks: 
  rich rules:

Вот 3307 используется в качестве порта базы данных Docker на 172.17.0.2 IP, если этот порт недоступен, выполните следующую команду -

sudo firewall-cmd --zone=public --add-port=3307/tcp

Теперь вы можете легко получить доступ к базе данных Docker из вашей локальной системы с помощью вышеуказанной конфигурации.

На всякий случай вышеперечисленные решения ни у кого не работают. Используйте приведенную ниже инструкцию для подключения из докера к хосту postgres (на Mac):

      psql --host docker.for.mac.host.internal -U postgres

Еще одна вещь, необходимая для моей настройки, это добавить

172.17.0.1  localhost

в /etc/hosts

так что Докер будет указывать на 172.17.0.1 в качестве имени хоста БД, а не полагаться на изменение внешнего ip для поиска БД. Надеюсь, что это поможет кому-то еще в этом вопросе!

Другое решение - это сервисный том. Вы можете определить сервисный том и смонтировать каталог данных PostgreSQL на этом томе. Проверьте данный составной файл для деталей.

version: '2'
services:
  db:   
    image: postgres:9.6.1
    volumes:
      - "/var/lib/postgresql/data:/var/lib/postgresql/data" 
    ports:
      - "5432:5432"

Делая это, другая служба PostgreSQL будет работать в контейнере, но использует тот же каталог данных, который использует служба PostgreSQL.

Другие вопросы по тегам