Windows11 WSL2使用

wsl全称是windows的linux子系统,可以理解为在你的windows电脑上提供一个linux的工作环境。

windows虚拟化的基础知识

windows功能 作用 其他
Hyper-V 微软自己的虚拟化工具 包含了“管理工具”和“平台”,其中“平台”包含“服务”和“虚拟机监控程序”
Windows Subsystem for Linux WSL1,不是我们讨论的WSL2所需要的
Virtual Machine Platform 虚拟机平台(WSL2的底层依赖) 看到说Hyper-V也依赖这个,但启用Hyper-V并不需要启用虚拟机平台,因此我觉得Hyper-V依赖的是“Hyper-V虚拟机监控程序”吧
Windows Sandbox 一个隔离的桌面环境 我反正没用过,不了解
Windows 虚拟机监控程序平台 用于支持vmware等第三方虚拟机软件
  1. 虚拟机平台会一定程度上影响游戏性能,为了游戏性能,可以关闭虚拟机平台、Hyper-V。Windows虚拟机监控程序平台、适用于Linux的Windows子系统我理解是不影响游戏性能的。参考用于在 Windows 11 中优化游戏性能的选项
  2. Hyper-V和vmware等软件是冲突的,详见虚拟化应用程序无法与 Hyper-V、Device Guard 和 Credential Guard 协同工作

关闭虚拟机平台和Hyper-V虚拟机监控程序:

dism.exe /online /disable-feature /featurename:VirtualMachinePlatform /norestart
DISM /Online /Disable-Feature /FeatureName:Microsoft-Hyper-V-All /NoRestart
@REM 其实只要关闭 Microsoft-Hyper-V-Hypervisor 就行了

开启虚拟机平台和Hyper-V虚拟机监控程序:

dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
DISM /Online /Enable-Feature /All /FeatureName:Microsoft-Hyper-V-All /NoRestart

查看所有windows功能

dism.exe /online /Get-Features

%userprofile%/.wslconfig

[wsl2]
# networkingMode=bridged
# vmSwitch=Home # 此处的名称和指定的虚拟网络交换机一致
# dhcp=false # 禁用DHCP,在WSL2系统中通过设置Linux的静态IP实现获取IP
networkingMode = mirrored # 端口自动转发,Windows和WSL共享端口,都使用127.0.0.1
dnsTunneling = true # WSL的DNS请求通过Windows转发
firewall = true # WSL同步Windows防火墙规则
autoProxy = true # Windows设置代理时自动同步给WSL,用于使用代理访问外网

[experimental]
sparseVhd = true # 自动清理磁盘空间
autoMemoryReclaim = gradual # 可以在gradual 、dropcache 、disabled之间选择。 如果设置成gradual,需要设置kernelCommandLine以开启cgroupV2,否则docker会有问题

[wsl2]
swap = 0 # 禁用swap,使用内存交换文件,不使用磁盘交换文件
# 开启cgroup v2,用于docker和autoMemoryReclaim = gradual共存
kernelCommandLine = cgroup_no_v1=all systemd.unified_cgroup_hierarchy=1 

上面的配置启用了自动内存回收,不过仍然可以手动释放page cache:

echo "sync; echo 3 > /proc/sys/vm/drop_caches; touch /root/drop_caches_last_run" |tee /tmp/drop_caches
install /tmp/drop_caches /usr/local/bin/loss
loss

安装WSL2

这里使用了Debian12,因为我不喜欢Ubuntu的Snap,而且Debian12的wsl发行版支持ebpf。

@REM 启用VMP 虚拟机平台
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
echo you may need reboot to take effect
@REM 启用wslservice
sc.exe config wslservice start= demand
wsl --set-default-version 2
wsl -v
wsl --list --online
wsl --install -d Debian
@REM 设置默认root用户
debian config --default-user root

第一次启动

设置用户名和密码:

启用systemd:

if ! grep -q "systemd=true" /etc/wsl.conf; then
    cat <<EOF | sudo tee /etc/wsl.conf
[boot]
systemd = true

[user]
default = root

EOF
fi

执行 wsl --shutdown 重启wsl,然后就可以使用systemd了。

其他设置

apt设置代理

默认安装的Debian的默认源是官方源,国内比较慢,直接配置apt代理。

if ! grep -q Acquire::http::Proxy /etc/apt/apt.conf.d/proxy.conf;then
    cat <<EOF | sudo tee /etc/apt/apt.conf.d/proxy.conf
Acquire::http::Proxy "https://user:passwd@server:port/";
Acquire::https::Proxy "https://user:passwd@server:port/";
# 否则报错没有ca-certificates
Acquire::https::Verify-Peer "false";
EOF
fi

apt不更新某软件

apt-mark 可以对软件包进行设置(手动/自动)安装标记,也可以用来处理软件包的 dpkg(1) 选中状态,以及列出或过滤拥有某个标记的软件包。

apt-mark auto – 标记指定软件包为自动安装
apt-mark manual – 标记指定软件包为手动安装
apt-mark minimize-manual – Mark all dependencies of meta packages as automatically installed.
apt-mark hold – 标记指定软件包为保留(held back),阻止软件自动更新
apt-mark unhold – 取消指定软件包的保留(held back)标记,解除阻止自动更新
apt-mark showauto – 列出所有自动安装的软件包
apt-mark showmanual – 列出所有手动安装的软件包
apt-mark showhold – 列出设为保留的软件包

比如保留某个软件不更新可以使用hold标记,如docker
sudo apt-mark hold docker*

sudo apt-mark showhold

