双系统的终极方案 - WSL2
+++ title = ’ 双系统的终极方案 - WSL2' date = ‘2024-02-20T21:32:18+08:00’ +++
双系统的终极方案 - WSL2
作为一个开发者主力系统使用 Linux 系统的好处是显而易见的,大部分的技术的安装、演示,都是以 Linux 系统为基础的,而且很多技术或者工具压根儿就不兼容 Windows 系统,比如 Docker。主力系统使用 Linux,开发体验将有很大提升。
主要是我这段时间主要从事运维相关的工作,对 Linux 的使用也很有心得,我感觉有这个能力了可以用好 Linux
其实从很早的时候想将主力操作系统切换为 Linux,希望能在一个跟服务器环境相同的环境中开发,这样的话,我们就可以使用 Nginx、Docker 这种非常方便的工具了,对我们的开发和日常工作都将带来极大的便利,但是经过一定的调研之后(主要调研 Ubuntu+GNOME),发现 Ubuntu 到目前为止依然有一些无法解决的问题,有这些问题的存在,让我认为现在将主力操作系统切换到 Linux 并不明智:
-
GNOME 桌面存在不稳定的问题,插件装多了之后可能会崩溃
-
GNOME 桌面的额头叠加问题很难适配解决,IDEA 等开发工具在 GNOME 桌面下的额头问题很严重,而此类问题在 Windows 下已经成功优化了
-
微信和企业微信不支持 Linux,在可见的未来也不会支持,此外,其他的常用办公软件都不是很重视 Linux 的适配
诸如此类的原因让我觉得完全放弃 Windows,转向 Linxu 并不明智,这个时候我想到了,作为一个成年人,我的想法应该是我全都要。
于是我想到了双系统方案、Linux 虚拟机、还有 WSL。这三种方式我基本上都尝试过,然后我了解到 WSL2 经过一段时间的优化已经足够好用,简单体验之后,发现使用起来确实非常丝滑,非常方便,最终决定采用 WSL2 来实现双系统,我相信这也是目前为止(2024 年 2 月 28 日)双系统的终极方案。
先说结论:
WSL2 的文件系统跟 Windows 是互通的,而且通过配置可以让 WSL2 中的 Linux 发行版跟 Windows 共用网卡端口,给人的感觉就是像是一个电脑里真的安装了两个独立又互通的操作系统,这两个操作系统同时共享电脑的磁盘、网卡等硬件。WSL2 可以浏览 Windows 的文件,Windows 也可以浏览 WSL2 的文件,在 WSL2 中启动一个服务占用了 8080 端口,在另一台电脑访问 当前电脑的ip:8080
,可以正常访问 WSL2 中的服务,非常惊艳。
安装
在线安装
官方文档:安装 WSL | Microsoft Learn。官方文档写的很好,没有必要看别人的博客
首先打开 powersehll,运行以下命令行查看当前支持哪些 Linux 发行版
|
|
然后选择一个版本进行安装
|
|
比如当前(2024 年 2 月 28 日)支持 Ubuntu-22.04
|
|
我们可以直接通过以下命令安装,注意,Windows11 中默认使用的是 WSL2,而不是 WSL1。
|
|
实际上,Ubuntu-22.04
是通过微软的应用商店下载的
安装完成之后提示重启操作系统,重启之后会自动打开 PowerShell,并让用户设置 Ubuntu-22.04
系统的用户名密码即可登录 Ubuntu-22.04
。
后续,如果我们想进入 Ubuntu-22.04
,可以在 Windows Terminal 中进入,安装 Ubuntu-22.04
的时候,已经自动在 Windows Terminal 中添加了相关链接。选择 Ubuntu 22.04.03 LTS
登录我们刚刚安装的 Ubuntu-22.04
然后,我们可以通过以下命令,查看所有安装的发行版,
|
|
简化版为
wsl -l -v
在结果中,可以看到 WSL 安装的所有的发行版的版本,其中 VERSION 列表示的是 WSL 当前的版本,Windows11 中默认使用的是 WSL2。
|
|
自己准备发行版 ISO 安装
过程很简单,到 Docker Hub 上下载 CentOS 的镜像,打成 tar 包,然后导入到 WSL 中即可。以后有时间再弄吧,TODO
日常使用
命令
WSL 管理 Linux 发行版(Distro)/ 子系统 的方式,有点类似 Docker 管理镜像的方式:WSL 就是一个类似于 docker 的管理程序,wsl 可以安装多个发行版,然后可以单独控制每一个发行版的启动和关闭。
wsl
命令的格式如下
|
|
其中我们一般省略 .exe
直接执行 wsl
,会进入默认的子系统,如果当前没有子系统启动,则会先启动默认的子系统,然后进入默认的子系统。
后面我们会学习到
wsl --set-default <Distro>
用于设置默认的子系统,其中--set-default
可简写为-s
。
参数:运行 Linux 二进制文件(一般我们称之为命令 command)的参数,如果未指定 shell(例如 /bin/bash
),wsl.exe 将启动默认的 shell。
每一个命令都有其对应的二进制文件,比如
cp
、mv
这类的,在/bin
都有其对应的文件。
-
--exec <CommandLine>
,-e <CommandLine>
:在不使用默认 Linux shell 的情况下执行指定的命令。1 2
wsl -e pwd /mnt/c/Users/wwwli
-
--shell-type <standard|login|none>
:使用指定的 shell 类型执行指定的命令。 -
--
:按原样传递剩余的命令行。1 2
wsl pwd /mnt/c/Users/wwwli
选项:
-
--cd <Directory>
:将指定目录设置为当前工作目录。即登录发行版,并切换到指定目录。如果使用~
,则将使用 Linux 用户的主路径。如果路径以/
字符开始,它将解释为绝对 Linux 路径。否则,该值必须是绝对 Windows 路径。 -
--distribution <Distro>
,-d <Distro>
:运行指定的分发版。常用 -
--user <UserName>
,-u <UserName>
:以指定用户身份运行。 -
--system
:为系统分发版启动 shell。不知道啥意思
用于管理子系统的参数
-
--help
:显示帮助文档。 -
-debug-shell
:出于诊断目的打开 WSL2 调试 shell。 -
--install [发行版] [选项...]
:安装适用于 Linux 的 Windows 子系统分发版。其中,发行版参数可以通过wsl.exe --list --online
查看当前可用的发行版的列表,选项部分解释如下:-
--no-launch
,-n
:安装后不要启动分发版。 -
--web-download
:从 Internet 而不是 Microsoft Store 下载分发版。 -
--no-distribution
:仅安装所需的可选组件,不安装分发版。 -
--enable-wsl1
:启用 WSL1 支持。
-
-
--manage <Distro> <Options...>
:更改发行版特定选项。支持的选项如下:--set-sparse <true|false>
,-s <true|false>
:将发行版的 vhdx 设置为稀疏,从而允许自动回收磁盘空间。
-
--mount <Disk>
:在所有 WSL 2 分发版中附加和装载物理磁盘或虚拟磁盘。选项:-
--vhd
:指定<Disk>
引用虚拟硬盘。 -
--bare
:将磁盘附加到 WSL2,但不要装载它。 -
--name <Name>
:使用装入点的自定义名称装载磁盘。 -
--type <Type>
:装载磁盘时要使用的文件系统 (如果未指定) 默认为 ext4。 -
--options <Options>
:其他装载选项。 -
--partition <Index>
:要装载的分区的索引 (如果未指定) 默认为整个磁盘。
-
-
--unmount [磁盘]
:从所有 WSL2 分发版中卸载和分离磁盘。如果在没有参数的情况下调用,则卸载和分离所有磁盘。 -
--set-default-version <Version>
:更改新分发版的默认安装版本。若要设置 WSL 1 或 WSL 2 为默认使用的版本,请将<Version>
替换为数字 1 或 2。例如wsl --set-default-version 2
。该数字表示新 Linux 发行版安装默认使用的 WSL 版本。 -
--shutdown
:立即终止所有正在运行的分发版和 WSL 2, 常用 -
--status
:显示所有子系统状态。 -
--update
:更新适用于 Linux 的 Windows 子系统包。--pre-release
:下载预发行版本 (如果可用)。
-
--version
,-v
:显示版本信息。
用于在子系统中管理分发版的参数:
-
--export <Distro> <FileName> [选项]
:将分发版导出到 tar 文件。--vhd
:指定应将分发版导出为 .vhdx 文件。
-
--import <Distro> <InstallLocation> <FileName> [选项]
:将指定的 tar 文件作为新分发版导入。-
--version <Version>
:指定要用于新分发的版本。 -
--vhd
:指定所提供的文件是.vhdx
文件,而不是 tar 文件。此操作在指定的安装位置创建.vhdx
文件的副本。
-
-
--import-in-place <Distro> <FileName>
:将指定的.vhdx
文件作为新分发版导入。必须使用 ext4 文件系统类型设置此虚拟硬盘的格式。 -
--list [选项]
,-l [选项]
:列出分发版。选项:-
--all
:列出所有分发版,包括当前正在安装或卸载的分发版。 -
--running
:仅列出当前正在运行的分发版。 -
--quiet
,-q
:仅显示分发版名称。 -
--verbose
,-v
:显示有关所有分发版的详细信息。 -
--online
,-o
:显示适合通过wsl.exe --install
安装的可用分发版列表。
-
-
--set-default <Distro>
,-s <Distro>
:将分布版设置为默认值。 -
--set-version <Distro> <Version>
:更改指定分发版的版本。 -
--terminate <Distro>
,-t <Distro>
:终止指定的分发版。 -
--unregister <Distro>
:取消注册分发版并删除根文件系统。
其实常用的也就是:
-
启动并进入默认子系统
wsl
,启动指定的子系统wsl -d <Distro>
: -
关闭子系统和 WSL:
wsl --shutdown
,wsl -t <Distro>
关闭指定的子系统。
注意,关闭 Terminal 是不会关闭 Linux 系统的。需要通过 wsl --shutdown
关闭子系统和 WSL2 或者通过 wsl --terminate <Distro>
或者 wsl -t <Distro>
关闭指定的子系统。
隐藏桌面图标
参考博客:Reddit - Dive into anything、BrainByteZ » [Windows 11] Hide/Remove WSL Linux icon from Desktop
具体的原理是:Registry Tweak - Add or Remove System Icons from the Desktop
安装完 Ubuntu 22.04
之后,桌面出现了图标:
这个图标无法删除,想要隐藏的话,没有找到官方提供的方法,只找到一个国外大神想到的办法。
具体做法是,到 [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel]
这个目录下,创建一个名称为 {B2B4A4D1-2754-4140-A2EB-9A76D9D7CDC6}
类型为 DWORD (32-Bit)
的十进制的值,值为 1,然后重启,即可隐藏图标
配置用户
首先在 Linux 子系统中设置 root 用户密码,我这里设置的是 root/root
|
|
然后配置以后都用 root 用户登录,修改 Linux 子系统的默认登录用户,命令为:
|
|
当前安装的发行版是 Ubuntu-22.04
,其在微软应用商店下下载,下载的软件执行器的名字为 ubuntu2204.exe
,因此当前执行的就是
|
|
再次启动 wsl
,默认登录的就是 root 用户了。
手动的安装发行版不能这样设置,因为这些发行版没有可执行启动器。 可以改为使用 /etc/wsl.conf
文件来更改导入的发行版的默认用户。请参阅 高级设置配置 文档中的“自动装载”选项。
但是现在都
.wslconfig
了啊,不用wsl.conf
了啊
可以用 wsl --user <Username>
或者 wsl --distribution <Distribution Name> --user <User Name>
来启动。
配置子系统
我们在 VMware 虚拟机中创建虚拟机的时候,可以配置虚拟机使用的 CPU 核心数,占用的内存,WSL 中也可以配置这些信息。
- .wslconfig 用于在 WSL 2 上运行的所有已安装发行版中配置全局设置。
- wsl.conf 用于为在 WSL 1 或 WSL 2 上运行的每个 Linux 发行版按各个发行版配置本地设置。
我们当前使用的是 WSL2,因此只需要关注 .wslconfig
。
使用 .wslconfig
为 WSL 上运行的所有已安装的发行版配置全局设置。
-
默认情况下,
.wslconfig
文件不存在。它必须创建并存储在%UserProfile%
目录中才能应用这些配置设置。%UserProfile%
路径一般为C:\Users\<UserName>
-
用于在作为 WSL 2 版本运行的所有已安装的 Linux 发行版中全局配置设置。
-
只能用于 WSL 2 运行的发行版。作为 WSL 1 运行的发行版不受此配置的影响,因为它们不作为虚拟机运行。
-
要访问
%UserProfile%
目录,请在 PowerShell 中使用cd ~
访问主目录(通常是用户配置文件C:\Users\<UserName>
),或者可以打开 Windows 文件资源管理器并在地址栏中输入%UserProfile%
。该目录路径应类似于:C:\Users\<UserName>\.wslconfig
。
配置项:
key | value | default | 说明 |
---|---|---|---|
内核 (kernel) | path | Microsoft 内置内核提供的收件箱 | 自定义 Linux 内核的绝对 Windows 路径。 |
内存 | 大小 | Windows 上总内存的 50% 或 8GB,以较小者为准;在 20175 之前的版本上:Windows 上总内存的 80% | 要分配给 WSL 2 VM 的内存量。 |
处理器 | number | Windows 上相同数量的逻辑处理器 | 要分配给 WSL 2 VM 的逻辑处理器数量。 |
localhostForwarding | boolean | true |
一个布尔值,用于指定绑定到 WSL 2 VM 中的通配符或 localhost 的端口是否应可通过 localhost:port 从主机连接。 |
kernelCommandLine | string | 空白 | 其他内核命令行参数。 |
safeMode | boolean | false |
在“安全模式”中运行 WSL,这会禁用许多功能,应用于恢复处于错误状态的发行版。仅适用于 Windows 11 和 WSL 版本 0.66.2+。 |
swap | 大小 | Windows 上 25% 的内存大小四舍五入到最接近的 GB | 要向 WSL 2 VM 添加的交换空间量,0 表示无交换文件。交换存储是当内存需求超过硬件设备上的限制时使用的基于磁盘的 RAM。 |
swapFile | path | %USERPROFILE%\AppData\Local\Temp\swap.vhdx |
交换虚拟硬盘的绝对 Windows 路径。 |
pageReporting | boolean | true |
默认的 true 设置使 Windows 能够回收分配给 WSL 2 虚拟机的未使用内存。 |
guiApplications | 布尔 * | true |
一个布尔值,用于在 WSL 中打开或关闭对 GUI 应用程序 (WSLg) 的支持。仅适用于 Windows 11。 |
debugConsole | 布尔 * | false |
一个布尔值,用于在 WSL 2 发行版实例启动时打开显示 dmesg 内容的输出控制台窗口。仅适用于 Windows 11。 |
nestedVirtualization | 布尔 * | true |
用于打开或关闭嵌套虚拟化的布尔值,使其他嵌套 VM 能够在 WSL 2 中运行。仅适用于 Windows 11。 |
vmIdleTimeout | 数量 * | 60000 |
VM 在关闭之前处于空闲状态的毫秒数。仅适用于 Windows 11。 |
dnsProxy | bool | true | 仅适用于 networkingMode = NAT。布尔值,通知 WSL 将 Linux 中的 DNS 服务器配置为主机上的 NAT。设置为 false 会将 DNS 服务器从 Windows 镜像到 Linux。 |
networkingMode** | string | NAT | 如果值为 mirrored ,则会启用镜像网络模式。默认或无法识别的字符串会生成 NAT 网络。 |
firewall** | bool | 是 | 如果设置为 true,则 Windows 防火墙规则以及特定于 Hyper-V 流量的规则可以筛选 WSL 网络流量。 |
dnsTunneling** | bool | false | 更改将 DNS 请求从 WSL 代理到 Windows 的方式 |
autoProxy* | bool | false | 强制 WSL 使用 Windows 的 HTTP 代理信息 |
其中
具有 path
值的条目必须是带有转义反斜杠的 Windows 路径,例如:C:\\Temp\\myCustomKernel
具有 size
值的条目后面必须跟上大小的单位,例如 8GB
或 512MB
。
值类型后带有 *
的条目仅在 Windows 11 中可用。
值类型后带有 **
的条目需要 Windows 11 版本 22H2 或更高版本。
这些设置是试验性功能的选择加入预览,我们的目标是将来将其设为默认设置。
.wslconfig
节标签:[experimental]
设置名称 | 值 | 默认值 | 说明 |
---|---|---|---|
autoMemoryReclaim |
string | disabled | 检测空闲 CPU 使用率后,自动释放缓存的内存。设置为 gradual 以慢速释放,设置为 dropcache 以立即释放缓存的内存。 |
sparseVhd |
bool | false | 如果设置为 true,则任何新创建的 VHD 将自动设置为稀疏。 |
useWindowsDnsCache ** |
bool | false | 仅当 wsl2.dnsTunneling 设置为 true 时才适用。如果此选项设置为 false,则从 Linux 隧道传输的 DNS 请求将绕过 Windows 中的缓存名称,以始终将请求放在网络上。 |
bestEffortDnsParsing ** |
bool | false | 仅当 wsl2.dnsTunneling 设置为 true 时才适用。如果设置为 true,Windows 将从 DNS 请求中提取问题并尝试解决该问题,从而忽略未知记录。 |
initialAutoProxyTimeout * |
string | 1000 | 仅当 wsl2.autoProxy 设置为 true 时才适用。配置启动 WSL 容器时,WSL 等待检索 HTTP 代理信息的时长(以毫秒为单位)。如果代理设置在此时间之后解析,则必须重启 WSL 实例才能使用检索到的代理设置。 |
ignoredPorts ** |
string | Null | 仅当 wsl2.networkingMode 设置为 mirrored 时才适用。指定 Linux 应用程序可以绑定到哪些端口(即使该端口已在 Windows 中使用)。通过此设置,应用程序能够仅侦听 Linux 中的流量端口,因此即使该端口在 Windows 上用于其他用途,这些应用程序也不会被阻止。例如,WSL 将允许绑定到 Linux for Docker Desktop 中的端口 53,因为它只侦听来自 Linux 容器中的请求。应在逗号分隔列表中设置格式,例如:3000,9000,9090 |
hostAddressLoopback ** |
bool | false | 仅当 wsl2.networkingMode 设置为 mirrored 时才适用。如果设置为 True ,将会允许容器通过分配给主机的 IP 地址连接到主机,或允许主机通过此方式连接到容器。始终可以使用 127.0.0.1 环回地址,此选项也允许使用所有额外分配的本地 IP 地址。仅支持分配给主机的 IPv4 地址。 |
值类型后带有 *
的条目仅在 Windows 11 中可用。
值类型后显示 **
的条目需要 Windows 版本 22H2 或更高版本。
我们可以自定义
|
|
移动子系统
我发现,子系统实际上安装到了 C:\Users\<username>\AppData\Local\Packages\Canonical...\LocalState\ext4.vhdx
,也就是说,保存在 C 盘,
参考博客:windows subsystem for linux - Where is WSL located on my computer? - Ask Ubuntu
到目前为止,WSL 没有提供自定义安装路径的配置。比较好的办法是装好子系统之后再移动子系统,也就是先通过在线安装安装好子系统,之后再导出成一个文件放到你想要的位置,然后再导入到 WSL 中。
另一个办法是手动去下发行版文件(tar 文件),放到目标目录,然后解压再安装,不过这样就缺失了很多功能。
操作步骤是:
首先,关闭所有子系统
|
|
查看所有分发版本
|
|
导出分发版为 tar 文件到 G 盘
|
|
注销当前分发版
|
|
重新导入并安装分发版在 G:\WSL\ubuntu22.04
|
|
此外,我还发现了一个工具 LxRunOffline,但是对 WSL2 的支持好像很差,有 bug,例如:Issue with WSL2 Ubuntu 22 trying to use LxRunOffline - Microsoft Q&A,反正官方的指令又不长,就用官方指令算了。
子系统桌面
子系统可配置其使用桌面,比如可以装 GNOME 或者 KDE,我找过了,有教程,但是没有必要,就用 Windows 桌面来访问子系统算了,反正文件系统是互通的。
设置 wsl 开机自启
方法如下:
-
WIN+R 运行
shell:startup
打开启动目录,其实就是C:\Users\<user_name>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
-
在此目录中创建文件
wsl-start.vbs
-
在
wsl-start.vbs
中填充如下内容,Ubuntu-22.0
需替换为你使用的发行版名称。1 2
Set ws = CreateObject("Wscript.Shell") ws.run "wsl -d Ubuntu-22.04", vbhide
-
想要停止 WSL 开机自启,直接删除掉
wsl-start.vbs
即可。
wsl 开机自启之后,我们可以在 wsl 中设置一些开机自启的服务,这样就可以做到 Windows 启动的时候 wsl 中的一些服务也自启。
为了不让 wsl 的开机自启影响到 Windows 的性能,推荐设置一下 wsl 的内存占用,CPU 占用的限制就不必了,一般用不到
开发相关
Python
Ubuntu22.04 自带 python3.10。
装 Docker
在 Ubuntu 中安装 Docker,参考博客:Ubuntu - Docker — 从入门到实践
网络设置 - 重点
如果你进入子系统的时候看到这个错误,说明子系统的网络没有配置好。
|
|
别人也遇到了同样的问题:Github Issue
这个问题和下面这个问题其实是一个问题:如何实现 WSL 使用宿主机的代理,比如 Clash?
在 WSL 2.0.5 版本 后,一些特性得以稳定,比如 镜像模式网络。启用镜像模式网络会将 WSL 更改为全新的网络体系结构,其目标是将 Windows 上的网络接口“镜像”到 Linux 中,以添加新的网络功能并提高兼容性。
以下是启用此模式的当前优势:
- IPv6 支持
- 使用 localhost 地址
127.0.0.1
从 Linux 内部连接到 Windows 服务器。不支持 IPv6 localhost 地址::1
- 改进了 VPN 的网络兼容性
- 多播支持
- 直接从局域网 (LAN) 连接到 WSL
如何启用镜像模式网络?我们在 配置子系统
小节了解过如何配置 WSL,具体做法是在 C:\Users\<UserName>\.wslconfig
文件中 (如果不存在就手动创建一个) 加入以下内容:
|
|
经过这样设置之后,WSL 管理的子系统的 IP 跟主机一样了,也就是说,两个机器共用一套 IP 和端口,在子系统中部署的服务,在 Windows 中直接可以通过 localhost 来访问,比如我在 wsl 中部署了一个 nginx 服务,代理了 80 端口,那么在 Windows 下的浏览器中,直接输入 localhost:80
就能访问,再加上 WSL 管理的子系统和 Windows 的文件本来就是互通的,修改和调试 Linux 下的应用就更加简单了。
我宣布,Windows11 是最好的 Linux 管理软件。
注意,这个时候,子系统中的服务,Windows 中想要访问只能通过 localhost 来访问,因此此时只是开启了 Hyper-V 的回环地址访问(WSL 基于 Hyper-V,localhost 基于回环地址),在其他机器上通过 Windows/子系统的具体 ip 访问子系统中的服务是访问不了的,必须在 wsl 的虚拟机的防火墙上开端口。也就是配置 WSL 虚拟机的入站规则。
配置 WSL 虚拟机的入站规则
官方文档:
首先,我们要知道 WSL 基于 Hyper-V,而 Hyper-V 的防火墙规则按 VMCreatorId 启用。若要获取 WSL 虚拟机的 VMCreatorId,则可以这样查询:
|
|
此时我们查看 WSL 虚拟机的配置,我们会发现入站是被阻断(Block
)的,也就是说,通过 IP 从 WSL 虚拟机的外部,是无法 ping 通 WSL 虚拟机中的任何端口的
|
|
我们可以开启这个入站规则,开启之后,虚拟机外部访问虚拟机内部的所有端口,都会放行。此命令需要以管理员权限运行终端
|
|
再次查看
|
|
那我们如何关闭 WSL 虚拟机入站的命令呢?
|
|
此外,你也可以不开启所有端口,也可以只开启特定端口,方法是创建一个入站规则
|
|
然后通过以下命令查看手动添加的入站规则,
应该会有两个默认的
PolicyStoreSourceType : Local
的规则。
|
|
删除此特定的入站规则
|
|
相关 API 页面:New-NetFirewallHyperVRule (NetSecurity) | Microsoft Learn、Remove-NetFirewallHyperVRule (NetSecurity) | Microsoft Learn