本人所使用的系统是 win11 22H2 家庭版,如果你不是非 CentOS 不可,强烈建议直接去微软应用商店里面下载 Ubuntu,全自动安装到 WSL,啥都不用管。(就是好像没办法选择安装路径)

1. 启用 WSL

刚开始安装 WSL 的时候,参考的是基于 Windwos11 的 WSL 安装 CentOS。说实话,我个人并不喜欢这篇博客。因为里面遗漏了很多东西,并且在不恰当的位置贴出了命令,导致读者会误以为是需要执行这些命令。

比如我就理解错误,先执行了设置 wsl 默认版本为 2 的命令,这个命令先不要执行!后文会告诉你为什么。

这篇博客中对开启 wsl 的设置的位置描述也不完全,看上去像从网上哪里抄过来的 win10 的设置逻辑(win11 的位置完全不一样)

plaintext
1
该博客原文:在windows设置中打开【启用或关闭Windwos功能】,勾选【适用于Linux的Windwos子系统】,点击确定后会系统会提示重启,选择确认即可

实际上在 win11 中,需要多点好几个地方才能找到这个设置的位置

plaintext
1
右键桌面 - 个性化 - 进入win11设置界面 - 应用 - 可选功能 - (往下滑)更多windows功能

image-20231015104701566

新版本的 win11 23h2 系统又把这个设置移动到系统-可选功能里面了。在 win11 设置里面搜索 “可选功能 “可以找到这里的设置。

image.png

更多 windows 功能选项框中(win10/11 的这个选项框基本相同),勾选下面的几个选项,三个都要勾选上!

  • 适用于 Linux 的 Windows 子系统;
  • 虚拟机平台(或 HyperV);
  • windows 虚拟机监控程序平台;

点击确定,就成功启用了 WSL。系统会弹出一个进度条,下载一些东西。

image-20231015104951463

处理完毕后,会让你重启电脑。如果 wsl 安装成功,你会在开始界面看到 wsl 的软件图标。

image.png

重启完成后,WIN+R 输入 cmd,打开命令行工具,在命令行工具中输入 wsl -l -v 命令,有相关输出就是启用成功了!默认情况下,执行 wsl -l -v 这个命令,应该会提示你当前什么虚拟机都没有安装,或者显示 wsl 的帮助命令。

注意,在 23h2 的 win11 版本中,即便没有做上述勾选 “适用于 linux 的 windows 子系统” 选项,wsl 命令也是存在的。

先不要着急做后续的步骤,我们先升级一下 wsl。

plaintext
1
wsl --update

执行 wsl --update 命令会提示你此命令需要提升(以管理员身份执行),点击是,会进入如如下页面,有一个自动下载 wsl 的升级包的进度条。下载速度会有点慢,耐心等待吧。

image.png

plaintext
1
2
3
PS C:\> wsl --update
正在安装: 适用于 Linux 的 Windows 子系统
已安装 适用于 Linux 的 Windows 子系统。

如果已经更新过了,则会显示如下字样

plaintext
1
2
3
PS C:\> wsl --update
正在检查更新。
已安装最新版本的适用于 Linux 的 Windows 子系统。

如果默认的 wsl --update 命令很慢,可以考虑使用 wsl --update --web-download 命令。更新下载完毕后会弹出一个管理员权限确定框,选择是即可。

2. 安装 Centos8

2.1 下载系统 zip

github/wsldl-pg/CentWSL 上下载适用于 wsl 的 CentOS8 系统的 zip

这个也可以:https://github.com/mishamosher/CentOS-WSL

image-20231015104110576

把 zip 解压到你想安装虚拟机的位置(一定要是一个空文件夹),然后右键 CentOS8.exe,以管理员身份运行。

image-20231015104455537

2.2 报错 HRESULT:0x80370102 解决

安装 CentOS8 的时候,就遇到了这个 issue 中的问题👇

github.com/wsldl-pg/CentWSL/issues/36

