"host.docker.internal"在Linux中的等效是什么?

331

在 Mac 和 Windows 上,可以在容器内使用 host.docker.internal(Docker 18.03+)。

是否有类似的方法适用于 Linux,并且可以直接使用而无需传递环境变量或使用各种 CLI 命令进行提取?


4
在18.03版本中有一个docker.host.internal,但它对我来说不起作用。 - James O'Brien
7
这里有一个开放的 PR(https://github.com/docker/libnetwork/pull/2348),它为 Linux 添加了“host.docker.internal”功能。等待其被接受,现在可以使用一个特殊的容器(https://github.com/qoomon/docker-host)作为解决方法,它添加了统一的“dockerhost”主机,并且您可以从 Docker 中使用它。 - Serhii Popov
1
需要注意的是,docker-for-windows是一个特定的产品线,不会涵盖Windows上的docker总体。例如,我使用docker-toolbox(OG)在Windows上使用docker,这样它就可以与我的其他设置产生较少的冲突,而且我不需要HyperV。这个线程中有一个使用grep、awk和netstat的答案,对我来说很有效;尽管通常情况下,混合网络环境也可以通过LAN或WAN级别的主机名来解决,而不是机器主机名。这比在docker VM上进行hack更明确和灵活/可组合。 - MrMesees
11个回答

299

这要看你想做什么。如果你正在使用 --net=hostlocalhost 应该可以正常工作。如果你使用默认网络,请使用静态 IP 172.17.0.1。我认为两种方式都不能像那些域名一样表现。


78
哇!172.17.0.1 竟然有效!我在文件和所有抱怨 host.docker.internal 无法使用的论坛中都找不到这个信息。这个 IP 地址是否保证始终链接到主机? - Jules Colle
8
您可以编辑/etc/hosts文件,并添加 172.17.0.1 docker.host.internal。 - PHZ.fi-Pharazon
7
我可以证实,使用172.17.0.1这个技巧可以在 GitHub Actions 中使用! - Alex
9
只要您使用默认网络,就可以“保证”,172.17.0.1并不是什么魔术,而只是网络bridge的网关,恰好与主机相同。除非另有规定,否则所有容器都将连接到bridge在这里查看 - FirefoxMetzger
10
并非所有情况都适用。如果您有其他网络,会创建一个新接口:172.17.0.1、172.18.0.1、172.19.0.1等(使用“ifconfig”命令列出所有接口)。您必须手动获取您的网络IP。 - Federico
显示剩余3条评论

225

4
有没有一种方法可以在 daemon.json 或其他地方启用这个功能?我在考虑 Rancher 和 Kubernetes 的测试环境,我不想照顾其中的每一个容器。 - qräbnö
6
在CentOS上运行--add-host=host.docker.internal:host-gateway时,我收到了错误信息invalid argument "host.docker.internal:host-gateway" for "--add-host" flag: invalid IP address in add-host: "host-gateway"。您是否希望用实际的主机IP地址来替换host-gateway - mummybot
3
神奇的IP地址生效了:--add-host=host.docker.internal:172.17.0.1 \。该命令会将 host.docker.internal 映射到 IP 地址 172.17.0.1 上。 - mummybot
2
这对我也有效。在我的情况下,172.17.0.1是桥接网络的网关地址。如果有人有不同的网络设置,他们可以通过执行docker inspect来获取此信息。 - Aniket Chopade
10
只有较新版本的Docker才具有神奇的字符串“host-gateway”,它会将其转换为Docker默认桥接网络IP(或在使用Docker桌面版时转换为主机的虚拟IP)。您可以尝试运行命令:docker run --rm --add-host=host.docker.internal:host-gateway ubuntu:18.04 cat /etc/hosts,然后查看是否有效并展示主机文件中的IP地址(其中应该有一行类似于172.17.0.1 host.docker.internal)。 - Lucas Basquerotto
显示剩余3条评论

193

如果你正在使用 Docker Compose + Linux,你需要手动添加它(至少目前是这样)。在你的docker-compose.yaml文件中使用extra_hosts

version: '3.7'

services:

  fpm:
    build:
      context: .
    extra_hosts:
      - "host.docker.internal:host-gateway"

不要忘记更新Docker,因为这只适用于Docker v20.10+
来源:https://github.com/docker/for-linux/issues/264#issuecomment-784985736

3
太棒了!我终于也可以在Linux上使用xdebug了 :-) - funder7
1
@funder7 哈哈,是的,我这样做是为了使用xdebug :) - jawira
13
如果我想从容器中访问主机上的3000端口,我需要使用这个地址吗:http://host.docker.internal:3000/ - Javohir Mirzo Fazliddinov
2
我尝试了,但在我的 Docker 版本“Version: 20.10.17”上无法工作。 - Kristi Jorgji
2
这在Linux上不起作用。它似乎会“思考”很长时间,然后超时。 - Jonny
显示剩余8条评论

32

一种解决方法是使用特殊容器将流量重定向到主机。您可以在此处找到这样的容器:https://github.com/qoomon/docker-host。思路是从容器内获取默认路由,并将其安装为传入连接的NAT网关。

