如何从主机外部(同一网络)连接到 Docker 容器 [Windows]

122

我创建了我的第一个Docker容器,它正在使用Go运行服务器,但我无法从主机之外访问它。我刚刚开始使用Docker,所以我在这里有点迷失。

所以我有一个非常简单的Go代码启动服务器,我已经构建了Docker镜像,其中安装了Go并在Linux基础镜像中构建了该代码。我在8080端口上运行服务器,因此我将该端口暴露给运行容器的主机,如下所示:

docker run -p 8080:8080 dockertest

这个方法有效,我可以通过Docker的机器IP(在启动时出现在Docker Quickstart终端上)访问服务器,但问题是我无法从主机外部访问托管的网站,所以如果我尝试在手机上打开同一个IP地址,它会显示错误:此网页不可用(ERR_CONNECTION_TIMED_OUT)。

我还尝试了像这样指定IP:

docker run -p 192.168.0.157:8080:8080 dockertest
但是当我这样做时,我无法通过docker机器的IP或上面命令行中指定的IP访问网站。 我也不确定在该命令中应该写哪个IP地址,我试过使用我的电脑IP地址,也尝试了127.0.0.1(本地主机),但结果都一样:无法通过任何IP访问网站。
我已经在Google上搜索了这个问题,并找到了许多StackOverflow的问题,但没有一个能帮助我解决这个问题。大多数问题都是针对Linux或Mac的,所以解决方案并不适用于我的情况。
此外,我可以在我的计算机上运行Go代码,并通过我的计算机IP地址从同一网络中的另一台设备访问该网站。我不明白为什么在运行它时无法访问它,我想可能与IP转发之类的东西有关,但我对网络一窍不通,我主要是一个Web开发人员,几乎没有本地开发经验。

你在 Dockerfile 中是否使用了“EXPOSE 8080”与“-p”选项配合?同时,请检查运行容器的主机上的端口8080是否被安全规则所阻止。 - keda
@keda 是的,Dockerfile 中包含 EXPOSE 8080。我正在通过 Docker 的 Quickstart 终端在本地计算机上运行容器,我还尝试禁用 Windows 防火墙,但也没有起作用,我不知道是否有一些设置我错过了。 - redsalt
8个回答

139
  1. 打开Oracle VM VirtualBox Manager
  2. 选择Docker使用的虚拟机
  3. 点击设置 -> 网络
  4. 适配器 1 应该(默认)是 "连接方式:NAT"
  5. 点击高级 -> 端口转发
  6. 添加规则:协议 TCP,主机端口 8080,客户机端口 8080(将主机 IP 和客户机 IP 留空)
  7. 客户机是您的 Docker 容器,主机是您的计算机

现在您应该能够通过 localhost:8080 和您的内部 IP:8080 浏览到您的容器了。


10
确认,不错且容易。 - Dirk
2
最佳答案,不要像选中的那个一样有大量描述。 - Amir Qayyum Khan
2
对于 Vagrant 用户,请在 Vagrantfile 中添加以下内容:config.vm.network "forwarded_port", guest: 8080, host: 8080, protocol: "tcp" - Vince Verhoeven
3
哟!这个方法太好用了!谢谢!!!我花了几个小时才弄明白它。 - Joseph Freeman
2
这是一个非常棒的解决方案,适用于任何通过VBox运行Docker的人! - Mirodinho
显示剩余8条评论

104

TL;DR:检查您的VirtualBox主机的网络模式 - 如果您希望虚拟机(及其托管的Docker容器)可以在本地网络上访问,则应该使用bridged


你的困惑似乎在于要连接哪个主机才能通过HTTP访问你的应用程序。您并没有真正说明您的配置是什么 - 基于您的标签中有"Windows"和"VirtualBox",我会做出一些猜测。

我猜您在Windows主机上运行VirtualBox中某种Linux版本上的Docker。 我将IP地址标签如下:

D = Docker容器的IP地址

L = 运行在VirtualBox中的Linux主机的IP地址

W = Windows主机的IP地址

当您在Windows主机上运行Go应用程序时,您可以从本地网络上的任何位置使用http://W:8080/连接到它。这是因为Go应用程序在Windows机器上绑定了端口8080,任何试图访问IP地址W的端口8080的人都会被连接到它。

现在问题变得更加复杂:

