Windows 10: 将 WSL Linux 实例安装到 D 盘

  |   0 评论   |   0 浏览

前言

WSL, 即 Windows Subsystem for Linux,它是 Win10.1709 起提供的新功能,能够让我们在 Windows 10 上获得一个真实的 Linux 应用层运行环境。Linux 真机上的 64-bit ELF 可执行文件能够在 WSL 环境中直接运行,这比 cygwin 那种 Unix C API 层面的模拟大大前进了一步。

安装 WSL 实例(具体的一个 Linux 发行版)的常规方法是,从 Microsoft Store 在线下载。但 Windows 老是把 WSL 实例安装到 C 盘,这让我十分恼火。

以 Win10.21H2 上通常方法安装 WSL Ubuntu 22.04 为例,

  • 第一块, 初始安装包总是被存一份在 C:\Program Files\WindowsApps\CanonicalGroupLimited.Ubuntu22.04LTS_2204.0.9.0_x64__79rhkp1fndgsc .
  • 第二块, Linux 的文件系统内容存在 %LocalAppData%\Packages\CanonicalGroupLimited.Ubuntu22.04LTS_79rhkp1fndgsc\LocalState .

第一块内容,相当于是 WSL Ubuntu 20.04 的安装包, 恒定为 650MB。

这第二块内容,可是会随着往 Linux 里头添加软件包而无限制地膨胀。这些跟“Windows 系统”无关的数据占用着大量系统盘空间,十分憋屈。

经过一些网络搜索和自己的探索,将 WSL 实例安放到任意指定目录的方法总算被我找到了。上头两块内容都可以自定义目录存放。

安装到 D 盘的方法

【STEP 1】 用常规方法到 Microsoft Store 获取 WSL Linux 安装包。

点击蓝色 [Get] ,等待下载完成、蓝色按钮变为 [Launch]。

【STEP 2】 提取已下载到本地的安装包。

出现 [Launch] 按钮后,先不要 Launch,而是转到 C:\Program Files\WindowsApps , 敲 dir /od 查看多出了哪些子目录。

发现多出了三个,目录名里头带有 Ubuntu22.04 字样。用 Explorer 检查一下它们各自的内容,名字里有 neutral 字样的那两个文件夹,内容就几百 KB, 估计是无关紧要的东西,先不理会它们。

剩下的那个,尺寸有 650MB,这就是我们需要的离线安装包了。

现在将此中内容全部选中,拷贝到 D:\WSL-Ubunut-22.04 中,该目录将成为此 WSL 实例的永久栖息地。

拷贝后不妨将该目录整个 zip 起来,以便日后在其他机器上安装时重复使用。

【STEP 3】 执行 WSL 实例安装程序。

继续之前,不妨决定一下,我们是希望以 WSL1 模式还是 WSL2 模式来使用这份 Ubuntu 。

  • 选择 WSL1 (需要 Win10.1709),Linux 的文件系统将出现于宿主机的 D:\WSL-Ubunut-22.04\rootfs 文件夹中,Linux 的文件将直接呈现在 NTFS 文件系统中,一份典型的 Linux 基础安装,文件数能达到 30000+ 。
  • 选择 WSL2 (需要 Win10.2004),其本质是让 Linux 运行在一个虚拟机中,虚拟机中运行着真正的 Linux 内核,Windows 将创建 D:\WSL-Ubunut-22.04\ext4.vhdx 虚拟磁盘文件来存放 Linux 的文件系统。这种模式更接近真实的 Linux 行为,与 Windows 宿主机的隔离也更彻底。

两种模式各有优劣。我更喜欢 WSL1,因为它真是个创新;用 WSL2 的话,不如 VMware Workstation 里头安装 Linux VM 那般明明白白 ,比如随意做快照之类。

以下两个命令可以选择“新建 WSL 实例时所采用的 WSL 模式”:

wsl --set-default-version 1

wsl --set-default-version 2