如果要解除保留可以使用unhold
sudo apt-mark unhold docker*

git设置

由于wsl支持windows和linux的命令互操作,你实际上会有两个git,一个wsl的git,一个windows的git.exe。

WSL git配置

git config --global core.editor vim
git config --global http.proxy http://127.0.0.1:7880
git config --global https.proxy http://127.0.0.1:7880
git config --global "includeIf.hasconfig:remote.*.url:*://*github.com*/**.path" .gitconfig_github
git config --global "includeIf.hasconfig:remote.*.url:git@github.com:*/**.path" .gitconfig_github
cat > ~/.gitconfig_github <<EOF
[user]
        name = arloor
        email = admin@arloor.com
EOF
git config --global credential.helper store
# wsl的git忽略文件权限的变更
git config --global core.filemode false
# wsl的git 提交时自动将crlf转换为lf,checkout时不转成crlf
git config --global core.autocrlf input

windows git配置

wsl的git 提交时自动将crlf转换为lf,checkout时不转成crlf

git config --global core.autocrlf input

autocrlf的配置详见git文档

简单解释就是:

  • windows使用crlf换行,linux和macos使用lf换行(早期macos使用cr换行)
  • autocrlf=true,提交到index时自动将crlf换成lf,checkout时自动将lf换成crlf。适合windows使用,widnwos默认配置
  • autocrlf=input,提交到index时自动将crlf换成lf,checkout时不自动转换。适合macos和linux用。
  • autocrlf=false,不自动转换换行符。

git文档推荐,linux和macos使用input,windows使用true。这样保证index、linux、macos中永远是lf,windows中是crlf。

但是我的设置成了windows上也是input。

直接原因是我有很多shell脚本,原本git.exe的bash是可以执行crlf的shell文件的。安装wsl后,bash被替换为了Debian的bash,不能处理crlf的shell文件。——我需要shell脚本是lf的。根本原因,换行符的问题是一个历史遗留问题,是操作系统之间的壁垒。现代的ide或者文本编辑器都是跨平台使用的,他们能处理换行符的问题,那么用vscode,idea就行了,不要用windows的老版文本编辑器了。我已经比较习惯在linux处理文本了,vim、grep、awk、sed等等很爽,wsl的最大好处就是在windows上能用上原生的bash,那就文本全部linux化好了。

安装ca证书

sudo cp your-certificate.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

参考文档

内存释放太慢,最不满意的一点

即使有了autoMemoryReclaim,任务管理器里看到的 VmmemWSL 还是远大于 wsl 里top看到的res + buffer/cache。即使wsl -t Debian 也不会释放内存,只有wsl --shutdown才可以释放内存。观察到断开所有wsl的terminal和所有由用户启动的后台进程(不包含systemd启动的)都结束后,wsl会在一段时间后自动shutdown,此时VmmemWSL也会降为0。但如果有后台进程常驻的话,就不会自动关闭了,这就建议放个bat文件在桌面,不用wsl的时候就shutdown掉吧。

@echo off
wsl --shutdown

相关issue: WSL 2 consumes massive amounts of RAM and doesn’t return it

关于内存回收的问题,找到两个文章:

文章 时间 说明
Memory Reclaim in the Windows Subsystem for Linux 2 October 30th, 2019 基于某kernel patch的pageReporting,将虚拟机闲置的连续的内存返还给宿主机。WSL会在cpu Idle的时候进行内存的compaction,然后进行返还。也可以手动执行echo 1 > /proc/sys/vm/compact_memory触发
Automatic memory reclaim September 18th, 2023 “逐渐释放”:基于CgroupV2的memory.reclaim特性逐渐释放page cache,与docker使用的CgroupV1冲突。“idle时立即释放”:不依赖CgroupV2的特性,可与docker共存

让wsl一直在后台运行

https://www.cnblogs.com/wswind/p/17201979.html

简单方案: 写个VBS脚本,启动wsl的terminal在后台一直等待输入:

set ws=wscript.CreateObject("wscript.shell")
ws.run "wsl -d Debian", 0

进阶方案: 只启动一个后台进程,即使多次运行该VBS脚本:

keepalive命令:

cat > /usr/local/bin/keepalive <<\EOF
command="watch -n 30 uptime | tee /tmp/uptime"
ps -ef|grep "${command}"|grep -v grep
if [ $? -ne 0 ]
then
    sh -c "${command}"
else
    echo "The command is already running"
fi
EOF
chmod +x /usr/local/bin/keepalive

写个VBS脚本:

set ws=wscript.CreateObject("wscript.shell")
ws.run "wsl -d Debian /usr/local/bin/keepalive", 0

常见报错解决

0x80070422 wslservice服务未启动

无法启动服务,原因可能是已被禁用或与其相关联的设备没有启动。
Error code: Wsl/0x80070422

解决方案:

sc.exe config wslservice start= demand

0x8004032d 虚拟机平台功能未启用

WslRegisterDistribution failed with error: 0x8004032d
Error: 0x8004032d (null)

解决方案:在启用和关闭windows功能中打开“虚拟机平台”或使用下面的cmd命令并重启

dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

端口被占用问题解决

# 查看当前动态端口范围
netsh int ipv4 show dynamicport tcp
# 查看被使用的端口
netsh int ipv4 show excludedportrange protocol=tcp

# 修改动态端口范围
netsh int ipv4 set dynamic tcp start=50000 num=15536
netsh int ipv6 set dynamic tcp start=50000 num=15536
# 重启网络
net stop winnat
net start winnat

卸载发行版

wsl --uninstall Debian
wsl --unregister Debian