简体   繁体   English

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

[英]Allow docker container to connect to a local/host postgres database

I've recently been playing around with Docker and QGIS and have installed a container following the instructions in this tutorial .我最近一直在玩弄 Docker 和 QGIS,并按照本教程中的说明安装了一个容器。

Everything works great, although I am unable to connect to a localhost postgres database that contains all my GIS data.一切都很好,尽管我无法连接到包含我所有 GIS 数据的本地主机 postgres 数据库。 I figure this is because my postgres database is not configured to accept remote connections and have been editing the postgres conf files to allow remote connections using the instructions in this article .我想这是因为我的 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?当我尝试连接到在 Docker 中运行 QGIS 的数据库时,我仍然收到一条错误消息:无法连接到服务器: 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). postgres 服务器正在运行,我编辑了pg_hba.conf文件以允许来自 IP 地址范围 (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我之前使用docker ps查询过 docker 容器的 IP 地址,尽管 IP 地址发生变化,但到目前为止它一直在 172.17.0.x 范围内

Any ideas why I can't connect to this database?为什么我无法连接到这个数据库有什么想法吗? Probably something very simple I imagine!可能是我想象的非常简单的东西!

I'm running Ubuntu 14.04;我正在运行 Ubuntu 14.04; Postgres 9.3 Postgres 9.3

TL;DR TL; 博士

  1. Use 172.17.0.0/16 as IP address range, not 172.17.0.0/32 .使用172.17.0.0/16作为 IP 地址范围,而不是172.17.0.0/32
  2. Don't use localhost to connect to the PostgreSQL database on your host, but the host's IP instead.不要使用localhost连接到主机上的 PostgreSQL 数据库,而是使用主机的 IP。 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.为了保持容器的可移植性,请使用--add-host=database:<host-ip>标志启动容器,并使用database作为主机名连接到 PostgreSQL。
  3. Make sure PostgreSQL is configured to listen for connections on all IP addresses, not just on localhost .确保 PostgreSQL 配置为侦听所有 IP 地址上的连接,而不仅仅是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).在 PostgreSQL 的配置文件中查找设置listen_addresses ,通常可以在/etc/postgresql/9.3/main/postgresql.conf找到(归功于 @DazmoNorton)。

Long version长版

172.17.0.0/32 is not a range of IP addresses, but a single address (namly 172.17.0.0 ). 172.17.0.0/32不是 IP 地址范围,而是单个地址(即172.17.0.0 )。 No Docker container will ever get that address assigned, because it's the network address of the Docker bridge ( docker0 ) interface.没有 Docker 容器会获得分配的地址,因为它是 Docker 网桥 ( docker0 ) 接口的网络地址。

When Docker starts, it will create a new bridge network interface, that you can easily see when calling ip a :当 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

As you can see, in my case, the docker0 interface has the IP address 172.17.42.1 with a netmask of /16 (or 255.255.0.0 ).如您所见,就我而言, docker0接口的 IP 地址为172.17.42.1 ,网络掩码为/16 (或255.255.0.0 )。 This means that the network address is 172.17.0.0/16 .这意味着网络地址是172.17.0.0/16

The IP address is randomly assigned, but without any additional configuration, it will always be in the 172.17.0.0/16 network. IP 地址是随机分配的,但无需任何额外配置,它将始终在172.17.0.0/16网络中。 For each Docker container, a random address from that range will be assigned.对于每个 Docker 容器,将分配该范围内的一个随机地址。

This means, if you want to grant access from all possible containers to your database, use 172.17.0.0/16 .这意味着,如果您想从所有可能的容器中授予对数据库的访问权限,请使用172.17.0.0/16

Simple Solution简单的解决方案

The newest version of docker (18.03) offers a built in port forwarding solution.最新版本的 docker (18.03) 提供了一个内置的端口转发解决方案。 Inside your docker container simply have the db host set to host.docker.internal .在您的host.docker.internal容器内,只需将 db 主机设置为host.docker.internal This will be forwarded to the host the docker container is running on.这将被转发到运行 docker 容器的主机。

