文章

【笔记】WSL 的架构、互操作与使用边界

【笔记】WSL 的架构、互操作与使用边界

WSL 不是一种固定实现,而是 Windows 提供的 Linux 运行与集成环境。WSL 1 通过系统调用转换运行 Linux binary;WSL 2 在受管理的轻量虚拟机中运行真实 Linux kernel。二者给用户暴露相近的发行版和命令体验,但 kernel、文件、网络与资源边界完全不同。

1. 中心模型:WSL 统一了体验,没有消除边界

flowchart TB
    U[Windows User]
    W[wsl.exe / WSL Service]
    D1[Linux Distribution A]
    D2[Linux Distribution B]
    K[Microsoft-maintained Linux Kernel]
    VM[Managed Utility VM]
    WIN[Windows Kernel / Files / Network]

    U --> W
    W --> D1
    W --> D2
    D1 --> K
    D2 --> K
    K --> VM
    VM <--> WIN

在 WSL 2 中,Windows 负责 VM 生命周期、kernel 更新、资源与集成;发行版提供自己的 Linux userspace、package、用户和 root filesystem。多个发行版不是多台需要分别配置硬件的传统 VM,但也不是同一个 userspace。

需要始终区分:

  • Windows process 与 Linux process;
  • Windows filesystem 与发行版 Linux filesystem;
  • Windows shell 语法与 Linux shell 语法;
  • WSL 全局配置与单个发行版配置;
  • WSL managed VM 与发行版实例。

2. WSL 1:系统调用转换层

WSL 1 没有运行真实 Linux kernel。Linux binary 发起 system call 后,由 WSL translation layer 将其映射到 Windows kernel 能力。

1
2
3
4
Linux ELF process
  → Linux system call ABI
  → WSL translation layer
  → Windows kernel

它的优势是没有独立 VM 内存与虚拟磁盘边界,访问 Windows filesystem 的路径通常更直接。限制也来自同一处:Linux kernel ABI 必须由转换层实现,新的或复杂的 kernel feature 不会自动获得完整兼容。

因此 WSL 1 不是“运行一个被精简的 Linux kernel”,也不是传统意义上的硬件虚拟机。它更接近 Windows kernel 上的 Linux ABI compatibility subsystem。

3. WSL 2:真实 Linux kernel + managed utility VM

WSL 2 使用 Microsoft 维护的开源 Linux kernel,并借助虚拟化技术运行在轻量 utility VM 中。Linux system call 由真实 Linux kernel 处理,不再逐项翻译到 Windows system call。

1
2
3
4
5
Linux process
  → Linux system call
  → WSL Linux kernel
  → virtualized CPU / memory / device boundary
  → Windows / Hyper-V platform

3.1 它是真 VM,但不是传统 VM 产品体验

WSL 2 具有 Guest kernel、虚拟 CPU、内存、虚拟磁盘和网络边界,因此属于硬件辅助虚拟化。但用户通常不需要选择固件、手工挂载 ISO、创建虚拟网卡或管理快照。

WSL service 负责按需启动、空闲回收、kernel servicing、发行版挂载和 Windows 集成。与 VMware Workstation、Parallels Desktop 等通用 VM 产品相比,区别首先是产品抽象和控制面收窄,而不是“一个是真虚拟化、另一个不是”。

3.2 发行版不是一台独立配置的 VM

一个 WSL distribution 主要是一套 Linux userspace、root filesystem、用户配置与发行版状态。WSL 2 distributions 由 WSL 管理并共享底层 VM/kernel 资源,同时通过 process、mount、user 等 namespace 隔离各自 userspace。

这解释了两个现象:

  • wsl -l -v 列出的是发行版实例,不是传统 Hyper-V Manager 中的一组完整 VM;
  • .wslconfig 的 CPU、内存、swap、kernel 等配置作用于整体 WSL 2 VM,而不是某一个发行版。

3.3 看不到 VirtIO 不代表没有虚拟化

