WSL2开启systemctl命令简单方法

上一级页面:index-wsl

前言

我们如果想要拥有一个 systemd 环境的话,该怎麽办呢?

本文记录如何提供systemd支持,目的是能够正常使用systemctl命令,并能够正常运行一些应用程序

提供完整systemd的项目有很多:

这些项目的核心原理并无大异,无非是细节处理的好坏和附加功能的多少,但最重要的一点可能是工作层次不同。

Pasted image 20220606151803

前三个脚本都工作在图中的 shell 层,要依赖外置命令执行系统调用。genie 工作在 应用程序 层,它使用 C# 编写,通过 shell 执行系统调用,比前三个还多了一层。最后两个虽然也是 应用程序,但它们由 Rust 编写,不经 shell,而直接由 C system call wrapper 执行系统调用,依赖最少,动态链接编译后只有几百 K。

init

我们探讨的是WSL2的发行版,而WSL2的发行版,均拥有微软提供的 init,它是一种systemd的替代方案,不支持systemctl 命令,

WSL2 本身是由 Windows 负责运行的,因此使用 tree 或 ps 命令时会看到根进程不是 systemd,这将导致无法启动 Linux 系统服务的守护进程(deamon)。

当我们执行 systemctl 命令的时候,会显示出我们的 init system (PID 1) 并非 systemd,而是微软提供的 init

1
2
3
4
5
6
systemctl
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
ps u -q 1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 908 592 ? Sl 10:31 0:00 /init

我们如果想要拥有一个 systemd 环境的话,该怎麽办呢?

本文记录如何提供systemd支持,目的是能够正常使用systemctl命令,并能够正常运行一些应用程序

(推荐)官方方案

官方现在已经支持systemd,见Advanced settings configuration in WSL | Microsoft Learn

(推荐)方案一–使用**wsl-distrod**

推荐这种方案,阅读官方的README,nullpo-head/wsl-distrod:Distrod是WSL 2的元发行版,它可以在一分钟内安装Ubuntu,Arch,Debian,Gentoo等系统。Distrod还具有Windows启动和端口转发功能的内置自动启动功能。 (github.com)

使当前发行版运行wsl-distrod

通过此安装,systemd 已在 WSL 2 发行版中启用。

  1. 下载并运行最新的安装程序脚本。
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

此脚本安装发行版,但尚未启用它。

  1. 在发行版中启用发行版

您有两种选择。如果要在 Windows 启动时自动启动发行版,请通过以下命令启用 distrod

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

否则,如果不在 Windows 启动时自动启动发行版

1
/opt/distrod/bin/distrod enable

如果要在以后启用自动启动,则可以再次运行

1
/opt/distrod/bin/distrod enable --start-on-windows-boot
  1. 重新启动发行版

关闭 WSL 的终端。打开一个新的命令提示符窗口,然后运行以下命令。

1
wsl --terminate DistroName

例如

1
wsl -t Ubuntu

重新打开新的 WSL 窗口后,shell 将在 systemd 会话中运行。

另请参见

方案二–使用genie bottle

要求

**仅仅wsl2支持使用_systemd_  或  genie **

在安装 genie 之前,最好将 systemd 默认目标设置为_多用户目标_。(multi-user.target以命令行形式运行)

要将引导目标更改为多用户模式模式: 见如何在 systemd Linux 中将引导目标切换到文本或 GUI - nixCraft (cyberciti.biz)

1
sudo systemctl set-default multi-user.target

multi-user.target是 genie 设计运行的目标,

因为许多发行版使用的默认值为 graphical.target,这包括图形桌面的服务,

如果你的默认值为graphical.target,在 WSL/WSLg 环境下正常运行之前,这些服务至少需要进行大量的重新配置。

安装依赖

安装 daemonize 和 fontconfig

1
sudo apt install -y fontconfig daemonize

你可以尝试标记它们为自动安装

1
sudo apt-mark auto fontconfig daemonize

过去有脚本可以替换 init 为 systemd,但现在不再推荐使用。

现在推荐使用 genie 工具,他将在用户态创建 systemd 进程

首先要安装 dotnet runtime,因 genie 使用 .net core

下载deb文件

1
2
3
wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb

安装dotnet runtime

1
2
3
4
sudo apt-get update; \
sudo apt-get install -y apt-transport-https && \
sudo apt-get update && \
sudo apt-get install -y dotnet-sdk-6.0