已经创建出来的 WSL 实例,不受 --set-default-version 的影响。 已经创建出的 WSL 实例,得用 --set-version 才能切换(非常费时,因为要将 Linux 的大量细碎文件拷入或拷出 vhdx)。

现在双击 "D:\WSL-Ubuntu-22.04\ubuntu2204.exe" ,开始安装这份实例。

下头就按安装程序的 UI 来操作即可,没太多可说的。

今后,每次要运行此份 WSL 实例,依然是执行 "D:\WSL-Ubuntu-22.04\ubuntu2204.exe" ,很方便。

下头分别用 WSL1 和 WSL2 模式安装完成的样子,中途的 UI 有些差别。

【清理】

第一处,刚才蓝色 [Launch] 按钮出现的时候,从 Microsoft Store 的角度看,Ubuntu 22.04 已经是“安装在我们的电脑上了”,因此,开始菜单中能够看到 Ubuntu 22.04 快捷方式。但这东西对我们已经没用了,可以 Uninstall 掉。

此处 Uninstall 的作用,主要是将 C:\Program Files\WindowsApps\CanonicalGroupLimited.Ubuntu22.04LTS_2204.0.9.0_x64__79rhkp1fndgsc 整个目录清除,为我们自己抢回 650MB C 盘空间。

第二处, D:\WSL-Ubuntu-22.04 中的 install.tar.gz 可以删除,因为它的内容已经解压到 rootfs 或是 ext4.vhd 中了。

如果你愿意用 wsl -d 来启动这份 WSL 实例(最后一节谈及),那么 ubuntu2204.exe 跟它旁边的一干原始安装包文件也可以删除。

前进一步,安装到移动硬盘

这是为了让我们的 WSL 实例变成可移动的绿色版,想插到哪台机器上用就插到哪台机器上用。

需要一些铺垫知识,让我们看看,刚才安装到 D 盘的动作,在系统中留下来哪些印迹。一个 Windows 软件,能在系统中留下的印迹,无非是两大类,一是创建/修改了哪些文件,二是创建/修改了哪些注册表项。

WSL Ubuntu 创建的文件刚才已经展示过,主要是 D:\WSL-Ubuntu-22.04\rootfs 或 D:\WSL-Ubuntu-22.04\ext4.vhdx 。

注册表方面,确实也留了一份印迹。在注册表节点 [HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss] 中,我们发现多出来一个 GUID subkey,以我的实验机为例,GUID 值是 {3d4e7ad0-63ee-40c8-9fad-a7c7e0260039} ,在你的机器上肯定不同,因为此处 GUID 值是随机生成的。今后多安装一份 WSL 实例,就会多出一个 GUID subkey,只要两个 GUID 值不同,在 WSL 引擎的眼中,就是两份不同的 WSL 实例。

在一份 WSL GUID subkey 中,最重要的注册表条目有两个:

  • BasePath,告知此份 WSL 实例的实体文件在哪个目录中。WSL 会去此目录中寻找 rootfs 子目录和 ext4.vhdx 。
  • DistributionName,告知这份 WSL 实例在 Win10 中登记的名字。 wsl --list 列出的名字就是来自该条目。

另外:

  • DefaultUid,指出此份 WSL 启动时,自动让这个用户处于登录状态。此处用 UID 来标识一个用户,Linux 上的第一个用户的 UID 总是 1000,UID 和用户名的映射关系体现在 /etc/passwd 文件中。
  • Flags ,可能是告知了此份 WSL 的模式,0x7 表示WSL1,0x0F 表示 WSL2 .

有了这个信息,我们不借助 ubuntu2204.exe 也能启动这份 WSL, 用命令:

wsl -d Ubuntu-22.04

-d 后头那个字符串,就是 GUID subkey 中 DistributionName 的值。

事实上,你可以任意修改 DistributionName 的值,然后 wsl -d 时告知正确的新值即可。不过呢,DistributionName 改名后,D:\WSL-Ubuntu-22.04\ubuntu2204.exe 就没法启动 WSL 实例了,因为 ubuntu2204.exe 会死认 "Ubuntu-22.04" 这个 DistributionName,没这个名字它就罢工。当然,由于这份 WSL 我们已经安装好,用 wsl -d <dist-name> 即可启动之,把 ubuntu2204.exe 删掉也无妨,如果你想改名就大胆改吧。