VirtualBox设置虚拟机(VM)时,可以配置多种不同的网络模式。我不记得所有不同的选项是什么,但您想要的是bridged。在此模式下,VirtualBox将虚拟机连接到您的本地网络,就像它是网络上的独立机器一样,就像任何其他插入到您的网络中的机器一样。在bridged模式下,虚拟机就像任何其他机器一样出现在您的网络上。使用其他模式会设置不同的东西,该机器将无法在您的网络上可见。

假设你正确设置了 Linux 主机的网络(bridged),则 Linux 主机将在您的本地网络上拥有一个 IP 地址(类似于 192.168.0.x),您可以通过 http://L:8080/ 访问 Docker 容器。

如果 Linux 主机设置为某种模式而不是 bridged,您可能能够从 Windows 主机访问,但这取决于它的确切模式。

编辑 - 根据下面的评论,看起来我描述的情况是正确的。

我们先回退一步:这是 Docker 在我的电脑上(Ubuntu Linux)的工作方式。

想象一下我运行与您相同的命令:docker run -p 8080:8080 dockertest。这样做会基于 dockertest 镜像启动一个新的容器,并将 Linux 主机(我的 PC)上的端口 8080 转发(连接)到容器上的端口 8080。Docker 设置自己的内部网络(具有自己的一组 IP 地址)以允许 Docker 守护程序通信,并允许容器彼此通信。因此,您使用那个 -p 8080: 8080 实际上是将 Docker 的内部网络与“外部”网络 - 即主机的网络适配器 - 在一个特定端口上连接起来。

到目前为止没问题吧?好了,现在让我们退后一步,看看您的系统。您的计算机正在运行 Windows - Docker 目前不支持 Windows,因此您使用的工具在 VirtualBox 虚拟机中设置了一个 Linux 主机。在您的环境中进行 docker run 时,正发生着完全相同的事情 - Linux 主机上的端口 8080 连接到容器上的端口 8080。这里的重大区别在于,您的 Windows 主机不是运行容器的 Linux 主机,因此在跨越此层进行通信时会遇到问题。

您需要以下两个选项之一:

  1. 若要将VirtualBox虚拟机的8080端口连接到Windows主机的8080端口,就像您将Docker容器连接到主机端口一样。

  2. 若要使用上述所述的"桥接"网络模式直接将VirtualBox虚拟机连接到本地网络,请选择第二个选项。

  3. 如果您选择第一个选项,则可以通过http://W:8080访问容器,其中W是Windows主机的IP地址或主机名。如果您选择第二个选项,则可以通过http://L:8080访问容器,其中L是Linux虚拟机的IP地址或主机名。

    这就是所有的高级别解释 - 现在您需要弄清如何更改VirtualBox VM的配置。这就是我无法真正帮助您的地方 - 我不知道您在Windows机器上使用什么工具来完成所有这些操作,并且我对在Windows上使用Docker毫不熟悉。

    如果您可以进入VirtualBox配置窗口,则可以进行下面描述的更改。还有一种命令行客户端可以修改VMs,但我不熟悉它。

    对于 bridged 模式(这确实是最简单的选择),关闭VM,单击顶部的"设置"按钮,将网络模式更改为 bridged ,然后重新启动VM即可。虚拟机应该通过DHCP在本地网络上获取一个IP地址,并且应该在该IP地址上对其他计算机可见。


1
我只能找到两个IP地址,一个是在打开快速启动终端时Docker显示的(192.168.99.100),另一个是我的计算机的IP地址(192.168.0.157)。使用“docker run -p 8080:8080 dockertest”命令,我可以通过“http://192.168.99.100:8080”访问我的网站,但只能从我的Windows计算机(主机)访问,而不能从我的手机访问。如果我使用“docker run -p 192.168.0.157:8080:8080 dockertest”命令,则无法使用任何IP地址从任何地方访问该网站。我不确定如何设置网络,我尝试使用“--net=bridge”命令,但也没有起作用。我应该打开VirtualBox吗?难道我不能使用Docker的终端来完成吗? - redsalt
问题不在于Docker,所以不,Docker不能帮助你。我将添加一些编辑来说明我认为正在发生的事情。 - Kryten
好的,谢谢!现在我明白了,我之前被整个Linux虚拟机部分搞糊涂了。我一直以为Docker是在使用Virtual Box进行我不应该触碰的内部操作。实际上很简单,我只需要在Virtual Box中改成“桥接”模式,现在它运行得非常好,非常感谢你。 - redsalt
难道没有办法让Windows和Docker容器在同一个网络中吗?这样我们就可以直接访问容器,而无需进行端口转发了吗? - Victor Basso
1
@raulsntos 我在VirtualBox的网络选项卡中有两个适配器。请问我应该更改哪一个? - kishore
显示剩余2条评论