上面演示的是为 Ubuntu 20.04安装 .net core,其他linux发行版本看文档:Instll Documentations

按文档要求,添加wsl-transdebian 仓库,安装文档见:wsl-transdebian |仅限 WSL 的 apt 包的存储库。 (arkane-systems.github.io)

确保已安装lsb_release,用来获取系统信息

1
sudo apt install lsb-release

安装systemd-genie

下面的命令权限要求很高,用root身份执行

1
sudo -s

配置 wsl-transdebian 源

1
2
3
4
5
6
7
8
9
10
11
wget -O /etc/apt/trusted.gpg.d/wsl-transdebian.gpg https://arkane-systems.github.io/wsl-transdebian/apt/wsl-transdebian.gpg

chmod a+r /etc/apt/trusted.gpg.d/wsl-transdebian.gpg

cat << EOF > /etc/apt/sources.list.d/wsl-transdebian.list
deb https://arkane-systems.github.io/wsl-transdebian/apt/ $(lsb_release -cs) main
deb-src https://arkane-systems.github.io/wsl-transdebian/apt/ $(lsb_release -cs) main
EOF

apt update

1
sudo apt install -y systemd-genie

修复SSHD服务

1
sudo ssh-keygen -A

/etc/fstab是用来存放文件系统的静态信息的文件。 位于/etc/目录下,可以用命令less /etc/fstab 来查看

1
less /etc/fstab

需要清空/etc/fstab

1
sudo echo '' > /etc/fstab

回到正常用户,

1
exit

运行

见官方wiki:首页 ·阿卡内系统/精灵维基 (github.com)

运行命令

1
genie -s

一些 systemd 模块无法加载。根据首次运行输出的列表直接禁用即可

Pasted%20image%2020220511190116.png

无法加载的模块列表:已知在WSL下有问题的系统单元 ·阿卡内系统/精灵维基 (github.com)

比如下面这些就已知无法加载,直接禁用即可

1
2
sudo systemctl disable systemd-modules-load
sudo systemctl disable multipathd.service

使用 reboot命令重新引导系统: 用例见Linux Reboot Command Example - nixCraft (cyberciti.biz)

1
sudo systemctl reboot

开机启动genie

可以用下列方案,见在每个 shell 会话中自动启动精灵 ·arkane-systems/genie Wiki (github.com)

首先进入 WSL 环境,编辑~./profile,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 设置genie自启动(genie 依赖于shell)
# Are we in the bottle?
temp_genie=$(exec /usr/bin/genie -b)
# inside (exit code 0) - inside the bottle
if [ $temp_genie == "inside" ](%20$temp_genie%20==%20%22inside%22%20); then
unset temp_genie
echo "inside the bottle"
# do nathing

else
# if no inside the bottle
read -t 3 -q "yn? * Preparing to enter genie bottle (in 3s); press y to abort it ? "
# 换行符
echo
# 用户输入y,则abort it
if [ $yn != "y" ](%20$yn%20!=%20%22y%22%20); then
# outside (exit code 1) - outside the bottle (bottle exists)
if [ $temp_genie == "outside" ](%20$temp_genie%20==%20%22outside%22%20); then
unset temp_genie
echo "outside the bottle (bottle exists)"
echo "Starting genie:"
exec /usr/bin/genie -s

# no-bottle (exit code 2) - no bottle is present
elif [ $temp_genie == "no-bottle" ](%20$temp_genie%20==%20%22no-bottle%22%20); then
unset temp_genie
echo "no bottle is present"
echo "Starting genie:"
exec /usr/bin/genie -s
fi
fi
fi

将自动进入瓶子,除非您进入shell的三秒钟内输入n中止,或者等待超时

然后回到 Windows,Win + R 组合键打开运行,输入 shell:startup 进入启动目录。

创建一个 vbs 文件,名称随意,内容如下:

1
2
Set ws = CreateObject("Wscript.Shell")
ws.run "wsl -d Debian", vbhide

注:参数中的 Debian 需要改成你自己使用的 WSL 发行版名称。

更改genie的配置

genie的默认配置有一些不太方便的地方,具体来说,默认设置如下,配置文件在/etc/genie.ini

1
2
3
4
5
6
7
8
9
[genie]
systemd-timeout=240
clone-env=WSL_DISTRO_NAME,WSL_INTEROP,WSLENV,DISPLAY,WAYLAND_DISPLAY,PULSE_SERVER
secure-path=/lib/systemd:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
clone-path=false
target-warning=true
update-hostname=true
update-hostname-suffix=-wsl
resolved-stub=false
1
sudo vim /etc/genie.ini

