WSL 不是一台普通虚拟机:理解它,才知道哪些事该放进去
原创 · 约 18 分钟阅读 · 阅读 --

WSL 不是一台普通虚拟机:理解它,才知道哪些事该放进去

作者: Alex Xiang


古董级程序员,大厂出来后一直在创业公司,现在仍活跃在一线做 AI 相关的开发。更完整的更新写在微信公众号「字与码」:工作经历、对新技术的想法,以及这些年走弯路的记录,会不定期发在那里。若觉得博客对你有用,欢迎顺手关注。

我见过不少团队把 WSL 用错,根源不是命令不会敲,而是对它的定位不清楚。

有人把它当成一个更快的 Git Bash。结果所有项目都放在 C:\Users,在 /mnt/c 下面跑 npm install,最后觉得 WSL 慢。

有人把它当成一台完整 Linux 服务器。结果在里面塞数据库、消息队列、监控、GPU 服务、后台任务,Windows 一重启,整个“服务器”都没了。

也有人把它当成虚拟机。结果到处找 NAT 网卡、快照、虚拟机控制台、桥接网络,越配越像运维事故。

WSL 最适合的身份其实更窄:它是一套贴着 Windows 桌面的 Linux 开发环境。

Windows、WSL 与远端环境的边界

这篇从一个很常见的团队场景讲起:公司里有几台 Windows 笔记本,要统一 Node、Python、Docker、数据库客户端、脚本工具链。我们到底应该把哪些东西放进 WSL,哪些留在 Windows,哪些根本不该依赖本地?

先把 WSL1 和 WSL2 的差别讲清楚

Microsoft 的官方说明里,WSL 是在 Windows 上运行 Linux 环境的方式,不需要传统虚拟机,也不需要双系统。这个描述容易让人误会,因为 WSL1 和 WSL2 的实现差别很大。

WSL1 更像系统调用翻译层。Linux 程序发出的很多系统调用,由 Windows 侧去兼容实现。它启动很快,Windows 文件系统访问也直接,但 Linux 内核兼容性有限。

WSL2 则使用真正的 Linux 内核,运行在轻量虚拟化环境里。它的 Linux 兼容性、容器支持、文件系统性能都更接近真实 Linux。Microsoft 文档也明确提到,WSL2 相比 WSL1 提升了文件系统性能,并提供完整系统调用兼容性。

今天讨论开发主力环境,默认说的是 WSL2。

确认版本:

wsl -l -v

输出类似:

  NAME      STATE           VERSION
* Ubuntu    Running         2

如果还是 WSL1:

wsl --set-version Ubuntu 2

这里的关键不是“2 比 1 新”。关键是你要知道自己在用哪一种边界。

WSL2 有 Linux 内核,有自己的 ext4 文件系统,有自己的发行版,有 systemd 支持,有 Docker 能力。它不是 Windows 上的一个 shell。

但它仍然不是一台你可以当生产服务器的独立机器。

发行版不是环境,环境要自己管理

团队里最常见的误会是:“大家都装 Ubuntu 了,所以环境一致。”

不是。

Ubuntu 只是发行版基线。真正影响结果的是:

  • Ubuntu 版本;
  • apt 源和包版本;
  • Python / Node / Go / Rust 版本;
  • 项目是否在 WSL 文件系统;
  • .wslconfig 是否限制了内存和 CPU;
  • Docker Desktop 是否启用 WSL integration;
  • 代理、DNS、证书是否一致;
  • shell profile 里有没有个人脚本。

我会把团队初始化写成一个可重复脚本,而不是在群里发几十条命令。

比如:

#!/usr/bin/env bash
set -euo pipefail

sudo apt update
sudo apt install -y \
  build-essential \
  curl \
  git \
  jq \
  unzip \
  ca-certificates \
  pkg-config

mkdir -p ~/work ~/bin

git config --global core.autocrlf input
git config --global init.defaultBranch main

然后再按项目拆:

~/work/company/bootstrap-node.sh
~/work/company/bootstrap-python.sh
~/work/company/bootstrap-docker.sh

这比“装好 WSL 就行”靠谱得多。

WSL 的文件系统边界决定大部分性能问题

WSL2 发行版的 Linux 文件系统通常在一个 VHDX 文件里。你在 WSL 里看到的 /home/alex/work/project,底层并不是 Windows 目录,而是 ext4 虚拟磁盘。

Windows 目录会挂到 /mnt/c/mnt/d 这类路径。

我的经验很简单:

项目源码、node_modules、venv、.git、编译产物 -> 放 WSL
下载文件、Office 文档、图片素材、归档包 -> 放 Windows

一个 Node 项目如果放在 /mnt/c/Users/alex/project,再在 WSL 里跑:

npm install
npm run dev

慢是正常的。node_modules.git 会制造大量小文件操作。跨 Windows/WSL 文件系统边界后,问题会被放大。

正确姿势:

mkdir -p ~/work
cd ~/work
git clone git@github.com:example/app.git
cd app
npm install
npm run dev

