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

时间:2015-07-06 14:57:42

标签: ubuntu docker postgresql-9.3 qgis

我最近一直在玩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

12 个答案:

答案 0 :(得分:104)

TL; DR

  1. 使用172.17.0.0/16作为IP地址范围,而不是172.17.0.0/32
  2. 不要使用localhost连接到主机上的PostgreSQL数据库,而是使用主机的IP。要使容器保持可移植性,请使用--add-host=database:<host-ip>标志启动容器,并使用database作为主机名以连接到PostgreSQL。
  3. 确保将PostreSQL配置为侦听所有IP地址上的连接,而不仅仅是localhost上的连接。在PostgreSQL的配置文件中查找设置listen_addresses,通常在/etc/postgresql/9.3/main/postgresql.conf中找到(@DazmoNorton的信用)。
  4. 长版

    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)

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的回答很好地解释了这个问题。但是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)

mac的简单解决方案:

最新版本的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

重新启动postgresql服务。

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

享受!

答案 4 :(得分:2)

简单解决方案

只需将--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

答案 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)

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

答案 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"

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

答案 9 :(得分:0)

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

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

答案 10 :(得分:0)

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

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

打开终端或 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 标志: Connect using network port mapping

关于docker runDocker 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服务正在使用的相同数据目录。