9

经过多次尝试,这样做对我有效:

  • 使用--publish=0.0.0.0:8080:8080 docker标志
  • 将virtualbox网络模式设置为NAT,并且不使用任何端口转发

除了地址为0.0.0.0以外,其他地址都没有成功。


6

简述: 如果你启用了Windows防火墙,请确保在私有网络中有一个“vpnkit”的例外。

对于我的情况,当我尝试从本地网络上的另一台机器访问容器的发布端口时,我发现Windows防火墙正在阻止我的连接,因为禁用它可以使一切正常。

然而,我不想完全禁用防火墙,只是为了访问我的容器服务。这引出了一个问题,即哪个“应用程序”代表我的容器服务在监听。在找到另一个SO线程教我使用netstat -a -b来发现我的计算机上监听套接字后面的应用程序之后,我了解到它是vpnkit.exe,它已经在我的Windows防火墙设置中有一个条目:但是“私有网络”被禁用了,一旦我启用它,我就能够从另一台机器访问我的容器服务,而无需完全禁用防火墙。


先生,您救了我数小时的挫败感。谢谢。 - Behdad
1
感谢您提供的netstat技巧。对我来说,问题不在vpnkit上,而是在C:\ program files \ docker \ docker \ resources \ com.docker.backend.exe上。它必须被创建为出站规则(它已经存在作为入站规则)。 - Abdullah Gheith

3
这是Windows用户在运行Docker容器时最常见的问题。我认为这是关于Docker的“百万美元问题”;“Rocco Smit”正确地指出,“我的主机防火墙默认禁用了入站流量”,在我的情况下,是我的McAfee杀毒软件。我在McAfee防火墙设置中添加了允许其他同一Wifi局域网上的计算机入站流量的额外端口;然后就神奇地解决了。我苦苦挣扎了一个多星期,在整个互联网、SO、Docker文档、教程和与Docker网络相关的多种插图(即使是几次相同的SO线程)之间浏览。我甚至开始用“有人在生产环境中使用Docker吗?”来搜索谷歌(是的,我知道Linux比Windows服务器更受欢迎),因为我不能从我的手机(在同一家庭WiFi中)访问部署在Windows上的Docker容器中的nginx应用程序。毕竟,如果您无法至少从同一局域网中的其他计算机/设备访问应用程序(部署在Docker容器中),那么有什么好处呢?最终,在我的情况下,问题只是防火墙阻止了入站流量;

1
我发现,除了设置 -p 端口值外,Docker for Windows 还使用 vpnkit,并且默认情况下,它的入站流量在我的主机防火墙上被禁用。启用 vpnkit 的入站 TCP 规则后,我可以从本地网络上的其他计算机访问我的容器。

1

我尝试了很多方法但都没用,最后我使用我的机器IP地址访问了docker主机。按照以下步骤操作:

  1. 打开CMD
  2. 输入IPCONFIG /ALL
  3. 查找IPv4地址,在我的情况下是192.168.1.7
  4. 然后,我通过映射端口访问了托管在docker容器中的应用程序
  5. 在我的情况下,我尝试访问我的Jenkins应用程序,它作为一个容器进行托管
  6. 简单来说,这样做很有效:192.168.1.7:50000
  7. 同样的方式,我可以访问所有使用docker托管的容器应用程序

如果我(或其他人)想要将运行在您机器上的Jenkins作为Docker容器使用,它能正常工作吗? - Manikanta Komuravelli
是的,如果您的计算机配置了公共静态IP,但显示的是本地IP。 - Mohan Raj Raja

1

基于Kryten的回答,我将添加一些关于Windows配置的信息。

  1. 停止虚拟机
  2. 打开VM设置 -> 网络 -> 选项卡“适配器3”:
  • 勾选“启用网络适配器”
  • 附加到:“桥接适配器”。
  • 名称:[您的Windows网络适配器]

Screenshot


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