关于Windows子系统(WSL/WSL2)的一些探究

目前博主日常工作已经离不开WSL了,但是即使每天使用,对WSL系统的一些细节上的实现还是一知半解,为此,特地去了解了一番,并做一下记录,方便日后查阅。

Windows WSL1 和 WSL2的网络机制及各自的原理

  • 实现机制差异
    WSL1 和 WSL2 的网络机制的主要区别在于,WSL1 是通过一个转换层来实现对 Linux 系统调用的支持,而 WSL2 是通过在轻量级虚拟机内运行一个实际的 Linux 内核来实现完整的系统调用兼容性。

  • 不用的网络方式

    1. 从 Windows 访问 WSL2 网络应用时,可以使用 localhost 作为 IP 地址,就像访问本地应用一样。
    2. 从 WSL2 访问 Windows 网络应用时,需要使用主机的 IP 地址,可以通过在 Linux 分发版中运行 cat /etc/resolv.conf 命令来获取。
    3. 从局域网 (LAN) 访问 WSL2 分发版时,需要添加一个端口代理来将主机上的端口映射到 WSL2 的 IP 地址和端口。
  • WSL1 和 WSL2 的网络机制的原理是:

    1. WSL1 是通过一个转换层来拦截 Linux 系统调用,并将其转换为 Windows 系统调用,从而实现对 Linux 应用的支持。这样,WSL1 可以直接使用 Windows 的网络栈和 IP 地址,无需额外的配置。
    2. WSL2 是通过 Hyper-V 功能来创建一个轻量级虚拟机,并在其中运行一个完整的 Linux 内核,从而实现对 Linux 应用的支持。这样,WSL2 就有了自己的虚拟化以太网适配器和 IP 地址,与 Windows 的网络栈是隔离的。为了实现 Windows 和 Linux 之间的网络互通,WSL2 使用了一种叫做 Plan9 协议的技术,来在虚拟机和主机之间共享文件和端口。

目前尚未支持WSL直接访问纯ipv6网络

性能:WSL1 vs WSL2

WSL1 和 WSL2 在性能方面的区别主要体现在以下几个方面:

  1. 文件系统性能:WSL2 在文件密集型操作(如 git 克隆、npm 安装、apt 更新等)上比 WSL1 快很多,因为它使用了一个真正的 Linux 文件系统,而不是通过转换层来访问 Windows 文件系统。
  2. 系统调用兼容性:WSL2 支持完全的系统调用兼容性,可以运行更多的 Linux 应用,例如 Docker 等,而 WSL1 只能支持一部分系统调用,有些应用可能无法正常工作。
    启动时间和资源占用:WSL1 和 WSL2 都有较短的启动时间和较少的资源占用,相比传统的虚拟机体验更加轻量级和快速。
  3. 跨操作系统文件访问:WSL1 可以更快地访问从 Windows 装载的文件,而 WSL2 需要通过 Plan9 协议来共享文件和端口,因此在跨操作系统的文件访问上性能会有所下降。
  4. 内存管理:WSL2 的内存使用量会随使用而缩放,并且在进程释放内存时会自动返回到 Windows。但是,WSL2 目前还不会在关闭实例前将内存中缓存的页面释放回 Windows,这可能会导致 Windows 内存耗尽。

在 Windows 上安装和使用 WSL2

在 Windows 上安装和使用 WSL2 的方法有:

  1. 使用单个命令:在管理员模式下打开 PowerShell 或 Windows 命令提示符,输入 wsl --install 命令,然后重启计算机。这样会启用 WSL 功能并安装 Ubuntu 发行版。
  2. 使用手动步骤:首先启用 WSL 功能和虚拟机平台功能,然后下载 Linux 内核更新包,再设置 WSL2 为默认版本,最后从 Microsoft Store 中选择并安装 Linux 发行版。

安装好 WSL2 后,可以使用 wsl 命令来管理和使用 Linux 发行版,例如:

  1. wsl -l -v : 列出已安装的 Linux 发行版和它们的 WSL 版本
  2. wsl -d <distro name> : 运行指定的 Linux 发行版
  3. wsl --set-version <distro name> 2 : 将指定的 Linux 发行版升级到 WSL2
  4. wsl --shutdown : 关闭所有运行的 Linux 发行版

还可以使用 Windows 终端、VS Code、Docker Desktop 等工具来增强 WSL2 的体验。

在 WSL 中安装和使用 Docker(仅WSL2支持)

在 WSL 中安装和使用 Docker 有两种方式,一种是在 WSL2 中直接安装原生的 Linux 版 Docker,另一种是在 Windows 中安装 Docker Desktop for Windows,并启用基于 WSL2 的引擎。

第一种方式的步骤如下:

  1. 在 WSL2 中安装喜欢的 Linux 发行版,例如 Ubuntu,并更新系统和软件源。
    在 Linux 发行版中运行 curl -fsSL https://get.docker.com -o get-docker.sh 命令,下载 Docker 的安装脚本。
  2. 运行 sudo sh get-docker.sh 命令,执行安装脚本。注意,脚本会提示使用 Docker Desktop for Windows,可以忽略这个提示,等待 20 秒后继续安装。
  3. 运行 sudo service docker start 命令,启动 Docker 服务。
  4. 运行 docker --version 命令,检查 Docker 的版本和内部版本号。
  5. 运行 docker run hello-world 命令,测试安装是否正常工作。

