我最近一直在使用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。localhost
上的连接。在PostgreSQL的配置文件中查找设置listen_addresses
,通常在/etc/postgresql/9.3/main/postgresql.conf
中找到(@DazmoNorton的信用)。172.17.0.0/32
不是一系列IP地址,而是一个地址(namly 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
。
感谢@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的答案很好地解释了这个问题。但Docker for Mac 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地址。
最新版本的docker(18.03)提供内置端口转发解决方案。在docker容器中,只需将db host设置为host.docker.internal
即可。这将被转发给运行docker容器的主机。
有关此文档,请访问:https://docs.docker.com/docker-for-mac/networking/#per-container-ip-addressing-is-not-possible
只需将--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
首先您必须通过以下命令检查系统中的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上的Docker数据库端口,如果此端口不可用运行以下命令 -
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
首先,您必须通过以下命令检查防火墙中的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上的Docker数据库端口,如果此端口不可用运行以下命令 -
sudo firewall-cmd --zone=public --add-port=3307/tcp
在服务器中,您可以永久添加端口
sudo firewall-cmd --permanent --add-port=3307/tcp
sudo firewall-cmd --reload
现在,您可以通过上述配置从本地系统轻松访问Docker数据库。
对于docker-compose,您可以尝试添加
network_mode: "host"
例如:
version: '2'
services:
feedx:
build: web
ports:
- "127.0.0.1:8000:8000"
network_mode: "host"
我的设置需要的另一件事是添加
172.17.0.1 localhost
到/etc/hosts
所以Docker会指向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服务正在使用的相同数据目录。