实际的 Docker Compose 等效项是通过将相同的字符串附加到 extra_hosts 参数 (#Doc) 来实现的:
version: '3.9'
services:
postgres:
image: postgres:14.1-bullseye
environment:
POSTGRES_PASSWORD: ****
ports:
- "5433:5432"
extra_hosts:
- "host.docker.internal:host-gateway"
你可以看到它已经从你的容器内部成功映射到docker0接口的IP,这里是172.17.0.1,例如:
$ docker-compose up -d
$ docker-compose exec postgres bash
然后,从容器内部:
root@5864db7d7fba:/# apt update && apt -y install netcat
root@5864db7d7fba:/# nc -vz host.docker.internal 80
Connection to host.docker.internal (172.17.0.1) 80 port [tcp/http] succeeded!
(假设 80 端口没有被主机上的防火墙关闭或限制为docker0 接口的 IP)。
可以在此处找到更多信息:
https://medium.com/@TimvanBaarsen/how-to-connect-to-the-docker-host-from-inside-a-docker-container-112b4c71bc66
但是……当心……
警告⚠️
这通常总是匹配主机上docker0 接口的172.17.0.1 IP。因此,如果您使用 Compose 文件启动容器(因此,不使用 docker run),该容器将依赖于在 Compose 服务构建期间创建的网络的可能性非常高。该网络将使用172.xxx.0.1 形式的随机网关地址,这肯定不同于172.17.0.1 默认docker 网关,例如172.22.0.1。
如果您仅明确授权从172.17.0.1 到主机上本地服务的端口的连接,这可能会给您带来一些麻烦。
实际上,无法从容器内部 ping 该服务的端口,正是因为这个不同分配的网关地址 (172.22.0.1)。
因此,由于您无法提前知道 Compose 网络将拥有哪个网关地址,我强烈建议您明智地在 Compose 文件中构建自定义 network 定义,例如:
version: '3.9'
networks:
network1:
name: my-network
attachable: true
ipam:
driver: default
config:
- subnet: 172.18.0.0/16
ip_range: 172.18.5.0/24
gateway: 172.18.0.1
services:
postgres:
image: postgres:14.1-bullseye
environment:
POSTGRES_PASSWORD: ****
ports:
- "5433:5432"
networks:
- network1
如果需要,我还建议使用一些 IP 范围计算器工具,例如 http://jodies.de/ipcalc?host=172.18.5.0&mask1=24&mask2= 来帮助自己完成这项任务,尤其是在使用 CIDR 符号定义范围时。
最后,启动您的容器。并验证新指定的Gateway地址172.18.0.1是否被正确使用:
$ docker inspect tmp_postgres_1 -f '{{range .NetworkSettings.Networks}}{{.Gateway}}{{end}}'
172.18.0.1
附加到它,安装netcat并验证:
root@9fe8de220d44:/# nc -vz 172.18.0.1 80
Connection to 172.18.0.1 80 port [tcp/http] succeeded!
(您可能还需要相应地调整防火墙规则和/或本地服务允许的 IP,例如数据库)
另一种解决方案
是使用docker network 连接到现有的默认bridge 网络。为此,在启动容器后,运行以下命令:
$ docker network connect bridge tmp_postgres_1
现在,检查应该给你两个 IP;您设置的那个(如果有的话)或者在容器创建过程中由 docker 自动设置的那个,以及bridge IP:
$ docker inspect tmp_postgres_1 -f '{{range .NetworkSettings.Networks}}{{.Gateway}}{{end}}'
172.17.0.1 172.18.0.1
或者
您可以跳过手动创建网络,并在 Compose 服务定义中直接告诉使用 network_mode: 标志加入 bridge 网络,如下所示:
version: '3.9'
services:
postgres:
image: postgres:14.1-bullseye
environment:
POSTGRES_PASSWORD: ****
ports:
- "5433:5432"
# removed networks: and add this:
network_mode: bridge
extra_hosts:
- "host.docker.internal:host-gateway"
现在,无论您是在 Compose 文件中使用 docker network connect... 方法还是 network_mode: 标志,您通常都会成功地将默认 bridge 网络与网关 172.17.0.1 连接起来,这将允许您使用该网关 IP连接到你的主机,或者通过输入它的数值,或者如果设置,变量host.docker.internal:
root@9fe8de220d44:/# nc -vz 172.18.0.1 80
Connection to 172.18.0.1 80 port [tcp/http] succeeded!
root@9fe8de220d44:/# nc -vz 172.17.0.1 80
Connection to 172.18.0.1 80 port [tcp/http] succeeded!
root@9fe8de220d44:/# nc -vz host.docker.internal 80
Connection to host.docker.internal (172.17.0.1) 80 port [tcp/http] succeeded!
⚠️ 但是通过加入bridge 网络,您还可以让您的容器与该网络上的所有其他容器进行通信(如果它们已发布端口),反之亦然。因此,如果您需要清楚地将其与这些其他容器分开,您最好不要这样做并坚持使用它自己的自定义网络!
如果出现问题怎么办?
如果您在尝试后弄乱了您的 docker 网络,您可能会遇到这样的错误消息:
Creating tmp_postgres_1 ... error
ERROR: for tmp_postgres_1 Cannot start service postgres: failed to create endpoint tmp_postgres_1 on network bridge: network 895de42e2a0bdaab5423a6356a079fae55aae41ae268ee887ed214bd6fd88486 does not exist
ERROR: for postgress Cannot start service postgres: failed to create endpoint tmp_postgres_1 on network bridge: network 895de42e2a0bdaab5423a6356a079fae55aae41ae268ee887ed214bd6fd88486 does not exist
ERROR: Encountered errors while bringing up the project.
即使895de42e2a0bdaab5423a6356a079fae55aae41ae268ee887ed214bd6fd88486 网桥网络确实存在,您必须通过重新启动计算机或在最幸运的情况下使用 docker 服务来清除所有这些:
$ sudo service docker restart
(docker networkd prune -f 可能还不够)。
文档中的更多内容:
https://docs.docker.com/compose/networking/
https://docs.docker.com/compose/compose-file/compose-file-v3/#networks
https://github.com/compose-spec/compose-spec/blob/master/spec.md#networks-top-level-element
在具有以下规格的主机上测试:
Ubuntu:18.04.6 LTS
内核:5.4.0-94-generic
Docker:20.10.12,构建 e91ed57
Docker Compose:1.27.4,构建 40524192