我最近一直在使用Docker和QGIS,并按照本教程中的说明安装了一个容器。
一切都很好,尽管我无法连接到包含我所有GIS数据的本地主机postgres数据库。我想这是因为我的postgres数据库没有配置为接受远程连接,并且一直在编辑postgres conf文件以允许使用本文中的说明进行远程连接。
I'm still getting an error message when I try and connect to my database running QGIS in Docker: could not connect to server: Connection refused Is the server running on host "localhost" (::1) and accepting TCP/IP connections to port 5433?
The postgres server is running, and I've edited my pg_hba.conf file to allow connections from a range of IP addresses (172.17.0.0/32). I had previously queried the IP address of the docker container using docker ps and although the IP address changes, it has so far always been in the range 172.17.0.x
知道为什么我无法连接到这个数据库吗?我想可能是非常简单的事情!
我运行的是Ubuntu 14.04;Postgres 9.3
博士TL;
Use 172.17.0.0/16 as IP address range, not 172.17.0.0/32.
Don't use localhost to connect to the PostgreSQL database on your host, but the host's IP instead. To keep the container portable, start the container with the --add-host=database:<host-ip> flag and use database as hostname for connecting to PostgreSQL.
Make sure PostgreSQL is configured to listen for connections on all IP addresses, not just on localhost. Look for the setting listen_addresses in PostgreSQL's configuration file, typically found in /etc/postgresql/9.3/main/postgresql.conf (credits to @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。
Mac解决方案的Docker
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/ postgresql.conf,编辑change 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的IP地址,而不是docker0网络接口。
在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地址的“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
In 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地址的“Docker数据库端口”,如果没有此端口执行以下命令-
sudo firewall-cmd --zone=public --add-port=3307/tcp
在服务器端,可以永久添加端口
sudo firewall-cmd --permanent --add-port=3307/tcp
sudo firewall-cmd --reload
现在,您可以通过上述配置轻松地从本地系统访问Docker数据库。
这里发布的解决方案对我不起作用。因此,我张贴这个答案来帮助那些面临类似问题的人。
注意:此解决方案也适用于Windows 10,请检查下面的评论。
操作系统: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,即172.17.0.1(在我的情况下),你可以使用:
$> 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
step2:在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。是否
享受! !
让我解释一下我做了什么。
Postgresql
首先,我做了必要的配置,以确保我的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(你的路由器将它属性为连接到它的每个设备,我不是在谈论让你访问互联网的ip)。也就是说,我打开了一个终端,做了以下事情:
查找本地网络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。
Django应用程序
访问数据库的配置如下:
在settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': ‘myDataBaseName',
'USER': ‘username',
'PASSWORD': '123456',
'HOST': '192.168.0.103',
'PORT': 5432,
}
}
参考文献
关于-p标志:
使用网口映射进行连接
关于docker run:
Docker运行文档
有趣的文章:
Docker提示#35:连接到运行在Docker主机上的数据库
你可以在docker运行命令时通过——network=host来访问容器内的localhost。
Ex:
docker run --network=host docker-image-name:latest
如果你想传递环境变量与localhost使用——env-file参数来访问容器内的环境变量。
Ex:
docker run --network=host --env-file .env-file-name docker-image-name:latest
注意:在docker镜像名称之前传递参数,否则参数将无效。(我面对过这个问题,所以要小心!)
3步解决方案
1. 更新docker-compose文件
首先,由于数据库是本地的,我们需要通过向容器服务添加以下配置来将主机网络绑定到容器
services:
...
my-web-app:
...
extra_hosts:
- "host.docker.internal:host-gateway"
...
...
2. 更新/etc/postgresql/12/main/pg_hba.conf
如果这个目录下不存在这个文件,使用find / -name 'pg_hba.conf'来找到它。
在注释标签# IPv4本地连接下添加以下一行:
host all all 172.17.0.1/16 md5
3.更新/etc/postgresql/12/main/postgresql.conf
如果这个目录下不存在这个文件,使用find / -name 'postgresql.conf'找到它。
找到下面的行(这行可能有注释)
#listen_addresses = 'localhost'
并将其更改为以下一行,以便能够从localhost和172.17.0.1连接到postgres
listen_addresses = 'localhost,172.17.0.1'
您还可以将其更改为如下所示,但不建议在生产环境中这样做,因为它将向世界公开数据库(意味着任何IP地址都可以连接到数据库)
listen_addresses = '*'
最后别忘了:
使用sudo systemctl Restart postgresql重新启动postgress服务
将连接字符串host更新为host.docker.internal