Разрешить контейнер 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
Ответы
Ответ 1
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-адресов, а единственным адресом (namly 172.17.0.0
). Контейнер Docker никогда не получит этот адрес, потому что это сетевой адрес интерфейса Docker bridge (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
.
Ответ 2
Решение 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, но использует IP-адрес, который присоединен к lo0
вместо сетевого интерфейса docker0
.
Ответ 3
Простое решение для Mac:
Новейшая версия Docker (18.03) предлагает встроенное решение для переадресации портов. Внутри вашего docker-контейнера просто установите для хоста db значение host.docker.internal
. Это будет перенаправлено на хост, на котором работает контейнер докеров.
Документация для этого здесь: https://docs.docker.com/docker-for-mac/networking/#per-container-ip-addressing-is-not-possible
Ответ 4
Простое решение
Просто добавьте --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
Ответ 5
В 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 из вашей локальной системы с помощью вышеуказанной конфигурации.
Ответ 6
для 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
Ответ 7
Еще одна вещь, необходимая для моей установки, заключалась в том, чтобы добавить
172.17.0.1 localhost
to /etc/hosts
чтобы Docker указывал на 172.17.0.1
как имя узла БД и не полагался на изменение внешнего ip для поиска БД. Надеюсь, это поможет кому-то еще с этой проблемой!
Ответ 8
Чтобы настроить что-то простое, разрешающее соединение 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: пароль, базу данных, имя пользователя и пароль.
Ответ 9
Другим решением является уровень обслуживания. Вы можете определить том службы и установить каталог данных PostgreSQL Host в том томе. Подробнее см. Данный файл компоновки.
version: '2'
services:
db:
image: postgres:9.6.1
volumes:
- "/var/lib/postgresql/data:/var/lib/postgresql/data"
ports:
- "5432:5432"
Таким образом, другая служба PostgreSQL будет работать под контейнером, но использует тот же каталог данных, который использует служба PostgreSQL.