无法从WSL2 Docker容器连接到WSL2本地主机服务器

29

我在我的WSL2 Ubuntu上运行了一个简单的Web服务器,地址为https://0.0.0.0:4000(也可以通过Ubuntu hosts文件中映射到127.0.0.1的https://local.phx-cd.shoepping.at:4000访问)。我可以从Ubuntu和Windows主机连接到它 - 到目前为止都很好。但是此外,在集成了WSL2的Docker for Win中,我运行了一个Selenium Chrome容器,该容器连接并测试了该Web服务器上的内容(使用bridge),但是无法连接!

我连接到了容器,并尝试通过curl访问Web服务器 - 结果得到了拒绝连接的提示。由于我的计算机上有双重启动,我尝试切换到我的Linux发行版,然后在那里运行Web服务器和Linux Docker中的selenium,这样就可以连接到本地Web服务器了。所以我认为问题与WSL2有关。

我的docker-compose.yaml文件如下(我省略了我的Selenium Hub配置):

selenium-chrome-local:
      image: selenium/node-chrome-debug:3.141.59
      restart: always
      ports:
        - 5901-5902:5900
      volumes:
        - /dev/shm:/dev/shm
        - ../../temp:/home/seluser/Downloads
      depends_on:
        - selenium-hub-local
      environment:
        - SCREEN_WIDTH=1920
        - SCREEN_HEIGHT=1080
      extra_hosts:
        - "local.phx-cd.shoepping.at:10.99.99.1"
      networks:
        - selgrid
        - dockerhost

 networks:
    selgrid:
    dockerhost:
      driver: bridge
      ipam:
        config:
          - subnet: 10.99.99.0/24

如果您需要更多配置,请告诉我。谢谢。


我有几个问题:1)您是否在同一组合文件中拥有服务器?2)如果是这样,容器是否共享相同的网络?3)您确定在端口4000上使用https时没有犯错误吗?4)如果您将Selenium容器的主机中的服务器IP更改为Ubuntu之一,您能否连接到服务器?5)Selenium容器启动日志中是否有任何错误? - anemyte
@anemyte 1)Web服务器在Ubuntu上的nodejs进程中运行。2)Web服务器本身与Selenium容器不共享同一网络,但它们应该通过桥接“连接”,顺便说一句,在WSL之外也可以工作。3)绝对确定。4)我已经通过docker-compose.yaml中的extra_hosts进行了设置,但我还尝试将IP设置为Ubuntu的ifconfig IP,但没有帮助。5)绝对没有错误。容器工作正常,我可以很好地测试非本地服务器。 - Dan Macak
我建议你使用host网络模式(参见1)https://docs.docker.com/network/host/ 2)https://github.com/compose-spec/compose-spec/blob/master/spec.md#network_mode)作为一个愚蠢但容易的解决方法,或者深入研究iptables规则并查看容器流量如何进行。可能有一些东西会从容器中丢弃数据包。还有第三个选项是使用`macvlan`网络,并在您的网络中将容器放置在静态IP上。这将为您提供类似于主机模式的东西,而实际上并没有使用它。 - anemyte
@anemyte 我尝试了主机网络,虽然我可以通过 127.0.0.1(与以前不同)连接到其他容器(绑定到 Docker 主机),但我仍然无法连接到我的本地服务器,无论是 nodejs、python 还是其他什么。但是,如果我使用 WSL 的 eth0 IP,我就可以正常连接它们。将该 IP 放入 WSL 的 /etc/hosts 中,并给它一个名字 local.phx-cd.shoepping.at,但我无法通过此名称连接到该服务器,只有 IP 可以使用。我在 IP 表中没有发现任何异常,尽管我只能使用 netstat,iptables 需要在容器中升级内核。 - Dan Macak
当我在WSL2上的Ubuntu上安装Matrix Synapse时,我拒绝了向WSL2 Ubuntu发行版授予网络权限,这使得我无法访问在Ubuntu上运行的端口。更改权限后问题得到解决,我可以使用该端口。你也可以试试。 - Sarath Chandra
@sarathchandra 我已经尝试过关闭公共和私人网络的防火墙,但没有帮助。 - Dan Macak
2个回答

