Дозвольте контейнеру докера підключитися до локальної / хост-бази даних postgres


143

Нещодавно я бавився з Docker та QGIS і встановив контейнер, дотримуючись інструкцій у цьому підручнику .

Все працює чудово, хоча я не в змозі підключитися до бази даних postgres localhost, яка містить усі мої дані ГІС. Я вважаю, що це тому, що моя база даних postgres не налаштована на прийняття віддалених з'єднань і редагувала файли confg 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 psі хоча IP-адреса змінюється, вона досі завжди знаходилася в діапазоні 172.17.0.x

Будь-які ідеї, чому я не можу підключитися до цієї бази даних? Напевно, щось дуже просте я собі уявляю!

Я запускаю Ubuntu 14.04; Постгрес 9.3

Відповіді:


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-адрес, а одна адреса (що називається 172.17.0.0). Жоден Docker-контейнер ніколи не отримає вказану адресу, оскільки це мережева адреса docker0інтерфейсу Docker bridge ( ).

Коли Докер запуститься, він створить новий мережевий інтерфейс мосту, який ви можете легко бачити при виклику 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.


1
Ей, дякую за ваші коментарі. Я змінив pg_hba.confадресу, яку ви запропонували, але все-таки отримую те саме повідомлення про помилку підключення після зупинки та перезапуску служби Postgres. Я додав рядок під мої ipv4-з'єднання - чи є ще десь я повинен додати запропоновану вами адресу? Крім того, мені в додатку QGIS, який працює в Докер, потрібно змінити інформацію про з'єднання після пошти? Наприклад, якщо я підключаюсь зсередини докерного контейнера, хост все ще є "localhost"?
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_addressesмає лише postgres, прив’язаний до localhost.
Дзамо Нортон

@DzamoNorton, дякую за підказку! Я відповідно оновив свою відповідь.
гельберт

@helmbert host-ip- це ip-адреса віртуальної машини чи контейнера докера ?
Mr.D

56

Докер для 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. Докладніше див. У примітці до випуску .

Старіша версія

@ відповідь Гельберта добре пояснює проблему. Але 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мережного інтерфейсу.


3
Це все ще актуально станом на 4 квітня 2017 року?
Петрус Терон

Мені подобається такий спосіб, який не буде виставляти базу даних. BTW, чи можу я це використовувати на CentOS? Я отримав помилку: alias: Невідомий хост, коли я намагався використовувати команду alias, яку ви надаєте.
Tsung Goh

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, інші варіанти все ще доступні, але застарілі ( Джерело ).
gseva

44

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

Найновіша версія докера (18.03) пропонує вбудоване рішення для переадресації портів. Всередині контейнера докера просто встановіть хост 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. У моєму випадку ubuntu не працює
Azri Zakaria

16

Просте рішення

Просто додайте --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/isissue/2716
jfcorugedo

Працює над 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 з вашої локальної системи за вказаною вище конфігурацією.


Я знаю, що це старе, але тепер ви можете легко отримати доступ до бази даних Docker з вашої локальної системи, дотримуючись конфігурації - у вас це не так. У нього є локальна база даних та докерська програма, яка намагається підключитися до цього локального db не навпаки
Craicerjack

2

Розміщене тут рішення не працює для мене. Тому я публікую цю відповідь, щоб допомогти комусь, хто стикається з подібною проблемою.

ОС: Ubuntu 18
PostgreSQL: 9.5 (розміщений на Ubuntu)
Докер: серверна програма (яка підключається до 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

Насолоджуйтесь !!



1

Щоб налаштувати щось просте, що дозволяє з'єднання Postgresql з контейнера docker до мого localhost, я використовував це в postgresql.conf:

listen_addresses = '*'

І додав цей pg_hba.conf:

host    all             all             172.17.0.0/16           password

Потім зробіть перезапуск. Мій клієнт із контейнера docker (який був на 172.17.0.2) міг потім підключитися до Postgresql, що працює на моєму локальному хості, використовуючи хост: пароль, базу даних, ім’я користувача та пароль.


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.


1
Це, ймовірно, спричинить конфлікти при записі із запущеним сервером PostgreSQL хосту
Petrus Theron

Я думаю, що припинення послуги хосту вирішить проблему в такому випадку.
Хріші
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.