VirtIO 是一种虚拟设备规范,不是 Hypervisor 的必选项。Hyper-V 使用 VMBus 和 synthetic devices 等自己的虚拟化接口。WSL kernel 中常见的 Hyper-V driver 名称与 VirtIO 不同,不能通过“没有 virtio-net”推出 WSL 2 没有 I/O 虚拟化。

4. 文件系统有两个存储世界

4.1 Linux root filesystem

WSL 2 发行版的 Linux filesystem 通常存放在虚拟磁盘中,保留 Linux inode、permission、symlink、case sensitivity 等语义。开发时涉及大量 Linux 小文件操作的项目,放在发行版 filesystem 中通常更合适。

Linux 中使用类似路径:

1
~/code/project

Windows 可以通过受支持的 WSL 文件入口访问,例如:

1
\\wsl$\Ubuntu\home\<user>\code

不应绕过 WSL 集成,直接用 Windows 工具修改发行版虚拟磁盘内部文件。

这条 Windows → Linux 入口与 Linux 侧的普通 mount 不是同一个抽象。部分 WSL 实现资料会提到 Plan 9/9P file server,但它属于跨边界文件服务的实现细节,不能由此推出两个方向都只是“挂载同一种 9P 文件系统”。笔记和排障应优先依赖 Microsoft 支持的路径与行为。

4.2 Windows drives

Windows drive 会挂载到 Linux 中,默认常见入口是:

1
2
/mnt/c
/mnt/d

这条路径便于 Windows/Linux 工具共享文件,但跨越 OS filesystem 边界。metadata、permission、case sensitivity、文件监听和性能不必然等同于原生 Linux filesystem。

4.3 项目放在哪里取决于主要工具

  • 主要由 Linux compiler、package manager、container tooling 操作:优先放 Linux filesystem;
  • 主要由 Windows 应用操作,偶尔调用 Linux 命令:可以放 Windows filesystem;
  • 同一目录由两侧高频并发修改:先明确 owner、watch、permission 和性能边界,不要假设完全透明。

WSL 1 与 WSL 2 的跨 OS 文件性能特征不同。Microsoft 当前仍指出,某些高频访问 Windows filesystem 的场景下 WSL 1 可能更快;不能把“WSL 2 整体更新”误写成所有文件路径都更快。

5. Windows 与 Linux 命令互操作

5.1 从 Windows 调 Linux

wsl.exe 是 Windows 侧入口:

1
2
3
wsl --distribution Ubuntu --user root
wsl ls -la /proc/cpuinfo
wsl ls -la "/mnt/c/Program Files"

不指定命令时启动默认 shell;指定命令时由选定发行版执行 Linux binary。

5.2 从 Linux 调 Windows

在 WSL shell 中可以直接调用 Windows executable:

1
2
3
notepad.exe .bashrc
ipconfig.exe
cmd.exe /c dir

.exe 后缀是 Windows executable 名的一部分。在 PowerShell/CMD 中输入 wsl 通常可以解析到 wsl.exe;在 Linux shell 中调用 Windows binary 时,保留 .exe 最清楚。

5.3 管道由外层 shell 先解析

以下命令在 PowerShell 中执行时:

1
wsl cat a.txt | Select-String keyword

| 由 PowerShell 解析:左侧是 WSL process,右侧是 PowerShell command。

1
wsl cat a.txt | wsl grep keyword

管道仍由 PowerShell 创建,但两侧 process 都通过 WSL 执行 Linux command。

要让整个 pipeline、redirect、glob 和 quoting 都由 Bash 解释,应显式进入 Linux shell:

1
wsl bash -lc 'cat a.txt | grep keyword'

判断一个符号在哪边生效,先看是谁启动并解析整行命令,而不是看管道左侧程序属于哪个 OS。

6. WSL 网络:只承诺公开行为,不猜内部流表

6.1 NAT 是默认模型

WSL 2 默认使用 NAT-based networking。Windows Host 与 Linux VM 有不同网络边界,外部访问、Host/Guest 地址和防火墙行为不能简单按同一协议栈理解。

