有关 docker 容器网络如何工作的问题

Question related to how docker containers networking work

当我们通过docker暴露端口时,其网络路径如下

Docker container network flow

所以当我 运行 我的容器使用下面的命令时

docker run --rm -it --name server -p 45678:45678 ubuntu:14.04 bash

这里我们基本上是在映射外部主机端口:内部容器端口正确吗?

现在在上面的容器里面如果我启动netcat来监听45678端口;那么任何容器都应该能够使用 nc <my-windows-hostname> 45678 连接到它,对吧?但是,它不起作用。

我读到了这篇文章,发现我们需要使用 host.docker.internal 而不是 windows-主机名。

我的问题是为什么会这样??

当您启动Docker时,会自动创建一个默认的桥接网络(也称为网桥),除非另有说明,否则新启动的容器将连接到它。

因此,当您启动容器时,它已连接到默认桥接网络。

此外,默认桥接网络上的容器只能通过 IP 地址相互访问,除非您使用 --link 选项,这被认为是遗留的。

host.docker.internal 的作用是解析主机使用的内部 IP 地址(经常更改)。

Reference

Docker for Windows(以及 Docker for Mac)利用带有 Linux 内核的虚拟机来提供 运行time linux 个容器的环境。

这意味着容器 运行 在与您的 windows 主机不同的主机上(使用另一个名称和 IP),如下图所述

|--------------------------------------------------------|
|  Windows host     |----------------------------------| |
|                   | Docker VM                        | |
|  docker cli       | |-------------|  |-------------| | |
|                   | | ContainerA  |  | ContainerB  | | |
|                   | |             |  |             | | |
|                   | |-------------|  |-------------| | |
|                   |----------------------------------| |
|--------------------------------------------------------|

docker cli 运行 在 windows 上,但所有容器 运行 在 Docker VM 内。

当你 运行 命令 docker run --rm -it --name containerA -p 45678:45678 ubuntu:14.04 bash Docker VM 上的端口 45678 被转发到 containerA 中的端口 45678。

此外,Docker CLI 负责将 windows 主机上的端口 45678 转发到 Docker 虚拟机。这样做的结果是,当您从 windows 机器上使用 localhost:45678<my-windows-hostname>:45678 时,您将通过链条到达容器:

<my-windows-hostname>:45678 -> <docker VM>:45678 -> ContainerA:45678

您正在尝试做的是从 另一个 容器而不是 windows 主机通过已发布的端口访问另一个容器。为此,您需要拥有 Docker VM 而不是 windows 主机的内部主机名或 IP。这就是您可以使用 host.docker.internal 的目的。

来自Docker for Windows Documentation

The host has a changing IP address (or none if you have no network access). From 18.03 onwards our recommendation is to connect to the special DNS name host.docker.internal, which resolves to the internal IP address used by the host.

This is for development purpose and will not work in a production environment outside of Docker Desktop for Windows.