小结一下,所谓“安装一份 WSL”实例,本质上就是在 Lxss 下方创建一个 GUID 子节点,在子节点中记录其 DistributionName、以及此份 Linux 的“根文件系统”存放在宿主机的何处。有几个途径可以创建出这个 GUID 子节点:

  • 前头执行 ubuntu2204.exe 来安装一份 WSL。
  • 自己执行 wsl --import 来生成一份根文件系统,根文件系统的内容来自指定的 tar 文件。
  • 自己直接创建 GUID 子节点,以及注册表项 DistributionName 和 BasePath 等等。稍后我们手工导入 WSL-green.reg 的实验可证明这点。

现在追问一个问题:这么看来,一份 WSL 实例本身就是绿色版的嘛。微软完全可以把 GUID subkey 里头的各个配置项写成配置文件,放在所谓的 BasePath 里头,这样的话,一个 D:\WSL-Ubuntu-22.04 文件夹就包含了一份 WSL 的所有信息,这么设计不好吗?

没错,这么想是完全合理的。但微软跟一些软件大厂常常就是作(zuō),非要在小白用户面前营造神秘感,在注册表里这里塞点那里塞点给用户制造认知门槛。

既然已经知道了这里面的门道,就没有什么能拦着我们把 WSL 实例变成绿色版的了。现在把已有的那个 GUID subkey 注册表节点导出,保存到 D:\WSL-Ubuntu-22.04\WSL-green.reg 文件,内容如下:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss\{3d4e7ad0-63ee-40c8-9fad-a7c7e0260039}]
"State"=dword:00000001
"DistributionName"="Ubuntu-22.04"
"Version"=dword:00000002
"BasePath"="D:\\WSL-Ubuntu-22.04"
"Flags"=dword:00000007
"DefaultUid"=dword:000003e8
"KernelCommandLine"="BOOT_IMAGE=/kernel init=/init"
"DefaultEnvironment"=hex(7):48,00,4f,00,53,00,54,00,54,00,59,00,50,00,45,00,3d,\
  00,78,00,38,00,36,00,5f,00,36,00,34,00,00,00,4c,00,41,00,4e,00,47,00,3d,00,\
  65,00,6e,00,5f,00,55,00,53,00,2e,00,55,00,54,00,46,00,2d,00,38,00,00,00,50,\
  00,41,00,54,00,48,00,3d,00,2f,00,75,00,73,00,72,00,2f,00,6c,00,6f,00,63,00,\
  61,00,6c,00,2f,00,73,00,62,00,69,00,6e,00,3a,00,2f,00,75,00,73,00,72,00,2f,\
  00,6c,00,6f,00,63,00,61,00,6c,00,2f,00,62,00,69,00,6e,00,3a,00,2f,00,75,00,\
  73,00,72,00,2f,00,73,00,62,00,69,00,6e,00,3a,00,2f,00,75,00,73,00,72,00,2f,\
  00,62,00,69,00,6e,00,3a,00,2f,00,73,00,62,00,69,00,6e,00,3a,00,2f,00,62,00,\
  69,00,6e,00,3a,00,2f,00,75,00,73,00,72,00,2f,00,67,00,61,00,6d,00,65,00,73,\
  00,3a,00,2f,00,75,00,73,00,72,00,2f,00,6c,00,6f,00,63,00,61,00,6c,00,2f,00,\
  67,00,61,00,6d,00,65,00,73,00,00,00,54,00,45,00,52,00,4d,00,3d,00,78,00,74,\
  00,65,00,72,00,6d,00,2d,00,32,00,35,00,36,00,63,00,6f,00,6c,00,6f,00,72,00,\
  00,00,00,00

