WSL2来了!但是能正常使用并不简单

盼星星盼月亮终于盼到 WSL2 正式发布了。之前虽然在 Windows Insider 渠道已经放出,但是因为 工作原因不敢贸然将 Windows 升级到预览版。5 月 28 日,我第一时间使用 Windows 易升 将系统 升级为 2004 版本,并安装了 WSL2,但在安装和使用过程中遇到了一些问题。下面我将记录这些经历, 并给出我自己的解决办法。

本文首发于本人博客0x1C.dev,欢迎访问以获得更好的阅读体验。

为什么要升级到WSL2

用过 WSL 第一代的朋友一定都遇到过一些比较蛋疼兼容性的问题,这些问题是由于 WSL 并不“完整”导致的。说到底 WSL 还只是一个用于访问 Linux 环境的兼容层,并没有实现 Linux 内核的完整功能。比如,我遇到了这些情况:

  • 无法启动Go的 Debug 进程,导致调试Go程序很麻烦
  • 需要在 WSL 下单独安装一套 Docker 引擎,并进行额外配置
  • 在 WSL 下启动 VS Code 后,会出现目录中文件被占用的情况,导致无法重命名,必须要先退出 VS Code
  • 无法正常使用 Linux 下全部命令,比如netstat

而 WSL2 基于Hyper-V功能的子集提供了“真正的 Linux 内核”,因此上述问题也被解决了。同时,WSL2 也 支持 Windows 10 家庭版,因此之前家庭版不能用 Docker Desktop 的情况也已经成了历史。 这对于习惯使用 Linux 开发,但是又需要 Windows 玩游戏,同时不希望用盗版的有志青年们来说简直是天大的福音。

升级到WSL2

下面的所有命令均需在有管理员权限的 PowerShell 中执行

A. 安装WSL2功能模块

  1. 如果之前没有用过 WSL,那么首先需要安装 Windows 10 的 WSL 功能:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

2. 安装 WSL2 功能模块:

dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

3. 上面的命令执行完毕后,重启电脑完成 WSL2 的安装。

B. 安装Linux内核

  1. 至此为止我们只是开启了 WSL2 的功能,但是还需要安装对应的 Linux 系统内核。 请按照官方文档中的说明下载并安装对应软件包。
  2. 在 PowerShell 中,将 WSL 默认版本设置为2,这样之后安装的 Linux 发行版才会都安装在 WSL2 中。若没有安装上一步中的内核,此时系统会提醒你到对应的网址下载内核并安装。
wsl --set-default-version 2

C. 安装Linux发行版

  1. 备份旧版 WSL 中的重要文件,比如 shell 配置文件等。卸载旧版 Linux 发行版,然后从 Microsoft Store 中重新下载安装 Linux 发行版, 比如 Ubuntu 18.04。
    虽然 WSL 提供了版本转换工具(例如可以执行,wsl --set-version Ubuntu-18.04 2),但在实际安装过程中,我的电脑转换了 3 个小时都没有成功,而且内存占用一直在 98%以上(我是 32G 内存),同时还吃掉了我所有的 C 盘空间,导致我一度无法工作。
    这是因为这个转换工具会把原发行版中的所有文件都重新复制到一个新的虚拟硬盘中(ext4 格式),而且 WSL2 对 NTFS 文件系统访问速度很慢, 耗时可想而知。因此最简单的办法,就是干掉原发行版,然后再重装一个新的。
  2. 到此为止大功告成,可以使用wsl命令启动 WSL2 了,你会发现 WSL2 的启动速度有显著提高。
    在 PowerShell 中使用如下命令可以检查是否安装成功:
wsl --list --verbose

从输出信息中可以看到,Ubuntu-18.04的版本确实已经是2

使用新版Docker后端引擎

Windows 下的 Docker Desktop 一直以来都是我心中的痛。为了使用这个完整版的 Docker 引擎,我不得不:

  • 使用更贵的 Windows 10 专业版
  • 进行更复杂的 Docker 引擎配置
  • 忍受 1 分钟左右的 Docker 启动时间

而随着 WSL2 的发布,Docker Desktop 也发布了支持 WSL2 后端的新版本,上述问题都不是问题了。

