WSL 疑难解答

持续更新 WSL 相关的问题。注意本文所提到的 WSL 实际上都是 WSL2,它和 WSL1 的区别可见文末;此外,本文默认使用 Ubuntu 作为 WSL 实例,它可以从 Microsoft 商店 中直接下载安装。

推荐使用微软的官方文档来进行 WSL 的 安装配置,这个配置页面建议使用英文版本,因为中文版会把一些指令、配置关键字也机翻成英文。

运行报错解决

此部分内容转载自 名实合为,原文链接:https://blog.mjyai.com/2020/06/01/win10-wsl2-ubuntu/ (作者:mjy)。
文中提到的问题,我自己也遇到过,经过这些解决方案的实践,结果证明可以奏效。


报错:WslRegisterDistribution failed with error: 0x800706ba 解决:

首次运行 Ubuntu 时报错:

Installing, this may take a few minutes...
WslRegisterDistribution failed with error: 0x800706ba
Error: 0x800706ba The RPC server is unavailable.

Press any key to continue...

产生此错误可能有两个原因:

原因1,LxssManager 服务未正常运行:

此时以管理员身份运行终端,重启服务:

sc stop LxssManager
sc start LxssManager

# 然后可以通过下面这个指令检查服务运行状态
sc query LxssManager

原因2,也可能是 DNS Client 服务未运行:

运行 service.msc 查看此服务,如果没有开启,则将它开启。
如果此服务启动按钮为灰色不可点击,此时需要修改注册表:

运行 regedit,找到 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Dnscache 目录,将 Start 值从 4(禁用)改为 2(自动),然后重启电脑。


报错:参考的对象类型不支持尝试的操作(The attempted operation is not supported for the type of object referenced.):

以管理员身份运行终端:

netsh winsock reset

这个问题的原因是,WSL 通讯和 Proxifier 通过 Winsock LSP 抓取 TCP 连接产生冲突。
如果重置 Winsock 后 WSL 正常,但是 Proxifier 无法工作,可以参考 Proxifier 作者提供的方案
下载 http://www.proxifier.com/tmp/Test20200228/NoLsp.exe,然后用管理员权限的终端运行它,参数:.

NoLsp.exe c:\windows\system32\wsl.exe

这可以使 WSL 绕开 Proxifier 修改过的 LSP。

配置文件

我们可以创建一个 %userprofile%\.wslconfig 配置文件,格式为常规的 ini 配置格式,它会成为当前电脑上所有 WSL 实例的公用全局配置,具体参考 微软官方文档(建议切换英文版,中文版会把关键字也给机翻了)。
(更新这个配置文件,建议重启计算机)

此外,每个 WSL 实例下的 /etc/wsl.conf 是实例的本地配置,这里面的字段优先级更高,格式和上面的相同,文档也在同一个页面,但可用的字段和上面的不同。
(更新这些配置文件,需要重启 WSL 实例来生效)

这两种配置文件,推荐的使用方式是:

  • 前者 %userprofile%\.wslconfig 有一些宿主机相关的配置,可以通过它来限制 WSL 实例享受的硬盘、内存、CPU 等硬件资源,这些也只能在这里配置;
  • 后者 /etc/wsl.conf 用于具体的 WSL 实例的配置,例如文件系统和网络与宿主机的互访问性,且配置在各个实例之间互不干扰,实例相关的配置推荐使用这个文件。

安装位置移出 C 盘

WSL 默认安装目录在 C 盘,如果想移动到别的目录,可以通过这个流程:
首先检查 WSL 运行的实例,如果有运行中的实例,需要先停止:

# 列出所有 WSL 实例和运行状态
wsl --list -v

# 停止 Ubuntu 实例的运行
wsl -t Ubuntu

使用 wsl export 指令将 WSL 导出成压缩包,导出到任意临时目录即可:

wsl --export Ubuntu "D:\wsl_export\ubuntu-export.tar"

从系统中取消注册 WSL 实例:

wsl --unregister Ubuntu

使用 wsl import 重新导入和激活 WSL 实例:

# 注意这里第一个 D:\wsl_new_directory\ubuntu 目录就是转移之后 WSL 实例的目录
wsl --import Ubuntu "D:\wsl_new_directory\ubuntu" "D:\wsl_export\ubuntu-export.tar"

然后就可以删掉之前导出的压缩包了。

默认用户改为 ubuntu

WSL 安装后,如果默认登录用户是 root,可以改为 ubuntu,有两种方式:

第一种方法,在 Windows 管理员终端中执行:

ubuntu config --default-user ubuntu

这种方式简单直接,如果你只有一个 WSL 实例,这个方式非常适合;

第二种方法,进入 WSL 实例,创建 /etc/wsl.conf 文件并填写:

[user]
default = ubuntu