Windows 里用 VS Code 打开时,不要从资源管理器直接打开 Windows 路径,而是:

cd ~/work/app
code .

这样 VS Code 会通过 Remote WSL 进入 Linux 环境,终端、扩展、语言服务都跟着项目走。

它可以跑后台服务,但不要把它当服务器

现在 WSL 支持 systemd,很多服务可以像 Linux 里一样启动:

systemctl --user status
sudo systemctl status ssh

这很好用。比如开发时临时跑 PostgreSQL、Redis、MinIO、本地模型服务,都可以。

但我不建议把 WSL 当成团队共享服务,更不建议把关键任务放在里面长跑。

原因很现实:

  • Windows 更新或重启会影响 WSL;
  • 用户注销、睡眠、关机都会打断服务;
  • 网络地址可能随模式变化;
  • 资源限制来自本机;
  • 备份和监控通常没人认真做;
  • 线上问题无法用“我本机 WSL 是好的”解释。

如果某个服务已经被两个人以上依赖,最好放到开发服务器、测试环境或 Docker Compose 的明确配置里,而不是藏在某个人的 WSL。

WSL 适合的是“本机可复现”,不适合“本机即基础设施”。

.wslconfig 是全局旋钮,不是性能魔法

WSL2 的全局配置放在 Windows 用户目录下的 .wslconfig。Microsoft 文档提醒过,修改后需要 wsl --shutdown 再重启 WSL 才会生效。

一个常见配置:

[wsl2]
memory=16GB
processors=8
swap=8GB
localhostForwarding=true

如果你机器 32GB 内存,给 WSL 限 16GB 很合理。如果机器只有 16GB,还给 WSL 12GB,再开浏览器、IDE、微信、会议软件,Windows 侧就会难受。

我不会把 .wslconfig 当成项目配置提交。它是个人机器配置。团队文档里最多给建议区间:

16GB 机器:memory=8GB,processors=4
32GB 机器:memory=16GB,processors=8
64GB 机器:memory=32GB,processors=12

真正影响项目可复现的东西,应该放在项目里:Dockerfile、devcontainer、Makefile、脚本、.env.example

Windows 和 Linux 可以互相调用,但别滥用

WSL 一个很爽的地方,是 Linux 可以启动 Windows 程序:

explorer.exe .
notepad.exe README.md

Windows 也可以访问 Linux 文件:

\\wsl.localhost\Ubuntu\home\alex\work

这在日常很方便。比如生成一个报告,直接:

explorer.exe dist

或者复制路径给同事。

但我不建议把自动化流程建立在大量 Windows/Linux 互相调用上。脚本里到处 powershell.execmd.exewsl.exe,很快会变成只有你机器能跑的东西。

我的规则是:

  • 临时查看、打开文件、调试,可以跨边界;
  • 构建、测试、部署脚本,尽量留在同一个边界;
  • 团队脚本优先假设自己运行在 Linux;
  • Windows 专用逻辑单独封装,不要散落。

一套团队 WSL 开发环境应该长什么样

如果让我给团队定一个最小方案,我会这样写:

Windows:
  - Windows Terminal
  - VS Code
  - 浏览器、沟通工具
  - Docker Desktop

WSL Ubuntu:
  - 项目源码:~/work
  - Git、编译工具、语言运行时
  - 项目脚本和测试
  - 本地缓存和临时数据

远端环境:
  - 共享数据库
  - 测试服务
  - CI/CD
  - 长期运行任务

项目 README 里放:

git clone ...
cd ...
./scripts/bootstrap-dev.sh
./scripts/test.sh
./scripts/run-local.sh

新人入职时,目标不是“把 WSL 装好”,而是半小时内跑通项目测试。

什么时候不该用 WSL

WSL 很好,但不是所有场景都该塞进去。

我会避开这些场景:

  • 需要长期稳定运行的生产服务;
  • 强依赖 Linux 内核模块或特殊硬件直通的服务;
  • 对网络拓扑有严格要求的测试;
  • 团队成员主要是非技术用户;
  • 项目已经有成熟的远程开发容器或云开发环境;
  • 最终交付物是 Windows 原生 GUI,且需要大量平台相关测试。

反过来,这些场景很适合:

  • Web 后端开发;
  • Node/Python/Go/Rust 工具链;
  • Docker Compose 本地环境;
  • 数据处理和脚本;
  • AI/机器学习开发;
  • Linux CLI 工具链;
  • 需要和 Windows 桌面应用并行工作的开发。

小结

WSL 不是普通虚拟机,也不是增强版命令行。

它最有价值的地方,是把 Linux 开发环境贴到 Windows 工作台旁边:代码、依赖、脚本、容器在 Linux;浏览器、编辑器、沟通、桌面软件在 Windows。

理解这个定位,很多选择就清楚了。

项目放 WSL 文件系统。
长期服务放远端。
Windows 负责桌面。
Linux 负责开发。
跨边界可以,但别把边界当透明。

参考资料: