我最近一直在玩Docker和QGIS,并按照this tutorial中的说明安装了一个容器。
一切都很好,虽然我无法连接到包含我所有GIS数据的localhost postgres数据库。我想这是因为我的postgres数据库没有配置为接受远程连接,并且已经使用this article中的说明编辑了postgres配置文件以允许远程连接。
当我尝试连接到在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
答案 0 :(得分:104)
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
。
答案 1 :(得分:44)
感谢@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地址。
答案 2 :(得分:17)
最新版本的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
答案 3 :(得分:7)
此处发布的解决方案不适用于我。因此,我将发布此答案以帮助面临类似问题的人。
操作系统: 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 i.e. 172.17.0.1 (in my case)
的IP,可以使用:
$> 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
OR
$> 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:现在,使用sudo service postgresql restart
步骤5::请使用host.docker.internal
主机名从服务器应用程序连接数据库。
例如:jdbc:postgresql://host.docker.internal:5432/bankDB
享受!
答案 4 :(得分:2)
只需将--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 :(得分:1)
我的设置还需要添加
error 2017/03/02 06:52:37 [error] 38#38: *89 recv() failed (104: Connection reset by peer) while reading response header from upstream
到172.17.0.1 localhost
这样Docker会指向/etc/hosts
作为数据库主机名,而不是依赖于更改外部IP来查找数据库。希望这可以帮助其他人解决这个问题!
答案 6 :(得分:1)
首先,您必须通过以下命令 -
检查系统中的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数据库。
答案 7 :(得分: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。
答案 8 :(得分:0)
对于docker-compose,您可以尝试添加
network_mode: "host"
示例:
version: '2'
services:
feedx:
build: web
ports:
- "127.0.0.1:8000:8000"
network_mode: "host"
答案 9 :(得分:0)
以防万一,上述解决方案对任何人都不起作用。使用以下语句从 docker 连接到主机 postgres(在 mac 上):
psql --host docker.for.mac.host.internal -U postgres
答案 10 :(得分:0)
让我试着解释一下我做了什么。
首先,我进行了必要的配置,以确保我的 Postgres 数据库接受来自外部的连接。
打开 pg_hba.conf
并在最后添加以下行:
host all all 0.0.0.0/0 md5
打开 postgresql.conf
并查找 listen_addresses
并像这样修改:
listen_addresses = '*'
确保上面的行没有用 #
注释
-> 重启你的数据库
OBS:这不是生产环境的推荐配置
接下来,我查找了我的主人的 ip
。我使用的是 localhosts ip 127.0.0.1
,但容器看不到它,因此在运行容器时会显示有问题的 Connection Refused 消息。在网上对此进行了长时间的搜索后,我读到容器可以看到来自您本地网络的内部 IP(您的路由器归属于连接到它的每个设备,我不是在谈论可以让您访问互联网)。也就是说,我打开了一个终端并执行了以下操作:
打开终端或 CMD
(MacOS/Linux)
$ ifconfig
(视窗)
$ 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
端口是默认的。
访问数据库的配置是:
在settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': ‘myDataBaseName',
'USER': ‘username',
'PASSWORD': '123456',
'HOST': '192.168.0.103',
'PORT': 5432,
}
}
关于 -p
标志:
Connect using network port mapping
关于docker run
:
Docker run documentation
有趣的文章: Docker Tip #35: Connect to a Database Running on Your Docker Host
答案 11 :(得分:-1)
另一种解决方案是服务量,您可以在该卷中定义服务卷并装载主机的PostgreSQL数据目录。查看给定的撰写文件以获取详细信息。
version: '2'
services:
db:
image: postgres:9.6.1
volumes:
- "/var/lib/postgresql/data:/var/lib/postgresql/data"
ports:
- "5432:5432"
通过这样做,另一个PostgreSQL服务将在容器下运行,但使用主机PostgreSQL服务正在使用的相同数据目录。