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

143

Недавно я играл с 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

marty_c
источник

Ответы:

149

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-адресов, а один адрес (namly 172.17.0.0). Ни один контейнер Docker никогда не получит этот адрес, потому что это сетевой адрес docker0интерфейса Docker bridge ( ).

Когда 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.

helmbert
источник
1
эй спасибо за ваши комментарии Я изменил свой pg_hba.confадрес на предложенный вами, но все равно получаю то же сообщение об ошибке подключения после остановки и перезапуска службы postgres. Я добавил строку под своими соединениями ipv4 - где-то еще я должен добавить адрес, который вы предлагаете? Или в моем приложении QGIS, работающем в Docker, мне нужно изменить информацию о соединении postgres? Например, если я подключаюсь из контейнера докера, хост все еще является «локальным»?
marty_c
Ах, это важный момент. Нет, localhostэто не хост-система внутри вашего контейнера Docker. Попробуйте подключиться к общедоступному IP-адресу хост-системы. Чтобы сохранить контейнер переносимым, вы также можете запустить контейнер с --add-host=database:<host-ip>и просто использовать в databaseкачестве имени хоста для подключения к вашему хосту PostgreSQL из контейнера Docker.
Helmbert
6
Мне нужен был еще один кусок. Я также должен был отредактировать /etc/postgresql/9.3/main/postgresql.confи добавить eth0IP-адрес моего сервера в listen_addresses. По умолчанию listen_addressespostgres имеет привязку localhostтолько к.
Дзамо Нортон
@DzamoNorton, спасибо за подсказку! Я обновил свой ответ соответственно.
helmbert
@helmbert host-ip- это IP-адрес виртуальной машины или контейнера Docker ?
17
56

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

17.06 года

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

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

Начиная с 17.12.0-cd-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, но lo0вместо docker0сетевого интерфейса используется IP-адрес, к которому он привязан .

baxang
источник
3
Это все еще актуально на 4 апреля 2017 года?
Петрус Терон
Мне нравится этот способ, который не будет выставлять базу данных. Кстати, я могу использовать это на CentOS? Я получил ошибку: псевдоним: неизвестный хост, когда я пытался использовать предоставленную вами команду псевдонима.
Цунг Го
6
На MacOS есть лучший способ, начиная с Docker 17.06.0-rc1-ce-mac13 (1 июня 2017 г.). Контейнеры распознают хост docker.for.mac.localhost. это IP вашего хост-компьютера. ищите его запись в базе данных хоста контейнера следующим образом: docker run alpine /bin/sh -c 'getent hosts docker.for.mac.localhost'
Birchlabs
@Birchlabs Это так здорово!
qqilihq
5
Похоже, что он изменился host.docker.internalс 18.03, другие опции все еще доступны, но устарели ( Источник ).
Гсева
44

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

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

Документация для этого здесь: https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host

Крис
источник
3
Это, безусловно, лучший ответ сейчас! так проще и так и должно быть.
bjm88
2
это host.docker.internalограничивается только Маков?
Драгас
@Dragas, согласно документам, «не будет работать за пределами Mac», но то же имя DNS упоминается в документах для Docker для Windows, поэтому я думаю, что оно ограничено «Docker для ...». В любом случае, это только для разработки: вы не должны отправлять образ докера, который использует это.
ревень
Работает только с Windows и Mac. В моем случае убунту не работает
Азри Закария
17

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

Просто добавь --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
Макс Малыш
источник
1
Быть осторожен! Это правильное решение, на мой взгляд, не работает для macOS. Не тратьте свое время, пытаясь понять, почему это не работает. Взгляните на: github.com/docker/for-mac/issues/2716
jfcorugedo
1
Работает на Debian. Попытался изменить postgresql.conf и pg_hba.conf, но это проще и быстрее.
frmbelz
2

В 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

На сервере Вы можете добавить порт навсегда

sudo firewall-cmd --permanent --add-port=3307/tcp
sudo firewall-cmd --reload

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

Sanaulla
источник
Я знаю, что это старо, но сейчас, вы можете легко получить доступ к базе данных Docker из вашей локальной системы, следуя конфигурации - у вас это неправильно. У него есть локальная база данных и приложение-докер, пытающееся подключиться к этой локальной базе данных, а не наоборот
Крейсерджек,
2

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

ОС: 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 = '*'

ШАГ 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

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

singhpradeep
источник
1

для 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/#network_mode

Сарат Ак
источник
4
добавив networkd_mode к хосту, разорвите соединение между другими контейнерами
Bawantha
1

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

listen_addresses = '*'

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

host    all             all             172.17.0.0/16           password

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

Харлин
источник
0

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

172.17.0.1  localhost

в /etc/hosts

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

Микко Пёри
источник
14
Это плохое решение. Localhost обычно должен указывать на 127.0.0.1. Его изменение может иметь нежелательные последствия, даже если в данном конкретном случае это работает.
Алекс
2
Лучший способ - настроить databaseхост --add-host=database:172.17.0.1при запуске контейнера. Затем укажите ваше приложение на этот хост. Это позволяет избежать жесткого кодирования IP-адреса внутри контейнера.
Jaredsk
1
--add-host=database:172.17.0.1предпочтительно
Луис Мартинс
-3

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

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

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

Hrishi
источник
1
Это, вероятно, вызовет конфликты записи с работающим хост-сервисом PostgreSQL
Petrus Theron
Я думаю, что остановка службы хоста решит проблему в этом случае.
Хриши