不妨假设 D: 是你实验机 A 的移动硬盘盘符,再假设当你将移动硬盘插到实验机 B 上,移动硬盘盘符变成 E: ,那么,为了在实验机 B 上使用这份 WSL,你要做的事也很简单,将 WSL-green.reg 的 BasePath 值当场修改,变成:

"BasePath"="E:\\WSL-Ubuntu-22.04"

双击 WSL-Ubuntu.reg 导入实验机 B 。然后 wsl -d Ubuntu-22.04 即可启动 WSL 。

一个小提示:为了防止跟实验机 B 上其他 WSL 实例重名,我建议将移动硬盘上 WSL-Ubuntu.reg 的 DistributionName 改得独特一些,比如叫 Ubuntu-22.04-on-my-Yellow-SSD 。

附带一个提示:DistributionName 字串中请不要加空格,因为 wsl.exe 的参数拆解行为变态了、没按常理出牌, wsl -d "some distri name" 总是会失败。

最后,我给自己准备了这样一个批处理,WSL-start.bat,内容如下:

@echo off
setlocal EnableDelayedExpansion

set batdir=%~dp0
set batdir=%batdir:~0,-1%
set batdir2=%batdir:\=\\%

set regfile=%batdir%\WSL-green.reg

echo "BasePath"="%batdir2%" >> "%regfile%"

reg import "%regfile%"
if not %ERRORLEVEL%==0 (
    echo.
    echo Import registry file fail: %regfile%
    echo.
    pause
    exit /b 4
)

wsl -d Ubuntu-22.04-on-my-Yellow-SSD
if not %ERRORLEVEL%==0 (
    echo.
    echo "wsl -d" execution fail. Please check your bat file or Windows environment.
    echo.
    pause
    exit /b 4
)

exit /b 0

该批处理干的事很简单:

  1. 把自己的当前目录作为 BasePath 值写入 WSL-green.reg 。为方便起见,只是追加到 .reg 文件末尾,反正后出现的值会覆盖先出现的。每年手工清理一次就好。
  2. 将 WSL-green.reg 导入注册表,为的是向 WSL 引擎注册这份新来的 DistributionName。
  3. 调用 wsl -d 来启动特定名称的 WSL 实例,这个名称,必须事先手工保证跟 WSL-green.reg 里头的匹配。

最后呢,我移动硬盘上的 WSL1 实例文件夹是这样的,ubuntu2004.exe 等安装包文件已被我删除, [temp] 和 fsserver 那两个东东是 WSL 每次运行都会自动生成的,不用理会它们。

今后,不管插到哪台 Win10 上,双击 WSL-start.bat 即可启动当前目录中的 WSL 实例,丝般顺滑。

最后还是要提示一句: 如果你在移动硬盘上准备两份 WSL 实例,并且希望它们能同时运行,那么,请确保两个目录中的 WSL-green.reg 里头的 GUID 值不重复、DistributionName 也不重复。

END (初稿:2022.06.11)

[2023-01-09] 新的批处理,免维护

将正文末尾提到的批处理改进了一下,做到每份 WSL 实例部署一次,部署后永久免维护(不论 WSL 文件夹移动还是换机器运行),非常方便了。

使用方法见 https://gitee.com/chjfth/dailytools/tree/master/cmd-batch/WSL-green

具体改进:

  • 同时使用两个 WSL 实例,用户无需手工编辑 GUID,批处理根据用户指定的 DistributionName 来自动生成 GUID,说白了就是拿 DistributionName 算 MD5,将 MD5 值当作 GUID。
  • 用户无需定期清理 WSL-green.reg 末尾不断增多的注册表条目,因为现在 WSL-green.reg 是从一个静态模板文件 WSL-green.reg.0 生成的,每次执行 WSL-green.bat 都将重新生成 WSL-green.reg ,因此不会出现老旧内容持续累积。

原文链接https://zhuanlan.zhihu.com/p/525955480


标题:Windows 10: 将 WSL Linux 实例安装到 D 盘
作者:michael
地址:https://blog.junxworks.cn/articles/2024/03/18/1710763375030.html