Compose 文件中 --add-host=host.docker.internal:host-gateway 的等价物是什么
What is the equivalent of --add-host=host.docker.internal:host-gateway in a Compose file
从 Docker 版本 20.10
(https://github.com/moby/moby/pull/40007) 开始,有一个新的特殊字符串 host-gateway
可以在 --add-host
运行 标志允许从 docker 容器内部直接连接到基于 Linux 的系统上的本地计算机。这很好。
但是 Compose 文件中 --add-host=host.docker.internal:host-gateway
的等价物是什么?
例如在:
$ docker run \
--rm \
--name postgres \
-p "5433:5432" \
-e POSTGRES_PASSWORD=**** \
--add-host=host.docker.internal:host-gateway \
-d postgres:14.1-bullseye
如何将相同的 --add-host
标记放入此 Docker Compose 等效模板中:
version: '3.9'
services:
postgres:
image: postgres:14.1-bullseye
environment:
POSTGRES_PASSWORD: ****
ports:
- "5433:5432"
肯定不是:network_mode: host
在服务级别(参见 #Doc)。
实际的 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= to help yourself in that task, especially when defining ranges using the CIDR notation。
最后,启动您的容器。并验证新指定的网关地址 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!
(您可能还需要相应地调整防火墙规则 and/or 本地服务允许的 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"
现在,无论您使用 docker network connect...
方法还是在 Compose 文件中使用 network_mode:
标志,您通常都可以通过网关 172.17.0.1
成功加入默认 bridge
网络,这将允许您使用该网关 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 撰写:1.27.4,构建 40524192
从 Docker 版本 20.10
(https://github.com/moby/moby/pull/40007) 开始,有一个新的特殊字符串 host-gateway
可以在 --add-host
运行 标志允许从 docker 容器内部直接连接到基于 Linux 的系统上的本地计算机。这很好。
但是 Compose 文件中 --add-host=host.docker.internal:host-gateway
的等价物是什么?
例如在:
$ docker run \
--rm \
--name postgres \
-p "5433:5432" \
-e POSTGRES_PASSWORD=**** \
--add-host=host.docker.internal:host-gateway \
-d postgres:14.1-bullseye
如何将相同的 --add-host
标记放入此 Docker Compose 等效模板中:
version: '3.9'
services:
postgres:
image: postgres:14.1-bullseye
environment:
POSTGRES_PASSWORD: ****
ports:
- "5433:5432"
肯定不是:network_mode: host
在服务级别(参见 #Doc)。
实际的 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= to help yourself in that task, especially when defining ranges using the CIDR notation。
最后,启动您的容器。并验证新指定的网关地址 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!
(您可能还需要相应地调整防火墙规则 and/or 本地服务允许的 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"
现在,无论您使用 docker network connect...
方法还是在 Compose 文件中使用 network_mode:
标志,您通常都可以通过网关 172.17.0.1
成功加入默认 bridge
网络,这将允许您使用该网关 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 撰写:1.27.4,构建 40524192