[英]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
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
。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。localhost
.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).listen_addresses
,通常可以在/etc/postgresql/9.3/main/postgresql.conf
找到(归功于 @DazmoNorton)。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
。
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
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.有关详细信息,请参阅发行说明。
@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 地址。
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).这样容器将使用主机的网络,因此
localhost
和127.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 数据库暴露在狂野的西部。
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
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.让我试着解释一下我做了什么。
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:
也就是说,我打开了一个终端并执行了以下操作:
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.完成此操作后,我运行了容器。
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
端口是默认的。
The configuration to access the database was:访问数据库的配置是:
In settings.py
在
settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': ‘myDataBaseName',
'USER': ‘username',
'PASSWORD': '123456',
'HOST': '192.168.0.103',
'PORT': 5432,
}
}
About -p
flag: Connect using network port mapping关于
-p
标志:使用网络端口映射连接
About docker run
: Docker run documentation关于
docker run
: Docker 运行文档
Interesting article: Docker Tip #35: Connect to a Database Running on Your Docker Host有趣的文章: Docker 技巧 #35:连接到在 Docker 主机上运行的数据库
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"
...
...
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
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最后别忘了
sudo systemctl restart postgresql
sudo systemctl restart postgresql
postgres 服务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.