26
你确定Ubuntu WSL2实例正在运行桥接模式吗?默认情况下,WSL2实例是运行在NAT模式下的(而WSL1实例是运行在桥接模式下的)。所以,虽然Docker网络是桥接的,但它仍然无法直接访问NAT模式下的WSL2虚拟机,需要进行一些额外的工作。
我相当确定你遇到了WSL问题#4150中描述的根本问题。如果是这样的话,以下是一些尝试的方法...
选项1 - 将端口转发到WSL2实例
在GitHub问题中有几种解决方法,但对于你的情况来说,基本上可以通过将Windows主机接口的4000端口转发到WSL2实例的私有IP地址来解决。在PowerShell中执行以下命令:
netsh interface portproxy delete v4tov4 listenport="4000" # Delete any existing port 4000 forwarding
$wslIp=(wsl -d Ubuntu -e sh -c "ip addr show eth0 | grep 'inet\b' | awk '{print $2}' | cut -d/ -f1") # Get the private IP of the WSL2 instance
netsh interface portproxy add v4tov4 listenport="4000" connectaddress="$wslIp" connectport="4000"

请注意,您需要在每次重启后执行此操作,否则可以设置一个在登录时运行的脚本,如GitHub问题中所述(参见this comment)。
选项#2 - WSL1
我还建议,如果适合您的工作流程并且您的Web应用程序在其上运行,则可以简单地使用WSL1而不是WSL2。您可以通过以下方式尝试:
备份现有的发行版(从PowerShell或cmd中使用wsl --export <DistroName> <FileName>) 使用wsl --import <NewDistroName> <InstallLocation> <FileNameOfBackup> --version 1将备份导入新的WSL1实例 可以直接更改版本,但我倾向于在进行更改之前先备份,只要您备份了,也可以将原始文件保留在原位。
可能的选项#3 - socat转发或隧道

虽然我没有直接测试过你的特定用例,但我已经在WSL2中成功地使用了。从外观上看,可以用于将端口转发从WSL2到(至少)Windows主机(这对Docker容器是可访问的)。请参见this comment一个关于类似用例的GitHub示例。

可能的选项#4 - WSL2桥接模式

上面引用的GitHub线程还介绍了如何使用Hyper-V在WSL2接口上启用桥接模式的一些详细信息。我相信这需要Windows 10专业版或企业版。与选项1一样,每次重启后都必须执行此操作。如果端口转发或WSL1可以实现您所需的功能,则可能过于复杂。


听起来可能可行,但是那个IP地址会改变,因为我会带着我的笔记本电脑旅行,所以我必须在容器启动之前检索它并设置它,或者我错过了什么? - Dan Macak
4
在这个答案中所描述的host.docker.internal是否可以解决这个问题? - NotTheDr01ds
2
好的,实际上可以与端口转发一起使用 - 当我使用curl https://host.docker.internal:4000时,我可以从我的本地服务器得到响应。然而,由于local.phx-cd.shoepping.at域名连接到受信任证书,我想使用它来代替docker内部。我看到`host.docker.internal`是在/etc/hosts中生成的条目,因此使其正常工作的一种方法是在Ubuntu的启动时运行脚本以检索docker内部IP,并将我的服务器域名与此IP输入。是否有更好的方法? - Dan Macak
注意到你的 docker-compose.yamlextra_hosts 中有 local.phx-cd.shoepping.at:10.99.99.1,但是在正文中提到它被映射到了 127.0.0.1。最好在组合文件中将其映射到 127.0.0.1。 - NotTheDr01ds
我将它映射到10.99.99.1,因为这是docker主机网络(Ubuntu)的网关。如果我将它映射到127.0.0.1,它将解析为容器的本地网络,该网络不知道桥接模式下docker主机的本地服务器。我还尝试了端口转发,并将extra_hosts解析为127.0.0.1,但仍然无法使用curl访问我的Web服务器。我想最好的解决方案是在与selenium相同的网络中运行我的Web服务器容器,或者像上面提到的那样玩一下/etc/hosts。无论如何,感谢您的帮助! - Dan Macak
显示剩余5条评论

6

以管理员身份在 PowerShell 上运行此命令:

用浏览器中将要使用的端口替换{#requiredWindowsPort}

用想要连接到的在 WSL2 中运行的端口替换{#requiredWSL2Port}

netsh interface portproxy add v4tov4 listenport={#requiredWindowsPort}
listenaddress=0.0.0.0 connectport={#requiredWSL2Port}
connectaddress=$($(wsl hostname -I).Trim());

1
这不是与NotTheDr01ds在选项#1中建议的基本相同吗? - Dan Macak
1
一样的东西,只是更短了。 - Esteban A. Maringolo

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