Documentation for this is here: https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host相关文档在这里: https : //docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host

Docker for Mac solution Docker for Mac 解决方案

17.06 onwards 17.06 起

Thanks to @Birchlabs' comment, now it is tons easier with this special Mac-only DNS name available :感谢@Birchlabs 的评论,现在有了这个仅适用于 Mac 的特殊 DNS 名称,事情变得更容易了:

docker run -e DB_PORT=5432 -e DB_HOST=docker.for.mac.host.internal

From 17.12.0-cd-mac46, docker.for.mac.host.internal should be used instead of docker.for.mac.localhost .从17.12.0-CD-mac46, docker.for.mac.host.internal应该用来代替docker.for.mac.localhost See release note for details.有关详细信息,请参阅发行说明

Older version旧版本

@helmbert's answer well explains the issue. @helmbert 的回答很好地解释了这个问题。 But Docker for Mac does not expose the bridge network , so I had to do this trick to workaround the limitation:但是 Docker for Mac 没有公开桥接网络,所以我不得不用这个技巧来解决这个限制:

$ sudo ifconfig lo0 alias 10.200.10.1/24

Open /usr/local/var/postgres/pg_hba.conf and add this line:打开/usr/local/var/postgres/pg_hba.conf并添加以下行:

host    all             all             10.200.10.1/24            trust

Open /usr/local/var/postgres/postgresql.conf and edit change listen_addresses :打开/usr/local/var/postgres/postgresql.conf并编辑更改listen_addresses

listen_addresses = '*'

Reload service and launch your container:重新加载服务并启动您的容器:

$ PGDATA=/usr/local/var/postgres pg_ctl reload
$ docker run -e DB_PORT=5432 -e DB_HOST=10.200.10.1 my_app 

What this workaround does is basically same with @helmbert's answer, but uses an IP address that is attached to lo0 instead of docker0 network interface.此解决方法的作用与@helmbert 的答案基本相同,但使用附加到lo0而不是docker0网络接口的 IP 地址。

Simple solution简单的解决方案

Just add --network=host to docker run .只需将--network=host添加到--network=host docker run That's all!就这样!

This way container will use the host's network, so localhost and 127.0.0.1 will point to the host (by default they point to a container).这样容器将使用主机的网络,因此localhost127.0.0.1将指向主机(默认情况下它们指向一个容器)。 Example:例子:

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

The solution posted here does not work for me.此处发布的解决方案对我不起作用。 Therefore, I am posting this answer to help someone facing similar issue.因此,我发布此答案以帮助面临类似问题的人。

Note : This solution works for Windows 10 as well, please check comment below.注意:此解决方案也适用于 Windows 10,请查看下面的评论。

OS: Ubuntu 18操作系统: Ubuntu 18
PostgreSQL: 9.5 (Hosted on Ubuntu) PostgreSQL: 9.5(在 Ubuntu 上托管)
Docker: Server Application (which connects to PostgreSQL) Docker:服务器应用程序(连接到 PostgreSQL)

I am using docker-compose.yml to build application.我正在使用 docker-compose.yml 来构建应用程序。

STEP 1: Please add host.docker.internal:<docker0 IP>第 1 host.docker.internal:<docker0 IP> 请添加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"

To find IP of docker ie 172.17.0.1 (in my case) you can use:要查找ie 172.17.0.1 (in my case) IP, ie 172.17.0.1 (in my case)您可以使用:

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

STEP 2: In postgresql.conf, change listen_addresses to listen_addresses = '*'第 2在 postgresql.conf 中,将 listen_addresses 更改为listen_addresses = '*'

STEP 3: In pg_hba.conf, add this line第 3在 pg_hba.conf 中,添加这一行

host    all             all             0.0.0.0/0               md5

STEP 4: Now restart postgresql service using, sudo service postgresql restart第 4现在使用重新启动 postgresql 服务, sudo service postgresql restart