WSL 会提供 localhost forwarding 等集成,让 Windows 访问 WSL 服务时不必总是手工查询 Guest IP。但产品便利入口不表示 Windows 与 Linux 共享同一个 kernel TCP/IP stack。

6.2 Mirrored mode 是更深的 Host 集成

当前 Microsoft 文档推荐在支持的平台上使用 mirrored networking mode,以改善:

  • IPv6;
  • VPN compatibility;
  • Windows 与 WSL 之间的 localhost 访问;
  • 从局域网直接连接 WSL;
  • multicast 等网络行为。

配置属于 Windows 用户目录下的 .wslconfig

1
2
[wsl2]
networkingMode=mirrored

mirrored mode 仍然是 Windows 与 Linux 两套协议栈的集成,不应写成“两边共享同一个 socket table”。公开行为也不足以证明 Linux listen() 一定通过 hv_netvsc 上报、Windows 维护某种固定“虚拟端口表”,或由名为 Anubis 的组件分流。这些具体断言缺少一手设计或源码依据。

6.3 DNS、proxy 与 firewall 是独立问题

WSL networking 还涉及 DNS tunneling、auto proxy、Windows firewall/Hyper-V firewall 和企业 VPN。出现网络故障时分层检查:

1
2
3
4
5
6
Linux listen address
  → WSL network mode
  → localhost/LAN exposure
  → Windows/Hyper-V firewall
  → DNS/proxy/VPN
  → application policy

“能解析但连不上”和“IP 能通但域名不通”属于不同边界,不能统一归因于 NAT 或 mirrored mode。

7. 配置文件作用域

7.1 .wslconfig:全局 WSL 2 VM

位置:

1
%UserProfile%\.wslconfig

用于控制所有 WSL 2 distributions 共享的 VM 层配置,例如:

1
2
3
4
5
[wsl2]
memory=8GB
processors=4
swap=4GB
networkingMode=mirrored

修改后通常需要:

1
wsl --shutdown

让 WSL VM 完全停止后再重新启动。具体支持项随 WSL/Windows 版本变化,应以当前 wsl --version 和 Microsoft 文档为准。

7.2 /etc/wsl.conf:单个发行版

/etc/wsl.conf 位于某个 distribution 内,只影响该实例,例如:

  • automount;
  • network 配置生成;
  • interop;
  • boot/systemd;
  • default user。
1
2
3
4
5
[boot]
systemd=true

[user]
default=example

不要把 /etc/wsl.conf 当成给某个发行版分配独立 vCPU/内存的配置;这类 VM 资源属于 .wslconfig

8. 发行版生命周期与 wsl.exe

8.1 查看状态

1
2
3
wsl --list --verbose
wsl --status
wsl --version

--list --verbose 显示发行版名称、运行状态和 WSL version。星号表示默认 distribution,不代表 Docker Desktop 必须与它共用 daemon 或 userspace。

8.2 安装和选择版本

1
2
3
4
wsl --list --online
wsl --install --distribution Ubuntu-24.04
wsl --set-default-version 2
wsl --set-version Ubuntu-24.04 2

发行版名称、可用版本和命令参数会随当前 WSL 版本变化;执行前用 wsl --helpwsl --list --online 核对。

8.3 启停与默认发行版

1
2
3
4
wsl --distribution Ubuntu-24.04
wsl --terminate Ubuntu-24.04
wsl --shutdown
wsl --set-default Ubuntu-24.04
  • --terminate 停止一个 distribution;
  • --shutdown 停止整个 WSL 2 managed VM 和所有 distributions;
  • --set-default 只改变默认入口,不迁移数据。

8.4 导出、导入与改名

WSL distribution 的“改名”通常通过导出、导入新实例名完成:

1
2
wsl --export Ubuntu old.tar
wsl --import Ubuntu-Main D:\WSL\Ubuntu-Main old.tar --version 2

确认新实例的数据、用户和启动正常后,再考虑清理旧实例。导入实例的 default user 处理方式与 Store-installed distribution 可能不同,应以当前 WSL 命令帮助和 /etc/wsl.conf 为准。