用管理员身份运行 CentOS8.exe 之后,弹出的终端会输出如下内容

plaintext
1
2
ERROR:Installation Failed!
HRESULT:0x80370102

根据该 issue 中最后一个回复的解决办法,我先将 wsl 版本设置回了 1(这就是为什么前文说不要先设置为默认 wsl2)

image-20231015112649042

plaintext
1
wsl --set-default-version 1

修改版本为 1 后,重复如上安装步骤(以管理员身份运行 CentOS8.exe),就成功安装了 CentOS 的虚拟机。此时在 win11 的文件管理器左侧会多出来一个 Linux 图标,里面有 CentOS8 的系统里面的文件。

image-20231015105247440

在 windows 的 powershell 或者 cmd 中,输入 wsl,就可以进入 CentOS8 的 bash;见下图,我们已经成功安装好了一个 CentOS8 的虚拟机。内部的文件就是 CentOS8 系统的默认文件。

在内部执行 exit 命令,就可以退出 wsl 虚拟机,回到 windows 的终端下。

image-20231015105338512

而且 WSL 有个最大的好处,就是它能自动挂载 windows 下的文件到 /mnt 目录下,这个目录里面可以看到我的 win11 宿主机的 3 个硬盘分区;windows 的文件资源管理器里面也可以看到 Linux 中的文件,方便我们在 windows 和 linux 下互传文件(就不需要用 sftp 工具了)

特别是如果你需要写带 Doxygen 文档的项目,在生成 Doxygen 的 html 后,就能直接从这里在 windows 的浏览器中打开网页,而不需要用 sftp 或者其他工具传到 windows 下再打开了!

当然,你也可以用带 GUI 的 Linux 系统来解决这个问题。

2.3 更新为 WSL2

使用 wsl -l -v 命令,可以看到当前运行的 wsl 虚拟机,版本是 1

plaintext
1
2
3
PS C:\Users\S2522\Desktop> wsl -l -v
NAME STATE VERSION
* CentOS8 Running 1

我们可以将其升级为 WSL2 版本,但是这里会告诉你需要更新内核组件

plaintext
1
2
3
4
PS C:\Users\S2522\Desktop> wsl --set-version CentOS8 2
正在进行转换,这可能需要几分钟时间...
有关与 WSL 2 的主要区别的信息,请访问 https://aka.ms/wsl2
WSL 2 需要更新其内核组件。有关信息,请访问 https://aka.ms/wsl2kernel

那就更新呗!微软官方文档 中会告诉你需要 wsl.exe --installwsl.exe --update 命令。

这里我执行了 wsl --update 命令,执行后会弹窗要你提供管理权限,并出现一个进度条,等他跑完就行。

plaintext
1
2
3
PS C:\Users\S2522\Desktop> wsl --update
正在安装: 适用于 Linux 的 Windows 子系统
已安装 适用于 Linux 的 Windows 子系统。

更新好了,再重新执行 wsl --set-version CentOS8 2 升级命令,会提示你正在执行转换,需要等待一会。

image-20231015105730332

最终成功转换了,使用命令 wsl -l -v 里面显示的版本也是 2 了。

plaintext
1
2
3
4
5
6
7
8
PS C:\Users\S2522\Desktop> wsl --set-version CentOS8 2
有关与 WSL 2 关键区别的信息,请访问 https://aka.ms/wsl2

正在进行转换,这可能需要几分钟时间。
操作成功完成。
PS C:\Users\S2522\Desktop> wsl -l -v
NAME STATE VERSION
* CentOS8 Stopped 2

搞定!现在我们就有一个方便的 CentOS8 的 WSL 环境啦!

可以用如下命令,将当前的 CentOS8 设置为默认的 wsl 虚拟机。这样在 windows 命令行中执行 wsl 或者 bash 命令,就能直接进入 CentOS8 中。

plaintext
1
wslconfig /setdefault CentOS8