STEP 5: Please use host.docker.internal hostname to connect database from Server Application.第 5 host.docker.internal 请使用host.docker.internal主机名从服务器应用程序连接数据库。
Ex: jdbc:postgresql://host.docker.internal:5432/bankDB例如: jdbc:postgresql://host.docker.internal:5432/bankDB

Enjoy!!享受!!

you can pass --network=host during docker run command to access localhost inside container.您可以在 docker docker run命令期间传递--network=host以访问容器内的localhost

Ex:前任:

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

In case you want to pass env variables with localhost use --env-file paramater to access environment variables inside container.如果您想使用本地主机传递环境变量,请使用--env-file参数来访问容器内的环境变量。

Ex:前任:

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

Note: pass the parameters before docker image name otherwise parameters will not work.注意:在 docker image name 之前传递参数,否则参数将不起作用。 (I faced this, so heads up!) (我遇到过这个,所以请注意!)

for docker-compose you can try just add对于 docker-compose,您可以尝试添加

network_mode: "host"

example :例子 :

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 https://docs.docker.com/compose/compose-file/#network_mode

To set up something simple that allows a Postgresql connection from the docker container to my localhost I used this in postgresql.conf:为了设置一些简单的东西,允许docker 容器到我的本地主机的 Postgresql 连接,我在 postgresql.conf 中使用了这个:

listen_addresses = '*'

And added this pg_hba.conf:并添加了这个 pg_hba.conf:

host    all             all             172.17.0.0/16           password

Then do a restart.然后重新启动。 My client from the docker container (which was at 172.17.0.2) could then connect to Postgresql running on my localhost using host:password, database, username and password.我的来自docker 容器的客户端(位于 172.17.0.2)然后可以使用主机:密码、数据库、用户名和密码连接到在我的本地主机上运行的 Postgresql。

You can add multiple listening address for better security.您可以添加多个监听地址以获得更好的安全性。

listen_addresses = 'localhost,172.17.0.1'

Adding listen_addresses = '*' isn't a good option, which is very dangerous and expose your postgresql database to the wild west.添加listen_addresses = '*'不是一个好的选择,这非常危险并且会将您的 postgresql 数据库暴露在狂野的西部。

In Ubuntu:在 Ubuntu 中:

First You have to check that is the Docker Database port is Available in your system by following command -首先,您必须通过以下命令检查系统中的 Docker 数据库端口是否可用 -

sudo iptables -L -n

Sample OUTPUT:示例输出:

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

Here 3306 is used as Docker Database Port on 172.17.0.2 IP, If this port is not available Run the following command -这里3306用作 172.17.0.2 IP 上的 Docker 数据库端口,如果此端口不可用运行以下命令 -

sudo iptables -A INPUT -p tcp --dport 3306 -j ACCEPT

Now, You can easily access the Docker Database from your local system by following configuration现在,您可以通过以下配置轻松地从本地系统访问 Docker 数据库

  host: 172.17.0.2 
  adapter: mysql
  database: DATABASE_NAME
  port: 3307
  username: DATABASE_USER
  password: DATABASE_PASSWORD
  encoding: utf8

In CentOS:在 CentOS 中:

First You have to check that is the Docker Database port is Available in your firewall by following command -首先,您必须通过以下命令检查防火墙中的 Docker 数据库端口是否可用 -

sudo firewall-cmd --list-all

Sample OUTPUT:示例输出:

  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:

Here 3307 is used as Docker Database Port on 172.17.0.2 IP, If this port is not available Run the following command -这里3307用作 172.17.0.2 IP 上的 Docker 数据库端口,如果此端口不可用运行以下命令 -

sudo firewall-cmd --zone=public --add-port=3307/tcp

In server, You can add the port permanently在服务器中,您可以永久添加端口

sudo firewall-cmd --permanent --add-port=3307/tcp
sudo firewall-cmd --reload

Now, You can easily access the Docker Database from your local system by the above configuration.现在,您可以通过上述配置从本地系统轻松访问 Docker 数据库。

One more thing needed for my setup was to add我的设置还需要做的一件事是添加

172.17.0.1  localhost

to /etc/hosts/etc/hosts

so that Docker would point to 172.17.0.1 as the DB hostname, and not rely on a changing outer ip to find the DB.这样 Docker 将指向172.17.0.1作为数据库主机名,而不是依赖不断变化的外部 ip 来查找数据库。 Hope this helps someone else with this issue!希望这可以帮助其他人解决这个问题!

Just in case, above solutions don't work for anyone.以防万一,上述解决方案对任何人都不起作用。 Use below statement to connect from docker to host postgres (on mac):使用以下语句从 docker 连接到主机 postgres(在 mac 上):

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

Let me try explain what i did.让我试着解释一下我做了什么。

Postgresql PostgreSQL

First of all I did the configuration needed to make sure my Postgres Database was accepting connections from outside.首先,我做了必要的配置以确保我的 Postgres 数据库接受来自外部的连接。

open pg_hba.conf and add in the end the following line:打开pg_hba.conf并在最后添加以下行:

host    all             all             0.0.0.0/0               md5

open postgresql.conf and look for listen_addresses and modify there like this:打开postgresql.conf并查找listen_addresses并像这样修改那里:

listen_addresses = '*'

Make sure the line above is not commented with a #确保上面的行没有用#注释

-> Restart your database -> 重启你的数据库

OBS : This is not the recommended configuration for a production environment OBS :这不是生产环境的推荐配置

Next, I looked for my host's ip .接下来,我寻找我的主机的ip I was using localhosts ip 127.0.0.1 , but the container doesn't see it, so the Connection Refused message in question shows up when running the container.我使用的是 localhosts ip 127.0.0.1 ,但容器没有看到它,因此运行容器时会显示有问题的 Connection Refused 消息。 After a long search in web about this, I read that the container sees the internal ip from your local network (That one your router attributes to every device that connects to it, i'm not talking about the IP that gives you access to the internet).在网络上对此进行了长时间的搜索后,我读到容器可以看到来自您本地网络的内部 IP(您的路由器归属于连接到它的每个设备,我不是在谈论让您可以访问互联网)。 That said, i opened a terminal and did the following:也就是说,我打开了一个终端并执行了以下操作:

Look for local network ip查找本地网络ip

Open a terminal or CMD打开终端或 CMD

(MacOS/Linux) (MacOS/Linux)

$ ifconfig

(Windows) (视窗)

$ ipconfig

This command will show your network configuration information.此命令将显示您的网络配置信息。 And looks like this:看起来像这样:

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

Look for the one that is active.寻找活跃的那个。

In my case, my local network ip was 192.168.0.103就我而言,我的本地网络 IP 是192.168.0.103

With this done, I ran the container.完成此操作后,我运行了容器。

Docker码头工人

Run the container with the --add-host parameter, like this:使用--add-host参数运行容器,如下所示:

$ docker run --add-host=aNameForYourDataBaseHost:yourLocalNetWorkIp --name containerName -di -p HostsportToBind:containerPort imageNameOrId

In my case I did:就我而言,我做了:

$ docker run --add-host=db:192.168.0.103 --name myCon -di -p 8000:8000 myImage

I'm using Django , so the 8000 port is the default.我正在使用Django ,所以8000端口是默认的。

Django Application Django 应用程序

The configuration to access the database was:访问数据库的配置是:

In settings.pysettings.py

DATABASES = {
    'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': ‘myDataBaseName',
            'USER': ‘username',
            'PASSWORD': '123456',
            'HOST': '192.168.0.103',
            'PORT': 5432,
    }
}

References参考

About -p flag: Connect using network port mapping关于-p标志:使用网络端口映射连接

About docker run : Docker run documentation关于docker runDocker 运行文档

Interesting article: Docker Tip #35: Connect to a Database Running on Your Docker Host有趣的文章: Docker 技巧 #35:连接到在 Docker 主机上运行的数据库

3 STEPS SOLUTION 3 步解决方案

1. Update docker-compose file 1.更新docker-compose文件

First, since the database is local we need to bind the host network to the container by adding the following configuration to the container service首先,由于数据库是本地的,我们需要通过将以下配置添加到容器服务来将主机网络绑定到容器

services:
    ...
    my-web-app:
        ...
        extra_hosts:
          -  "host.docker.internal:host-gateway"
        ...
    ...

2. Update /etc/postgresql/12/main/pg_hba.conf 2.更新/etc/postgresql/12/main/pg_hba.conf

If the file doesn't exists under this dir use find / -name 'pg_hba.conf' to find it.如果此目录下不存在该文件,请使用find / -name 'pg_hba.conf'找到它。

Add the following line under the comment tag # IPv4 local connections:在注释标签# IPv4 local connections:

host    all             all             172.17.0.1/16           md5

3. Update /etc/postgresql/12/main/postgresql.conf 3.更新/etc/postgresql/12/main/postgresql.conf

If the file doesn't exists under this dir use find / -name 'postgresql.conf' to find it.如果此目录下不存在该文件,请使用find / -name 'postgresql.conf'找到它。

find the following line (The line might be commented )找到以下行(该行可能被注释

#listen_addresses = 'localhost'

And change it to the following line, To be able to connect to postgres from localhost & 172.17.0.1并将其更改为以下行,以便能够从本地主机和172.17.0.1连接到 postgres

listen_addresses = 'localhost,172.17.0.1'

You can also change it to the following, But this is not recommended for production since it will expose the database to the world(Any IP address can connect to the database)您也可以将其更改为以下内容,但不建议将其用于生产,因为它会将数据库暴露给世界(任何 IP 地址都可以连接到数据库)

listen_addresses = '*'

Finally don't forget to最后别忘了

  1. restart the postgres service using sudo systemctl restart postgresql使用sudo systemctl restart postgresql postgres 服务
  2. update the connection string host to host.docker.internal将连接字符串主机更新为host.docker.internal

The another solution is service volume, You can define a service volume and mount host's PostgreSQL Data directory in that volume.另一种解决方案是服务卷,您可以定义一个服务卷并在该卷中挂载主机的 PostgreSQL 数据目录。 Check out the given compose file for details.查看给定的撰写文件以获取详细信息。

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

By doing this, another PostgreSQL service will run under container but uses same data directory which host PostgreSQL service is using.通过这样做,另一个 PostgreSQL 服务将在容器下运行,但使用主机 PostgreSQL 服务正在使用的相同数据目录。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从 PGAdmin Container 连接本地 postgres 数据库 - Connect local postgres database from PGAdmin Container ufw 禁止 docker 容器连接到 postgres - ufw forbids docker container to connect to postgres Windows版Docker-无法从Windows主机连接到Ubuntu容器上的MongoDB - Docker for Windows - Can not connect to the MongoDB on Ubuntu Container from Windows host 无法从本地计算机连接到Docker容器中的mongodb - Can't connect to mongodb in docker container from local machine docker pgAdmin4 连接在连接本地 postgres 数据库时被拒绝 - docker pgAdmin4 connection refused while connecting local postgres database Doctrine无法连接到链接的Docker容器中的MYSQL数据库 - Doctrine fails to connect to MYSQL database in linked docker container 如何连接到远程 ubuntu 服务器上的 docker 容器数据库? - How to connect to a docker container database on a remote ubuntu server? 连接到WordPress Docker容器 - Connect to WordPress Docker Container 将在 Ubuntu VM 内运行的 docker 容器端口与 VM 的主机网络连接 - Connect a docker's container port that is running inside an Ubuntu VM, with the VM's host machine network 无法从我的 Docker 容器内部连接到主机的本地主机 - Can't connect to localhost of the host machine from inside of my Docker container
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM