允许docker容器连接到本地/主机postgres数据库

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

一切都很好,尽管我无法连接到包含我所有GIS数据的本地主机postgres数据库。我认为这是因为我的postgres数据库没有配置为接受远程连接,并且一直在编辑postgres conf文件,以允许使用这篇文章中的指令进行远程连接。

我仍然得到一个错误消息,当我尝试连接到我的数据库运行在Docker:无法连接到服务器: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

273950 次浏览

博士TL;

  1. 使用172.17.0.0/16作为IP地址范围,而不是172.17.0.0/32
  2. 不要使用localhost连接到主机上的PostgreSQL数据库,而是使用主机的IP连接。为了保持容器的可移植性,使用--add-host=database:<host-ip>标志启动容器,并使用database作为连接到PostgreSQL的主机名。
  3. 确保PostgreSQL配置为监听所有IP地址上的连接,而不仅仅是在localhost上。在PostgreSQL的配置文件中寻找设置listen_addresses,通常在/etc/postgresql/9.3/main/postgresql.conf (credit 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/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地址。

我的设置还需要添加一个东西

172.17.0.1  localhost

/etc/hosts

这样Docker就会指向172.17.0.1作为DB的主机名,而不是依赖于一个变化的外部ip来找到DB。希望这能帮助其他人解决这个问题!

另一种解决方案是服务卷,您可以定义一个服务卷,并将主机的PostgreSQL Data目录挂载在该卷中。查看给定的合成文件以获得详细信息。

version: '2'
services:
db:
image: postgres:9.6.1
volumes:
- "/var/lib/postgresql/data:/var/lib/postgresql/data"
ports:
- "5432:5432"

通过这样做,另一个PostgreSQL服务将运行在容器下,但使用与主机PostgreSQL服务使用的相同的数据目录。

简单的解决方案

docker的最新版本(18.03)提供了一个内置的端口转发解决方案。在docker容器中,只需将db主机设置为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

在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

在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数据库。

简单的解决方案

只需将--network=host添加到docker 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

对于docker-compose,您可以尝试只添加

network_mode: "host"

例子:

version: '2'
services:
feedx:
build: web
ports:
- "127.0.0.1:8000:8000"
network_mode: "host"

https://docs.docker.com/compose/compose-file/#network_mode

为了建立一些简单的东西,允许Postgresql连接 docker容器到我的本地主机,我在Postgresql .conf中使用了这个:

listen_addresses = '*'

并添加了这个pg_hba.conf:

host    all             all             172.17.0.0/16           password

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

这里发布的解决方案对我不起作用。因此,我张贴这个答案来帮助那些面临类似问题的人。

请注意:此解决方案也适用于Windows 10,请检查下面的评论。

< p >操作系统:Ubuntu 18 < br > PostgreSQL: 9.5(在Ubuntu上托管) < br > 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

$> 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

在postgresql.conf中,将listen_addresses修改为listen_addresses = '*'

步骤3:在pg_hba.conf中添加这一行

host    all             all             0.0.0.0/0               md5

现在使用sudo service postgresql restart重新启动postgresql服务

步骤5:请使用host.docker.internal主机名从服务器应用程序连接数据库 例:jdbc:postgresql://host.docker.internal:5432/bankDB < / p >

享受! !

以防万一,上述解决方案并不适用于任何人。使用以下语句从docker连接到主机postgres(在mac上):

psql --host docker.for.mac.host.internal -U postgres

让我解释一下我做了什么。

Postgresql

首先,我做了必要的配置,以确保我的Postgres数据库接受来自外部的连接。

打开pg_hba.conf并在最后添加以下行:

host    all             all             0.0.0.0/0               md5

打开postgresql.conf并寻找listen_addresses并像这样修改:

listen_addresses = '*'

确保上面的行没有被#注释

→重新启动数据库

奥林匹克广播服务公司< <强> / >强:这不是生产环境的推荐配置

接下来,我寻找主机的ip。我使用的是localhosts ip 127.0.0.1,但容器没有看到它,所以在运行容器时显示有问题的连接拒绝消息。在网上搜索了很长一段时间后,我读到容器看到了来自本地网络的内部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标志: 使用网口映射进行连接 < / p > 关于docker run < p >: Docker运行文档 < / p > < p >有趣的文章: Docker提示#35:连接到运行在Docker主机上的数据库 < / p >

您可以添加多个监听地址,以提高安全性。

listen_addresses = 'localhost,172.17.0.1'

添加listen_addresses = '*'并不是一个好的选择,这是非常危险的,并且会将你的postgresql数据库暴露在蛮荒的西部。

你可以在docker run命令中传递--network=host来访问容器内的localhost

例:

docker run --network=host docker-image-name:latest

如果你想通过localhost传递env变量,使用--env-file参数来访问容器内的环境变量。

例:

docker run --network=host --env-file .env-file-name docker-image-name:latest

注意:在docker镜像名称之前传递参数,否则参数将无效。(我面对过这个问题,所以要小心!)