重启电脑后,在 powershell 的下拉栏中会自动出现 CentOS8 的选项,点击它也能进入 wsl 虚拟机环境中。

image-20231015134927313

3. 解决 yum 报错问题

因为这个 CentOS 的镜像是最小安装版本(类似于 Docker 安装的 CentOS),所以内部的 yum 源都是坏掉的。执行 yum update 会出现如下报错。

plaintext
1
2
3
4
5
[root@7945R9P ~]# yum -y update
Failed to set locale, defaulting to C.UTF-8
CentOS-8 - AppStream 68 B/s | 38 B 00:00
Failed to download metadata for repo 'AppStream'
Error: Failed to download metadata for repo 'AppStream'

这时候需要进行 yum 源的重新设置,参考本站博客解决这个问题就行

【Docker】配置 CentOS 容器时出现 Error Failed to download metadata for repo ‘appstream’ Cannot prepare internal mirrorlist | 转载

搞定 yum 之后,就可以正常安装你想要的开发软件了。这个系统很轻量,sudo 和 passwd 等很多完整系统会自带的命令都没有,需要自行安装一些。

另外,我写过一个 CentOS8 的初始化脚本,可以自动化安装一些软件,这里安装的软件并不一定是你想要的,请酌情参考:https://gitee.com/musnows/centos8-init

rpm 30969 错误

但我在重试的时候,yum 安装软件还遇到了这个问题

plaintext
1
2
3
4
5
6
RPM: error: db5 error(-30969) from dbenv->open: BDB0091 DB_VERSION_MISMATCH: Database environment version mismatch
RPM: error: cannot open Packages index using db5 - (-30969)
RPM: error: cannot open Packages database in /var/lib/rpm
The downloaded packages were saved in cache until the next successful transaction.
You can remove cached packages by executing 'yum clean packages'.
Error: Could not run transaction.

找到了 GitHub 的 issue:Cannot install software with dnf after dnf update · Issue #46 · WhitewaterFoundry/Fedora-Remix-for-WSL · GitHub

该 issue 中的这个解决方案有效,注意,wsl 纯净安装的 centos 是没有 sudo 命令的,把命令里面的 sudo 去掉就行了。(默认情况下进入的是 root 用户,也不需要 sudo)

bash
1
2
3
sudo dnf upgrade --refresh rpm glibc
sudo rm /var/lib/rpm/.rpm.lock
sudo dnf upgrade dnf

执行后,再重新执行 yum install vim,不再出现报错。

bash
1
yum install -y sudo

你可以执行上述命令安装一下 sudo;

设置 ls 和 ll 命令别名

而且,默认情况下的 ls 命令也没有颜色输出,需要修改 bash 配置来设置命令别名;修改 ~/.bashrc 文件即可。

bash
1
2
alias ls='ls --color=auto'
alias ll='ls -l'

你也可以根据自己的喜好,改成 zsh 或者其他终端。

4.vscode 连接

普通的虚拟机我们需要用 vscode 的 remote ssh 插件来连接,但是 WSL 主机我们直接用 vsc 的 WSL 插件来连接就行了,使用的效果和 remote ssh 插件是相同的

image-20231015111412100

在左侧这个远程连接控制器中(和 Remote ssh 是同一个位置),找到上方的下拉条,改成 WSL 目标,就能看到我们的 CentOS8 虚拟机。点击连接它就可以了。

image-20231015111429863

但是 vscode 默认链接的是 root 用户,一般情况下肯定不会在 root 下写代码的。所以需要配置一下子用户

修改虚拟机中的 /etc/wsl.conf 文件,添加下面两行

text
1
2
[user]
default=用户名

然后回到 windows 的命令行,重启 wsl

plaintext
1
wsl --shutdown CentOS8

再次启动 wsl,这样 vsc 就能默认链接你的子用户了。

5. 修改 wsl 资源限制

默认情况下,wsl2 的虚拟机能访问到完整的系统资源,包括所有 CPU 核心和内存。

这就会导致如果 Linux 下对一些东西进行了缓存而没有及时清理,Windows 是没办法回收这部分内存的。最终就导致我们 Windows 宿主机没有足够的内存可用了,这怎么行?

这种情况下,一般 windows 系统会把 wsl 直接给干掉,那我们虚拟机里面跑的活也没办法完成了。要知道,Linux 可是很喜欢 cache 内存的,很容易会把宿主机的内存给干没。

为了解决这个问题,我们需要设置 wsl 的虚拟机内存 / CPU 限制。

Linux 下可以用这两个命令来查看 cpu 和内存的配置信息,刚开始的时候应该是和你的宿主机的 CPU 和内存一样。

bash
1
2
cat /proc/cpuinfo | grep processor # 查看cpu核心数量
cat /proc/meminfo | grep Total # 查看内存信息

在 windows 的 C 盘用户文件夹下,创建一个.wslconfig 文件,并在内部写入限制

  • processors 是 cpu 核数限制
  • memory 和 swap 都是内存限制

顶多设置为宿主机内存的一半,避免宿主机卡顿。

plaintext
1
2
3
4
[wsl2]
processors=8
memory=8GB
swap=8GB

这个配置文件的路径是(windows 下)

plaintext
1
C:\Users\你的用户名\.wslconfig

随后在 windows 的终端中使用如下命令,终止这个 wsl 虚拟机

plaintext
1
2
3
4
PS C:\Users\S2522\Desktop> wsl --shutdown CentOS8
PS C:\Users\S2522\Desktop> wsl -l -v
NAME STATE VERSION
* CentOS8 Stopped 2

wsl 命令中并没有 --start 选项,我们直接用 wsl 命令,就会自动重启并进入这个虚拟机。

这时候再在虚拟机内部看看 CPU 和内存信息,就可以看到你刚刚配置的性能限制结果了。

plaintext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@7945R9P ~]# cat /proc/cpuinfo | grep processor
processor : 0
processor : 1
processor : 2
processor : 3
processor : 4
processor : 5
processor : 6
processor : 7
[root@7945R9P ~]# cat /proc/meminfo | grep Total
MemTotal: 8136640 kB
SwapTotal: 8388608 kB
VmallocTotal: 34359738367 kB
HugePages_Total: 0

删除 wsl 主机

删除虚拟机的命令如下

plaintext
1
wsl --unregister <DistributionName>

操作后,本地 centos 安装目录的 ext4.vhdx 虚拟磁盘文件会被删除。

plaintext
1
2
3
PS C:\> wsl --unregister CentOS8
正在注销。
操作成功完成。

更多 wsl 命令参考微软官网 https://learn.microsoft.com/zh-cn/windows/wsl/basic-commands

6. 启用 systemctl

我们的系统里面有 systemctl 命令,但是没有办法使用。网上有些教程说用 service 命令来替代,但 CentOS 中是没有 service 命令的。

plaintext
1
2
3
[root@7945R9P bison-3.8]# systemctl
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down

6.1 distrod 第三方工具

我们需要用 distrod 来安装 systemctl 的组件,才能成功启用它。具体教程参考 github 仓库的 README 中的介绍。不是很难

https://github.com/nullpo-head/wsl-distrod

先下载一个自动安装的脚本(连不上 github 会报 ssl 或者 timeout 错误,请使用其他办法下载这个脚本再丢到虚拟机里面去就行)

plaintext
1
2
3
curl -L -O "https://raw.githubusercontent.com/nullpo-head/wsl-distrod/main/install.sh"
chmod +x install.sh
sudo ./install.sh install

然后用下面两个命令之一来启动(第一个命令是会在 windows 开机自动启动的)

plaintext
1
2
/opt/distrod/bin/distrod enable --start-on-windows-boot
/opt/distrod/bin/distrod enable

更多内容相见该仓库 README

请注意,执行第一个自启动命令的时候需要 windows 的管理员权限,此时需要输入的是系统登录的微软账户的密码(不是你的 PIN),看下面,我第一次输入密码输入的就是 PIN,显示错误,第二次输入了微软账户的密码才成功。

plaintext
1
2
3
4
5
6
7
8
9
10
11
12
[root@7945R9P pkg]# /opt/distrod/bin/distrod enable --start-on-windows-boot
[Distrod] Distrod has been enabled. Now your shell will start under systemd.
[Distrod] Enabling atuomatic startup of Distrod. UAC dialog will appear because scheduling
a task requires the admin privilege. Please hit enter to proceed.


Error
It seems the task has not been scheduled successfully. You may have typed a wrong password, or you may not have the
necessary administrative privileges. Do you want to retry?
[Y] Yes [N] No [?] 帮助 (默认值为“Y”): y
Enabling autostart has succeeded.
[Distrod] Distrod will now start automatically on Windows startup.

操作完成后,需要重启虚拟机。用如下命令将对应的 wsl 虚拟机关闭就行了,再次执行 wsl 就会重启这个虚拟机。

plaintext
1
wsl --terminate CentOS8

如图,我的 systemctl 命令已经生效。

image-20231015150251531

也能正常通过 systemctl 命令启动 mariadb 数据库

image-20231015150404823

6.2 微软官方(推荐)

参考 https://zhuanlan.zhihu.com/p/569883693

查看 wsl 版本号命令为: wsl --version,如果此命令未正常回显版本号,或版本号低于 0.67.6,那么你安装的 wsl 还不支持 systemd。如下,我的 wsl 版本已经是支持的了。

plaintext
1
2
3
4
5
6
7
8
PS C:\Users\S2522\Desktop> wsl --version
WSL 版本: 1.2.5.0
内核版本: 5.15.90.1
WSLg 版本: 1.0.51
MSRDC 版本: 1.2.3770
Direct3D 版本: 1.608.2-61064218
DXCore 版本: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windows 版本: 10.0.22621.2134

进入 wsl 的 CentOS 虚拟机,执行如下命令

bash
1
echo -e "[boot]\nsystemd=true" | sudo tee -a /etc/wsl.conf

随后 exit 退出虚拟机,回到 windows 终端命令行,重启 wsl

powershell
1
wsl --shutdown

随后再次在 windows 命令行下执行 wsl 命令,重启这个虚拟机;

重启 wsl 虚拟机后,在虚拟机内部执行如下命令

bash
1
ps --no-headers -o comm 1
  • 如果这个命令返回结果是 systemd,则代表我们的 systemctl 命令已经可以使用。
  • 如果返回的是 init(CentOS8),则设置失败(检查一下 centos 的 wsl 版本是否为 2)
bash
1
2
# ps --no-headers -o comm 1
systemd

如下图,我已经设置成功了!

image-20231015204810685

微软官方支持的 systemd 还是有一点是优于 distrod 的,那就是启用了官方 systemd 的 wsl2 实例,在用户停止操作后,会自动关闭,和未启用 systemd 时的特性一样,这有利于节约电脑的计算资源。

写在最后

在本文第一点中,我写了当时我参考的博客中错误的部分,这都是我对一个不完善博客的吐槽,但并没有贬低这个教程的意思啊!至少他告诉我基本步骤应该做哪些。

为什么我要吐槽呢?因为这种写的不全的博客经常会让读者得去重新搜索某些设置的位置,而作者明明是已经走过这个流程的。博客里面作者的截图明显是 windows11,但他提供的设置却是 win10 中的旧位置。多花 30 秒写清楚位置并带上截图,不知道能节省读者多少时间…… 如果你体会过查资料的时候阅读这些「断头短尾」的博客,应该也能体会到我的心情。

any way,本文到此结束,感谢你看到最后。欢迎交流!