问题描述
我最近一直在使用Docker和QGIS并按照this tutorial中的说明安装了一个容器。
尽管我无法连接到包含我的所有GIS数据的localhost postgres数据库,但一切工作都很好。我认为这是因为我的postgres数据库未配置为接受远程连接,并且已经使用this article中的指令编辑了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 ps
查询docker容器的IP地址,尽管IP地址已更改,但到目前为止,它始终在172.17.0.x范围内
有什么想法为什么我无法连接到该数据库?我想象的可能很简单!
我正在运行Ubuntu 14.04; Postgres 9.3
最佳方案
长话短说
-
使用
172.17.0.0/16
作为IP地址范围,而不是172.17.0.0/32
。 -
不要使用
localhost
连接到主机上的PostgreSQL数据库,而要使用主机的IP。为了使容器可移植,请使用--add-host=database:<host-ip>
标志启动容器,并使用database
作为连接到PostgreSQL的主机名。 -
确保PostreSQL配置为侦听所有IP地址上的连接,而不仅仅是
localhost
上的连接。在PostgreSQL的配置文件中查找设置listen_addresses
,通常在/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
。
次佳方案
Docker for Mac解决方案
17.06起
感谢@Birchlabs的评论,现在使用special Mac-only DNS name available可以轻松得多:
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
。有关详细信息,请参见release note。
旧版
@helmbert的答案很好地解释了这个问题。但是适用于Mac的Docker does not expose the bridge network,所以我不得不做这个技巧来解决该限制:
$ 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地址。
第三种方案
适用于mac的简单解决方案:
最新版本的docker(18.03)提供了内置的端口转发解决方案。在您的Docker容器内部,只需将数据库主机设置为host.docker.internal
即可。这将转发到运行Docker容器的主机。
第四种方案
简单的解决方案
只需将--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