8.5 --unregister 是破坏性操作

1
wsl --unregister Ubuntu

它会注销发行版并删除其数据。重装、改名或迁移前必须先成功导出,并实际确认备份文件可用;不能把 --unregister 当成普通 stop/remove shortcut。

9. Docker 与 WSL 的边界

Docker Desktop 的 WSL integration 与“在个人 Ubuntu distribution 中安装 Docker Engine”是两种模式:

  • Desktop integration:Windows 上的 Docker Desktop 管理 daemon/VM backend,并把 Docker CLI/socket 能力暴露给所选 WSL distributions;
  • native Engine:daemon、image、container 和配置由该 Linux distribution 自己维护。

它们可以提供相似的 docker CLI 体验,但 daemon 生命周期、storage、network、代理和升级责任不同。不要因为某个 distribution 能执行 docker ps,就推断 daemon 一定运行在该 distribution 中。

若选择 native Engine,需要自行处理 systemd/service 启动、权限、升级、代理和数据备份;若选择 Docker Desktop,应按 Desktop 的 WSL integration 边界排障。两套方案不要在同一 context 下混用而不确认 docker context 与 server 信息。

10. 开发环境的实际选择

对于 Java、Go、Node/React 等后端或全栈开发,WSL 2 通常更适合需要真实 Linux kernel 行为、container、systemd 和现代 tooling 的场景。

一个稳定工作方式是:

1
2
3
4
源码与 Linux build cache 放在 WSL filesystem
  → Git/compiler/package manager 在 WSL 中执行
  → Windows IDE 通过 WSL/remote integration 访问
  → 浏览器和桌面工具仍在 Windows

选择 WSL 1 的理由应是具体边界,例如项目必须主要存放在 Windows filesystem 且跨 OS 文件访问性能更重要,而不是笼统认为 WSL 1“更轻”。

11. 易混点

说法更准确的理解
WSL 就是在 Windows 上运行 Linux VM只适用于 WSL 2;WSL 1 是 system call translation
每个 WSL distribution 是一台完整 VMdistribution 主要是独立 userspace/rootfs,WSL 2 共享 managed VM/kernel 资源
WSL 2 不是传统 VM,所以不是全虚拟化它使用真实 Guest kernel 和硬件虚拟化,只是控制面被产品隐藏
看不到 VirtIO,所以不是虚拟机Hyper-V 使用自己的虚拟设备接口,VirtIO 不是唯一规范
wsl cat a | grep x 整条都在 Linux管道先由启动命令的外层 shell 解析
/mnt/c~/code 只是不同路径二者跨越不同 filesystem 与语义/性能边界
mirrored networking 合并了两个协议栈它增强两套协议栈的集成,不代表共享同一个 socket table
wsl --shutdown 只停默认发行版它停止整个 WSL 2 VM 与全部发行版
wsl --unregister 等于卸载入口它会删除发行版数据,必须先验证备份
能运行 Docker CLI 就说明 daemon 在当前 UbuntuCLI、socket 与 daemon 可以跨 distribution/VM 集成

12. 复习索引

  1. WSL 1 是 Linux system call translation;WSL 2 是真实 Linux kernel + managed utility VM;
  2. WSL 2 distributions 主要隔离 userspace/rootfs,并共享 WSL 管理的 kernel/VM 资源;
  3. Linux filesystem 与 /mnt/c 代表不同存储边界,项目位置应服从主要工具;
  4. Windows/Linux 命令可以互调,但 pipeline、redirect 和 quoting 由外层 shell 决定;
  5. NAT 是默认网络模型,mirrored mode 改善集成但不合并两套协议栈;
  6. .wslconfig 管全局 WSL 2 VM,/etc/wsl.conf 管单个 distribution;
  7. --terminate--shutdown--unregister 的作用域与破坏性不同;
  8. Docker Desktop integration 与 distribution 内 native Docker Engine 是两套生命周期。

13. 核验入口

本文由作者按照 CC BY 4.0 进行授权