第二种方式的步骤如下:

  1. 在 Windows 中下载并安装 Docker Desktop for Windows。
  2. 启动 Docker Desktop for Windows,并从任务栏的隐藏图标菜单中选择 Docker 图标。
  3. 右键单击该图标以显示 Docker 命令菜单,然后选择“设置”。
  4. 确保在“设置”>“常规”中选中“使用基于 WSL2 的引擎”。
  5. 通过转到“设置”>“资源”>“WSL 集成”,从要启用 Docker 集成的已安装 WSL2 发行版中进行选择。
  6. 重启 Docker Desktop for Windows,重启完成后即可在 WSL2 中使用 docker 命令了。

无论使用哪种方式,在 WSL 中安装和使用 Docker 都需要计算机支持 WSL2,并且已经开启了虚拟化功能。

Docker Desktop使用WSL2作为后端与Hyper-V后端的性能说明

  1. WSL2 使用了一个完整的 Linux 内核,可以直接运行 Linux 的二进制文件,而不需要模拟或转换系统调用,这样可以提高执行效率和兼容性。
  2. WSL2 使用了动态内存分配的特性,可以根据需要调整 docker 的 CPU 和内存资源,而不需要预先分配固定的资源。这样可以减少资源的浪费和竞争,提高容器的启动速度和运行速度。
  3. WSL2 使用了一个虚拟化的以太网适配器,可以实现 Windows 和 Linux 之间的高速网络通信,而不需要通过 NAT 或端口映射。这样可以提高网络的性能和稳定性。

对应两种方式在WSL2里安装docker,把运行的容器的端口暴露到Windows的方法

WSL2原生安装Docker

  • 配置端口转发规则的一般步骤是:
    • 在 Windows 防火墙中开放要转发的端口,例如 2280 等。
    • 在 PowerShell 中以管理员身份运行netsh interface portproxy add v4tov4命令,指定监听端口,监听地址,连接端口和连接地址。
    • 监听地址可以设置为 0.0.0.0,表示匹配所有地址。
    • 连接地址可以设置为 localhost 或者 WSL2 的 IP 地址。
    • 连接端口应该和容器启动时指定的端口映射一致,例如 -p 80:80

举例:如果想从局域网的其他主机上通过 ssh 连接到 WSL2 里的 docker 容器,需要在 Windows 中执行以下命令:

netsh interface portproxy add v4tov4 listenport=22 listenaddress=0.0.0.0 connectport=22 connectaddress=localhost

这样就可以将 Windows 的 22 端口转发到 WSL2 的 22 端口,然后就可以使用的 Windows 的 IP 地址和 22 端口来 ssh 连接到 WSL2 里的 docker 容器了。

查看或删除已经配置的端口转发规则,可以在 PowerShell 中运行以下命令:

netsh interface portproxy show all # 查看所有规则
netsh interface portproxy delete v4tov4 listenport=22 listenaddress=0.0.0.0 # 删除指定规则

这是因为 WSL2 使用了一个虚拟化的以太网适配器,它有自己的 IP 地址,和 Windows 不在同一个网络。

安装Docker Desktop并选用WSL2作为backend

在 WSL2 里安装的 Docker 容器,可以通过 localhost 或者 Windows 的 IP 地址来访问,只要在 Windows 中开启了防火墙的相应端口,并且在 Docker 容器中也指定了相应的端口映射。

例如,在 WSL2 中运行了一个 web 服务,监听了 80 端口,可以在 Windows 中打开浏览器,输入 localhost 或者的 Windows 的 IP 地址(可以通过 ipconfig 命令查看),就可以访问到这个 web 服务。

Docker Desktop for Windows 通过在 Windows 和 WSL2 之间建立端口转发规则,使得可以直接通过 localhost 或者 Windows 的 IP 地址来访问容器端口。

在 WSL 中配置网络代理

在 WSL 中配置网络代理的方法有多种,根据使用的代理软件和协议的不同,可能需要不同的步骤。一般来说,需要做以下几件事:

  • 在 Windows 中找到的代理软件的监听端口和 IP 地址,通常是 127.0.0.1 或者的本机 IP 地址。
  • 在 Windows 中打开防火墙设置,允许的代理软件和 WSL 之间的网络通信。
  • 在 Windows 中启用“允许来自局域网的连接”或者类似的选项,让的代理软件接受来自 WSL 的请求。
  • 在 WSL 中设置环境变量,例如 http_proxyhttps_proxyall_proxy 等,指向的代理软件的监听端口和 IP 地址。注意,如果使用的是 WSL2,那么不能使用 127.0.0.1 来指向 Windows,而要使用的本机 IP 地址或者 WSL 的网关地址(可以通过 cat /etc/resolv.conf 命令查看)。
  • 在 WSL 中测试的代理配置是否生效,例如使用 curlaptgit 等命令。

为docker容器配置全局代理

全局配置:在 docker 客户端的配置文件 ~/.docker/config.json 中添加 proxies 字段,指定 httpProxyhttpsProxynoProxy 等代理信息。这样在创建或启动新的容器时,代理信息会自动传递给容器。这种方法需要 docker 17.07 或更高版本。

为docker容器单独配置代理

单独配置:在创建或运行容器时,使用 --env-e 标志,设置 HTTP_PROXYHTTPS_PROXYFTP_PROXYNO_PROXY 等环境变量,指定代理信息。这种方法可以针对不同的容器设置不同的代理。

总结

相信看完这篇文章,你和我一样,会对Windows的WSL有一个更深入的理解,一起Mark!