需要更改这几项

1
2
3
4
[genie]
systemd-timeout=60
clone-path=true
update-hostname=false
  • systemd-timeout默认的超时时间太长了,安装你系统的情况自己设置一个短一些的
  • clone-path复制必要的Windows环境变量到wsl-systemd-genie-bottle中
  • update-hostname取消在命令行中添加主机名的后缀,这能有效避免一些烦人的bug,就像如图的bug

Pasted image 20220609103648

之后,重新设置WSL主机的主机名,避免与Windows的主机名相同(不使用默认的主机名,自己生成一个WSL主机名),

genie常用命令列表

genie 的使用方法比较简单:

1
2
3
4
5
6
7
8
# 启动 systemd 环境
genie -i
# 启动 systemd 环境,并在环境中打开 shell
genie -s
# 启动 systemd 环境,并在环境中运行命令
genie -c commandi
# 检测genie是否正在运行
genie -r

genie与WSLG集成

index-wslg

genie与vs code集成

genie与-vs-code集成

wsl2上的systemctl 模块初始化,必做!!

有许多模块需要处理,按以下列表进行处理

genie-报错处理

如何重启系统

使用 reboot命令重新引导系统: 用例见Linux Reboot Command Example - nixCraft (cyberciti.biz)

1
sudo systemctl reboot

systemctl使用方法

以sshd为例,用法如下:

1
sudo systemctl start ssh
1
sudo systemctl stop ssh

在开机时启用服务

1
sudo systemctl enable ssh.service

在开机时禁用服务

1
sudo systemctl disable ssh.service

查看服务是否开机启动

1
sudo systemctl is-enabled ssh.service

systemctl常用命令

对于用户来说,最常用的是下面这些命令,用于启动和停止 Unit(主要是 service)。

立即启动一个服务

1
sudo systemctl start apache.service

立即停止一个服务

1
2
# 立即停止一个服务
sudo systemctl stop apache.service

重启一个服务

1
2
# 重启一个服务
sudo systemctl restart apache.service

显示服务的状态

1
sudo systemctl status test.service

在开机时启用服务

1
sudo systemctl enable test.service

在开机时禁用服务

1
sudo systemctl disable test.service

查看服务是否开机启动

1
sudo systemctl is-enabled test.service

查看已启动的服务列表

1
sudo systemctl list-unit-files|grep enabled

查看各服务的预配置(VENDOR PRESET)

1
sudo systemctl list-unit-files

查看启动失败的服务列表

1
sudo systemctl --failed

杀死一个服务的所有子进程

1
2
# 杀死一个服务的所有子进程
sudo systemctl kill apache.service

重新加载一个服务的配置文件

1
2
# 重新加载一个服务的配置文件
sudo systemctl reload apache.service

重载所有修改过的配置文件

1
2
# 重载所有修改过的配置文件
sudo systemctl daemon-reload

显示某个 Unit 的所有底层参数

1
2
# 显示某个 Unit 的所有底层参数
sudo systemctl show httpd.service

显示某个 Unit 的指定属性的值

1
2
# 显示某个 Unit 的指定属性的值
sudo systemctl show -p CPUShares httpd.service

设置某个 Unit 的指定属性

1
2
# 设置某个 Unit 的指定属性
sudo systemctl set-property httpd.service CPUShares=500

reset-failed

您可能正在寻找reset-failed

1
2
$ Sudo systemctl reset-failed
$

从systemd手册页:

reset-failed [PATTERN…]

重置指定单位的“失败”状态,或者如果没有传递单位名称,则重置所有单位的状态。当某个单元以某种方式出现故障时(即进程退出时出现非零错误代码,异常终止或超时),它将自动进入“失败”状态,并记录其退出代码和状态,以供管理员自省直至服务使用此命令重新启动或重置。

参考、引用、致谢

WSL2 的 Linux 中运行 systemctl 命令 - 知乎 (zhihu.com)

在 WSL2 上获得近乎完整的 Linux 体验 | Pan Xiao’s Blog (ddupan.top)

Systemd 用户服务失败 - Tableau

https://github.com/MicrosoftDocs/WSL/issues/457#issuecomment-751351142

linux — 如何删除systemd服务 (wake-up-neo.com)