Разрешить 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
- использование
172.17.0.0/16
как диапазон IP-адресов, а не172.17.0.0/32
, - Не использовать
localhost
для подключения к базе данных PostgreSQL на вашем хосте, но вместо IP-адреса хоста. Чтобы сохранить контейнер переносимым, запустите контейнер с--add-host=database:<host-ip>
пометить и использоватьdatabase
в качестве имени хоста для подключения к PostgreSQL. - Убедитесь, что 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"
Позвольте мне попытаться объяснить, что я сделал.
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 = '*'
Наконец, не забудьте:
- Перезапустите службу postgres, используя
sudo systemctl restart postgresql
- Обновите узел строки подключения до
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.