如果你之前一直在用 Docker Desktop 并设置了开机启动的话,会发现在安装 WSL2 并重启电脑后,Docker Desktop 会 自动弹出一个提示框,告诉你监测到系统中已安装了 WSL2,询问是否开启 WSL2 后端引擎。此时可以点 Enable 直接启用。

如果没有在上面的情况下启用,也可以打开 Docker Desktop 的设置界面,并在左侧导航栏中进入Resources>WSL INTEGRATION 面板,然后开启界面中的开关,如下图所示:

保存设置并重启 Docker,然后进入 WSL2,你会发现docker命令和docker-compose命令都可以正常使用了,无需任何额外操作! ️

文件访问慢 & 无法 Hot-Reloading

安装 WSL2 后我赶紧打开本博客项目,并在开发环境下继续未完成的工作。但是发现:

  • 文件系统 I/O 巨慢,Gatsby 开发环境的编译时间大大增长,git的反应也很慢
  • 更致命的是,在编辑过程中我发现保存文件后系统没有监测到文件变化,因此也没有进行 Rebuild 的过程。 这意味着我每进行一个改动,都需要完整重新编译整个项目才能看到效果。

这事儿真心忍不了。

在进行了一番调(sou)研(suo)后,发现这些都是 WSL2 的已知问题,主要还是由于 Windows 和 Linux 两种文件系统的兼容性尚未被很好的处理。 详细的讨论可参见#4197#4739这两个 issue。

目前的解决办法只有一个:将项目文件移动到 Linux 文件系统下

好吧。 ‍♂️

配置代理服务器正常科学上网

另一个巨坑,也是本文重点所在,是在 WSL2 下如何连到 Windows 的代理服务器来走向世界。 这个问题耗费了我几乎整个下午的时间。

A. 获取Windows主机IP

你会发现 WSL2 不再能正常访问localhost的各种端口了。比如我们在 Windows 下启动一个简单的 HTTP 服务器:

python -m http.server

然后在 WSL2 下尝试访问:

curl http://localhost:8000

结果是没有响应,连接直接超时或关闭。这时候我已经疯了,于是又开始了疯狂的探(sou)索。 在这篇博客官方文档中 我找到了答案:新的 WSL2 架构会为 Linux 系统分配一个虚拟网卡,Linux 虚拟机与 Windows 组成了一个局域网,因此 若想在 Linux 下访问 Windows 的服务,必须要使用 Windows 的主机地址。

通过查看 Linux 下的 DNS 设置可以得到 Windows 主机的地址:

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 192.168.112.1

上面的输出中,nameserver之后的部分就是 Windows 主机 IP。

B. 代理服务器自动设置工具

Windows 主机 IP 在每次重启后都会变化,因此我写了 一个 bash 脚本以便在 shell 启动时自动设置代理服务器,源码在此,也可以使用下面的命令直接获取安装:

中文版:

curl -o wslproxy -L https://git.io/Jfo6z
sudo bash ./wslproxy install

英文版:

curl -o wslproxy -L https://git.io/Jfo62
sudo bash ./wslproxy install

然后根据命令行提示使用即可。

C. Windows防火墙设置

在设置代理服务器后,我发现仍然无法正常连接 Windows 上的服务。研究很长时间后才发现,

Windows 防火墙居然拦住了来自 WSL 的请求!!!

佛了。Windows 认为 WSL 的虚拟网卡是公用网络,因此任何阻止公用网络入站请求的防火墙策略都会拦住 WSL 发过来的请求。

知道了问题所在就好办了。

  1. 首先我们使用 PowerShell 命令行创建一条给 WSL 网卡的防火墙策略:
New-NetFirewallRule -DisplayName "WSL" -Direction Inbound  -InterfaceAlias "vEthernet (WSL)"  -Action Allow

2. 然后进入 Windows 的防火墙和网络保护设置,在界面下方点击高级设置,提权后会打开高级安全 Windows Defender 防火墙窗口。

3. 在高级安全 Windows Defender 防火墙中选择入站规则,并在右侧找到你使用的代理软件,然后禁用对应的阻止公用网络的规则, 比如我的是这样:

4. 防火墙规则设置完毕后,应该已经可以在 Linux 中正常连接到代理服务器了。


欢迎在下方评论区或访问我的博客0x1C.dev分享您的看法!


参考资料

发布于 05-29

文章被以下专栏收录