这种方法可以为每个 WSL 实例单独设置默认用户,且它的优先级更高,会覆盖第一种方式。

默认起始路径改为 ~

每次进入 WSL,默认的路径均为 /mnt/c/Users/用户名,通常我们都想直接进入用户目录 ~

简单的方式,就是修改 Windows 终端的启动目录,新版 Windows 11 的终端可以配置,如图所示:

这样通过 Windows 终端进入 WSL,启动目录就是 ~ 了。

但是如果不是使用 Windows 终端,比如使用 cmd 或者 PowerShell,或是旧版的 Windows 系统没有这个终端应用,这个配置便不起效,此时进入 WSL 时的起始目录还是原来的目录。


不推荐使用这种方式:
在 WSL 实例中编辑 ~/.bashrc,在其内容最尾部添加:

cd ~

这样每次启动 WSL 实例的终端,就会自动进入到 ~ 目录。
但是,从 VSCode 等终端打开项目,也会强制进入 Home 目录,会很不方便。

与 Docker 协作

可以参考微软的 官方中文文档Docker 官方的文档

安装 Docker Desktop 时,便会提示是否使用 WSL 引擎来运行 Docker,推荐使用。Docker 使用 WSL 引擎时,即使终端全部关闭,WSL 也会处于运行的状态;用户主动自己关闭或重启 WSL 时,也会使 Docker 一起关闭或重启,此时 Docker Desktop 会弹出警告。

使用 WSL 作为 Docker 引擎后,执行 wsl --list -v 便可以看到多了 2 个实例:

  NAME                   STATE           VERSION
* Ubuntu                 Running         2
  docker-desktop         Running         2
  docker-desktop-data    Running         2

这里的 docker-desktop 用于运行 Docker 引擎(dockerd),而 docker-desktop-data 用于存储容器和镜像。

即使在安装时没有选用 WSL,也可以后续在 Docker Desktop 设置页面找到 “Use the WSL 2 based engine” 复选框修改设置。
如果你已有运行了的 WSL 的实例,也可以在 Docker Desktop 设置页面的 Resources > WSL integration 页面找到各个 WSL 实例,并配置允许哪些实例访问 Docker,在这些实例里面可以直接执行例如 docker ps 等命令。


如果你运行 WSL 实例后不会自动开启 Docker,可以编辑 WSL 实例的 /etc/wsl.conf,添加以下配置:

[boot]
command = service docker start

与 VS Code 协作

可以参考微软的 官方中文文档

安装 VS Code 的远程开发扩展后,需要对 WSL 实例做一些操作:
首先,需要在 WSL 实例中安装 Git、Vim 等常用工具:

sudo apt-get update
sudo apt-get install -y git vim

然后,推荐把宿主机的 SSH 公钥拷贝过来直接使用:

cp -r /mnt/c/Users/用户名/.ssh ~/.ssh

# (重要)一定要改好权限,SSH 对密钥文件的权限很敏感
chmod 700 ~/.ssh
chmod 600 ~/.ssh/*

SSH 的密钥权限尽量设置为 600(也就是 -rw-------),过高的权限会导致 SSH 报错提示。

在 WSL 实例里开发,可以直接在 WSL 的实例中安装 Node.js 等环境;
更推荐的做法是,把运行环境放在 Docker 镜像里,随项目提供 Docker Compose 配置和 Dockerfile,这样在 VS Code 连接 WSL 后,可以直接运行 docker compose up (此时不需要 -d 参数)来启动项目。目前 PaperPlane 的大部分项目均使用这种开发方式。

WSL 1 和 2 的区别

WSL1 和 2 的实现原理不同,因此它们之间有很大的区别:

  • WSL1 使用转发适配层对 Linux 提供支持,因此它的性能较差、程序无法直接访问硬件(影响较大),而且存在兼容性问题,例如 Docker 就无法在 WSL1 中运行(这一点很致命);
  • 相比之下,WSL2 可以做到对 Linux 的完全兼容,可以运行 Docker 等多种大型软件,程序也可以访问硬件;
  • WSL1 也并不是完全没有优点,它占用的资源少、启动速度快;而 WSL2 需求最低 Windows 10 版本并开启 Hyper-V 功能、需求 CPU 支持硬件虚拟化,对计算机软硬件要求比较高;
  • 此外,WSL1 的文件系统直接使用 NTFS,而 WSL2 使用的是 ext4 文件系统,所以必须通过网络地址来访问 WSL 内部的文件,这使得 WSL2 的文件系统性能不佳,例如在 Windows 中修改文件后,WSL2 中的程序很久才能监听到文件变动。

可以看出 WSL2 有更优秀的特性,以后 WSL2 也势必会成为主力发展和流行的版本。
现在安装 WSL 已经默认都是 WSL2 版本了。在早期版本,可能需要执行 wsl --set-default-version 2 指令来手动切换。