允许Docker容器连接到本地/主机Postgres数据库


143

我最近一直在研究Docker和QGIS,并按照本教程中的说明安装了一个容器。

尽管我无法连接到包含我的所有GIS数据的localhost postgres数据库,但一切工作都很好。我认为这是因为我的postgres数据库未配置为接受远程连接,并且已经按照本文中的说明编辑了postgres conf文件以允许远程连接。

尝试连接到在Docker中运行QGIS的数据库时,我仍然收到错误消息:无法连接到服务器: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)。我以前使用来查询docker容器docker ps的IP地址,尽管IP地址已更改,但到目前为止,它始终在172.17.0.x范围内

有什么想法为什么我无法连接到该数据库?我想可能很简单!

我正在运行Ubuntu 14.04;Postgres 9.3

Answers:


149

TL; DR

  1. 使用172.17.0.0/16IP地址范围,不是172.17.0.0/32
  2. 不要localhost用来连接主机上的PostgreSQL数据库,而要使用主机的IP。为了使容器具有可移植性,请--add-host=database:<host-ip>使用标志启动容器并database用作连接到PostgreSQL的主机名。
  3. 确保将PostreSQL配置为侦听所有IP地址上的连接,而不仅仅是侦听localhostlisten_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


1
谢谢您的评论。我将我pg_hba.conf的地址更改为您建议的地址,但是在停止并重新启动postgres服务后,仍然收到相同的连接错误消息。我已经在ipv4连接下添加了该行-我应该在其他地方添加您建议的地址吗?另外,在运行于Docker的QGIS应用程序中,是否需要更改postgres连接信息?例如,如果我从Docker容器内进行连接,主机是否仍为“ localhost”?
marty_c 2015年

啊,这很重要。不,localhost不是您的Docker容器内的主机系统。尝试连接到主机系统的公共IP地址。为了保持容器的可移植性,您还可以使用来启动容器,--add-host=database:<host-ip>并简单地database用作主机名,以从Docker容器中连接到PostgreSQL主机。
helmbert

6
我还需要一件。我还必须编辑/etc/postgresql/9.3/main/postgresql.conf服务器的eth0IP地址并将其添加到listen_addresses。默认情况下listen_addresses,postgres localhost仅绑定到。
Dzamo Norton

@DzamoNorton,谢谢您的提示!我相应地更新了我的答案。
helmbert

@helmbert host-ip是虚拟机或Docker 容器的IP地址吗?
D先生

56

Docker for Mac解决方案

17.06起

感谢@Birchlabs的评论,现在有了这个专用于Mac的特殊DNS名称,现在可以轻松得多:

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的答案很好地解释了这个问题。但是适用于Mac的Docker 并未公开桥接网络,因此我必须执行以下技巧来解决此限制:

$ 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
截至2017年4月4日,这仍然有效吗?
Petrus Theron

我喜欢这种方式不会公开数据库。顺便说一句,我可以在CentOS上使用它吗?我收到错误消息:alias:尝试使用您提供的alias命令时主机未知。
崇武(Dsung Goh)

6
从Docker 17.06.0-rc1-ce-mac13开始(2017年6月1日),在macOS上有更好的方法。容器识别主机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开始已更改,其他选项仍然可用,但已弃用(Source)。
gseva

44

适用于mac的简单解决方案:

最新版本的docker(18.03)提供了内置的端口转发解决方案。在您的Docker容器内部,只需将db host设置为host.docker.internal。这将转发到运行Docker容器的主机。

此处的文档位于:https : //docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host


3
这是迄今为止最好的答案!更容易,应该如何。
bjm88 '18年

2
host.docker.internal仅限于Mac电脑?
Dragas

@Dragas根据文档显示,它“将无法在Mac之外运行”,但是Docker for Windows文档中提到了相同的DNS名称,因此我认为仅限于“ Docker for ...”。无论哪种方式,它都只适用于开发:您无意发布使用此功能的docker映像。
大黄

仅适用于Windows和Mac。就我而言,ubuntu无法正常工作
Azri Zakaria

16

简单的解决方案

只需添加--network=hostdocker run。就这样!

这样,容器将使用主机的网络,所以localhost127.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

适用于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被用作泊坞数据库端口上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被用作泊坞数据库端口上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数据库 -这是错误的方法。他有一个本地数据库,还有一个尝试将其连接到本地数据库的
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"

要查找Docker的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

请享用!!



1

要设置一些简单的方法,以允许 Docker容器到我的本地主机的Postgresql连接,我在postgresql.conf中使用了以下方法:

listen_addresses = '*'

并添加了这个pg_hba.conf:

host    all             all             172.17.0.0/16           password

然后重新启动。然后,来自 docker容器(位于172.17.0.2)的客户端可以使用host:password,数据库,用户名和密码连接到在本地主机上运行的Postgresql。


0

我的设置需要做的另一件事是添加

172.17.0.1  localhost

/etc/hosts

因此Docker将指向172.17.0.1DB主机名,而不依赖于变化的外部ip来查找数据库。希望这对其他人有帮助!


14
这是一个不好的解决方案。Localhost通常应指向127.0.0.1。更改它可能会产生不希望的后果,即使在这种情况下它可以起作用。
亚历克斯(Alex)

2
更好的方法是在运行容器时设置database主机--add-host=database:172.17.0.1。然后将您的应用指向该主机。这样可以避免对容器内的IP地址进行硬编码。
jaredsk '17

1
--add-host=database:172.17.0.1是更好的选择
Luis Martins '18

-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

我认为停止主机服务可以解决这种情况。
rishi
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.