如何从 Docker 容器内部访问运行在 WSL2 上的服务?

30

我正在使用Windows 10 1909,并已安装WSL2,使用Ubuntu 20.04,19.03.13-beta2 docker版本,使用WSL2选项安装了Docker for Windows Edge版本。集成工作得非常好,但是我有一个问题无法解决。

在WSL2实例中,有一些运行的服务,暴露一些端口(3000、3001、3002等)。从其中一个docker容器中,我需要访问这些服务以进行特定的开发场景(API网关),但我无法使其工作。

我尝试直接使用WSL2 IP地址,但连接超时。我还尝试使用host.docker.internal,它解析为与WSL2 IP地址不同的内容,但仍然无法工作。

我需要采取特殊的技巧吗?或者当前不支持此类路由但将会支持,或者由于其他原因不可能实现吗?

这说明了我的目标:

Accessing WSL2 services from docker container

其他路由起作用-即我可以从Windows浏览器访问来自WSL2内的node.js进程的所有服务端口,而且我还可以从WSL2内部和Windows中的容器访问公开的服务端口。只是这个缺失的链接我无法使其工作。


1
我发誓我没有改变任何东西,但今天它可以工作了! - donmartin
2
我也发誓我没有改变任何东西,而且这在过去对我有效,但今天它不再起作用了...(如果我弄清楚了我做了什么,我会回报的...) - Addshore
@donmartin,你找到解决方法了吗? - Mateusz Mańka
不行,但是也有可能。大部分时间都能正常工作。没有任何更改。 - donmartin
4个回答

11

所以在 Windows 机器上,您需要进行端口转发以与运行在 WSL 机器上的端口通信。这个脚本将端口 4000 进行了转发。

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"

在容器的docker run命令中,你必须添加以下内容:

--add-host=host.docker.internal:host-gateway

如果你正在使用docker-compose:

    extra_hosts:
      - "host.docker.internal:host-gateway"

然后在容器内,您应该能够使用curl命令进行访问。

curl host.docker.internal:4000

并获取响应!


6

就这个问题而言:如果使用WSL2子系统的IP地址,则可以正常工作

如果使用 host.docker.internal,则无法工作 - 此DNS别名在容器中定义,但它映射到Windows主机的IP地址,而不是WSL2主机的IP地址,返回WSL2主机内部路由时会出现问题。

目前还不太清楚为什么(可能是暂时的原因) - 如果问题再次出现并且我能够追踪到实际问题所在,我将重新审视此答案。


我在我的应用程序中使用 host.docker.internal,但我不通过 docker run --add-host=host.docker.internal:host-gateway ... 启动容器。如果我这样做,我就无法从容器内部连接到外部。只需通过 docker run -p 8080:8080 <etc> 启动容器即可。 - Michael

1
我遇到了最新版的Docker Desktop的问题。我将它回滚到4.2版本,然后问题得到解决。
  • Docker Desktop 4.2
  • Windows 19044.1466
  • Ubuntu 20.04
我在Linux本地主机上运行一个Java服务(使用ifconfig命令访问IP地址),我的其他容器则在基于WSL2引擎的Docker桌面上运行,并可以使用该IP地址与我的Java服务进行通信。

1

这听起来像是这里讨论的问题。对我来说,唯一有效的方法是使用--net=host运行docker容器,然后在容器中使用[::1]而不是localhost来访问在WSL中运行的其他容器。

例如,container1是使用docker run --net=host启动的,然后像这样调用container2:http://[::1]:8000/container2 (根据您的特定应用程序调整端口和路径)


通过使用--net=host,我实际上能够直接使用localhost:[port] - Anna Madsen

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