WSL-Windos-Docker的互相网络访问

记录安装了WSL2以及Docker的Windows系统上,如何进行WSL、Windows、Docker之间的网络访问

# 为什么会有网络互相访问问题

现在的Windows10以及Windows11支持WSL子系统,对于硬件上安装Windows系统又需要Linux环境的开发人员来说十分实用。然而WSL在Windows系统中属于一种特殊的虚拟机,有特殊的网络桥接。同理,如果配置了基于WSL2的Docker,也是以特殊的方式进行网络桥接。如果在WSL或Windows中开启网络服务,在另一个系统中则有时会难以访问。因此记录一下我了解到的几种访问方式。

注:参考文档:

  1. 参考1:微软官方WSL网络相关文档
  2. 参考2:wsl-访问-windows-服务

# 环境信息

  • 操作系统: Windows11 22H2
  • WSL2
  • Docker Desktop for Windows
  • Docker Desktop中配置实用Use the WSL 2 based engine,基于WSL2运行Docker

# Windows与wsl2互相访问网络服务

# WSL2访问Windows网络服务

# 原理

WSL2每次在Windows中开机时,都会重新分配本机中Windows的ip地址 可以输入 cat /etc/resolv.conf 命令查看 Windows 端 IP:

1
2
3
4
5
➜  ~ cat /etc/resolv.conf
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 172.29.32.1

# 方式1

在WSL中通过绑定Windows ip到指定域名来访问

新建脚本,命名为 changeHosts.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# hosts edit
winIp=$(cat /etc/resolv.conf | grep -oP '((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}')
CUSTOM_ADDRESS="win.local"
addressInfo=$(cat /etc/hosts | grep -oP $CUSTOM_ADDRESS)
if [ -z "$addressInfo" ]; then
    # if [ $EUID != 0 ]; then
    #     sudo "$0" "$@"
    #     exit $?
    # fi
    echo "未找到自定义地址,将会进行添加..."
    echo "$winIp $CUSTOM_ADDRESS" >> /etc/hosts # 申请权限
    echo '完成'
else
    customAddressLineNumber=$(grep -n "win.local" /etc/hosts | cut -d : -f 1)
    originalIp=$(sed -n "$customAddressLineNumber"p /etc/hosts | grep -oP '((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}')
    # 如果 hosts 中 ip 和真实 ip 不相等,则进行更新
    if [ "$winIp" != "$originalIp" ]; then
        echo 'hosts 中 ip 和真实 ip 不一致,进行更新...'
        param=$customAddressLineNumber"d"
        sed -i "$param" /etc/hosts
        echo "$winIp $CUSTOM_ADDRESS" >> /etc/hosts
        echo '完成'
    fi
fi

这个脚本中,每次运行都会在WSL中读取/etc/resolv.conf获取WSL启动时自动获取的Windowsip,将宿主机ip地址绑定到本地域名win.local。手动运行一遍 sudo ./changeHosts.sh 就能在WSL中通过win.local来访问windows。

例如我在windows的8081端口开了一个spring 服务,那么在WSL中就可以这样访问:

1
2
$ curl win.local:8081
{"code":200,"msg":"success","data":null}%

也可以将这个脚本设置自动启动,这样每次开机后都会自动设置win.local

# 方式2

如果宿主机的Windows在局域网中使用静态ip地址,那么在WSL中直接通过局域网中Windows的固定ip地址访问即可。注:需要让程序监听0.0.0.0而不是127.0.0.1

# 防火墙

注意:方式2在访问时,为局域网访问。需要在Windows中注意防火墙问题,打开对应网络服务。方式1则是使用Windows系统自带NAT,为内部访问,没有这个问题

# Windows访问WSL2网络服务

微软已经帮忙做了映射,直接通过localhost:port的形式可以直接访问WSL2中Web服务对应的port

# Windows与Dcoker互相访问网络服务

# Docker访问Windows网络服务

Docker Desktop for Windows使用特殊的DNS,它将解析为主机使用的内部IP地址

不同版本Docker中可能可用的域名:

1
2
host.docker.internal
gateway.docker.internal

在容器中可直接通过类似curl host.docker.internal:port的方式直接访问

# Windows访问Docker网络服务

微软和Docker已经帮忙做了映射,直接通过localhost:port的形式可以直接访问Docker中容器暴露的port。需要注意Docker中服务和WSL2中服务都占用同一个端口的特殊情况

# Windows与WSL的文件互相访问

写都写了,顺便写一下文件系统的互相访问

# Windows访问WSL文件

打开Windows资源管理器。直接输入\\wsl$就可以看到对应的WSL主机根目录对应的文件夹,但这里默认的是根目录。所以更建议访问的是 \\wsl$\Ubuntu\home\你的用户名,对应的是Linux系统中的home文件夹。可以将这个文件夹保存到资源管理器的快速访问中,方便点击

还有需要注意的是:使用资源管理器直接访问时,输入的文件可能会出现windows与linux系统的文件格式冲突等奇怪问题。我的建议是:

  1. 对于大型资源文件,可以用zip压缩包的形式从windows资源管理器复制到wsl系统中再unzip,速度会比较快
  2. 对于程序源码等文本文件,最好使用VSCode等IDE提供的连接到WSL功能,直接在WSL中编写。这样默认是Linux文件格式,不太容易出错

# WSL访问Windows文件

直接在终端中输入ls /mnt,会看到

1
2
ls /mnt
c  d  e

可以发现windows中的c d e等硬盘被挂载到了/mnt目录下,直接使用cd等命令访问即可。但同样需要注意Windows和Linux的文件格式不同的问题

# 写在最后

以上只是一些我认为方便的简单做法的记录。如果遇到复杂问题,还是建议参考微软官方文档

使用 Hugo 构建
主题 StackJimmy 设计