一个想象中的用例示例:

docker-host:
  image: qoomon/docker-host
  cap_add: [ 'NET_ADMIN', 'NET_RAW' ]
  restart: on-failure
  environment:
    - PORTS=999

some-service:
  image: ...
  environment:
    SERVER_URL: "http://docker-host:999"
  command: ...
  depends_on:
    - docker-host

21

这是我的解决方案:

IP_ADDRESS=$(ip addr show | grep "\binet\b.*\bdocker0\b" | awk '{print $2}' | cut -d '/' -f 1)

然后在 docker-compose 中:

extra_hosts:
  docker.host: ${IP_ADDRESS}

2
在我的Ubuntu虚拟机上,这是172.17.0.1,与上面的答案相匹配。 - Dan Burton
3
在 Linux/Debian 上,使用这个命令在 Docker 中得不到任何结果。更好的方式是:/sbin/ip route|awk '/default/ { print $3 }' - GetoX
上面的 ip route 示例打印网关,而不是 docker0 io。下面的命令应该可以工作:# ip route | awk '/docker0/ {print $9}' - Adam Shand
我在我的情况下(Linux)使用这个解决方案结合 host.docker.internal 标志。看起来 host.docker.internal 在 macOS 上工作得很好。 - undefined

17

对于Linux来说,主机机器并没有默认的DNS名称。可以通过运行以下命令进行验证:

docker run -it alpine cat /etc/hosts

有人请求添加这个功能,但是未被实现。您可以查看此问题。如讨论所述,您可以使用以下命令从容器中查找主机的IP。

netstat -nr | grep '^0\.0\.0\.0' | awk '{print $2}'

或者,你可以通过 docker run --add-host dockerHost:<ip-address> ... 命令向运行命令提供主机IP。


1
这绝对不是等价的。拥有能够通过DNS解析的东西可以让你将其放入配置文件中,而无需进行评估、sed或其他奇怪的操作。 - James O'Brien
往往情况下,grep | awk 可以简化为只用 awk:awk '/^0\.0\.0\.0/{print $2}' :) - cviejo
我想说声谢谢。这个方法在我的Windows设置上运行良好,该设置使用docker-machine(我知道这是原始版本)。通常我会运行一个透传的nginx,以便我可以通过单个容器与docker通信,但是回传到主机似乎非常依赖于操作系统/设置。它对我起作用了,我为此感到非常兴奋。谢谢! - MrMesees

15

tldr; 通过静态IP 172.17.0.1 访问主机。

向主机发出HTTP请求:

  1. 运行以下命令获取静态IP地址:ip addr show | grep "\binet\b.*\bdocker0\b" | awk '{print $2}' | cut -d '/' -f 1

  2. 将新的IP地址添加到允许的主机中

  3. 在请求中使用刚找到的IP地址:req = requests.get('http://172.17.0.1:8000/api/YOUR_ENDPOINT')


2
这不取决于您的容器在哪个“网络”中运行吗? - Josh M.

14

https://github.com/docker/for-linux/issues/264

IP=$(ip -4 route list match 0/0 | awk '{print $3}')
echo "Host ip is $IP"
echo "$IP   host.docker.internal" | sudo tee -a /etc/hosts

它将在您的主机中添加host.docker.internal。然后您可以在xdebug配置中使用它。

这是docker-compose.yml中环境变量的示例:

XDEBUG_CONFIG: remote_host=host.docker.internal remote_autostart=On remote_enable=On idekey=XDEBUG remote_log=/tmp/xdebug.log remote_port=9999

11

host.docker.internal只存在于Windows WSL环境中,因为Docker Desktop for Windows将Docker守护程序运行在特殊的WSL VM Docker-Desktop内部。它有自己的本地主机名和自己的WSL2接口,用于与Windows通信。这个VM没有固定的IP地址,每次创建VM时都会生成一个新的IP地址,并通过生成的/etc/hosts文件传递到每个发行版中的host.docker.internal中。虽然没有桥接或实际的虚拟交换机,但在VM内部网络上打开的所有端口都映射到主机的本地网络上,但不映射到主机的eth0上。
没有真正的桥接和端口映射 - 没有什么需要配置的。在WSL VM内部,它的本地主机名与Linux机器的localhost相同。WSL VM内的两个进程可以通过localhost通信。跨发行版IPC必须使用host.docker.internal。在WSL VM内部,可以创建桥接-Docker这样做。


1
实际上,如果使用Docker Desktop,host.docker.internal也适用于OSX。 - Felipe Valdes
1
另一个提示来自文档:这(使用host.docker.internal)仅用于开发目的,在Docker Desktop之外的生产环境中不起作用。 - Daniel W.

9
使用docker0接口IP地址,例如172.17.0.1,可能是一个不错的解决办法。只需确保您需要到达的服务监听外部连接即可。典型的例子是MySQL,默认绑定到127.0.0.1,导致无法访问,直到您允许外部连接(如绑定到0.0.0.0)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接