我在 Windows 11 上使用 WSL2。我想systemctl
在 Ubuntu 20.04 中运行该命令,但它给了我以下错误:
System has not been booted with systemd as init system (PID 1).
Can't operate. Failed to connect to bus: Host is down
我该如何解决?
我在 Windows 11 上使用 WSL2。我想systemctl
在 Ubuntu 20.04 中运行该命令,但它给了我以下错误:
System has not been booted with systemd as init system (PID 1).
Can't operate. Failed to connect to bus: Host is down
我该如何解决?
简短的回答:
最常见的用途
systemctl
是启动服务。这通常(但不总是)可以在 WSL 上的 Ubuntu 上使用:有关更多详细信息以及替代解决方案,请参见下文,其中包括:
service
命令更详细(更多)更长的解释:
令人惊讶的是,经过 5 年左右的 WSL,Ask Ubuntu 上似乎没有一个好的、通用的“Systemd”问题。所以这看起来是一个很好的用途。
问题
通常,当您看到以下两条消息之一时:
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
然后它通常是相同的根本原因。在
systemctl
尝试开始的情况下ssh
,您会看到两者。正如评论中提到的那样,核心问题是 WSL 不使用 Systemd,即使在它是默认值的发行版中也是如此。相反,WSL 目前使用自己的进程作为 PID 1,它执行我在这个答案
/init
中提到的一些 WSL 特定的任务(所以我不会在这里重复它们)。虽然 WSL(恕我直言)是在 Windows(最近甚至是 GUI)中拥有全功能 Linux CLI 的好方法,但缺少 Systemd 确实会使期望它存在的发行版中的事情变得更加困难。幸运的是,在没有 Systemd 的情况下,Ubuntu 总体来说还是相当不错的。
如何处理缺少 Systemd
无论如何,Systemd 的核心只是一种(可能过于简单化)“完成系统任务的方式”。通常(但不总是,见下面的脚注)有一种方法可以在没有 Systemd 的情况下完成相同的任务,而且通常不止一种方法。
选项1:“旧方式”
在 WSL 上的 Ubuntu 中,许多常见的系统服务仍然具有
init.d
可用于代替systemctl
Systemd 单元的“旧”脚本。您可以使用ls /etc/init.d/
.因此,例如,您可以从 开始
ssh
,sudo service ssh start
它将运行带有参数的/etc/init.d/ssh
脚本。start
即使是一些非默认的包,比如 MySql/MariaDB 也会安装 Systemd 单元文件和旧
init.d
脚本,所以你仍然可以service
对它们使用命令。选项 2:码头工人
许多包/服务都可以作为 Docker 镜像使用。Docker 在 WSL2 上的 Ubuntu 下运行良好(特别是 WSL2;它不会在 WSL1 上运行)。如果您尝试启动的服务没有 SysVinit“服务”脚本,则很可能有一个在容器化环境中运行的 Docker 映像可用。
示例:Elasticsearch,如在这个问题和我的回答中。
Dockerfile
以查看在没有 Systemd 的情况下服务是如何启动的。有关详细信息,请参阅下一个选项 - “手动方式”。选项 3:“‘手动’方式”
编辑:从以前的“选项 2”位置下降了一个档次,因为 Docker 可能是许多服务的更好选择。
但是有些服务没有等效的初始化脚本,尤其是在其他发行版上。为简单起见,我们假设该
ssh
init.d
脚本不可用。在这种情况下,“答案”是弄清楚 Systemd 单元文件在做什么并尝试手动复制它。这在复杂性上可以有很大的不同。但我会先查看您尝试运行的 Systemd 单元文件:
我已经删除了一些不太相关的行来理解它的行为,但是你可以
man systemd.exec
,man systemd.service
和其他人来看看大多数选项的作用。在这种情况下,当你
sudo systemctl start ssh
,它:$SSHD_OPTS
从_/etc/default/ssh
/run/sshd
(从man systemd.exec
)。当您停止服务时,这也会删除运行时目录。/usr/sbin/sshd
使用选项运行所以,如果你没有任何基于环境的配置,你可以设置一个脚本来:
/run
,这是一个tmpfs
挂载,因此每次重启 WSL 实例后都会将其删除。0755
/usr/sbin/sshd
以 root 身份启动...如果没有 Systemd ,您将手动完成相同的操作。
同样,这可能是最简单的例子。对于更复杂的任务,您可能还有更多工作要做。
选项 4:在 PID 命名空间/容器中以 PID 1 运行 Systemd
最后,可以让 Systemd 在 WSL2(但不是 WSL1)下运行。这是一个相当高级的主题,尽管有多个脚本和项目试图简化它。
警告: Systemd 在启动时从根本上改变了 Ubuntu 的许多方面,包括 X 套接字、登录、WSL 互操作、临时文件等的方式!由于 WSL2 的共享 VM 特性,其中一些更改甚至会影响您在没有Systemd 的情况下使用的其他发行版。
我个人的建议是(a)确保您了解在使用其中一种技术时幕后发生的事情,(b)不要这样做!,或者(c)至少,在询问时关于为什么某些东西不起作用的问题,请确保让人们知道您在 WSL 下使用 Systemd 辅助脚本(以及哪个)。
有了这个...
让我们从一些更流行的项目开始,以在 WSL 中启用 Systemd:
我个人不会定期运行它们中的任何一个,但它们都是开源的,并且我已经扫描了源代码以比较这些技术。在核心,每个都创建一个新的命名空间或容器,Systemd 可以在其中作为 PID 1 运行。
您可以按照以下步骤查看此操作:
跑:
这会在具有自己的 PID 映射的新命名空间中启动 Systemd。在该命名空间内,Systemd 将是 PID1(它必须运行)并拥有所有其他进程。但是,“真正的”PID 映射仍然存在于该命名空间之外。
请注意,这是启动 Systemd 的“最低限度”命令行。它至少不支持:
.exe
)上面列出的脚本和项目做了额外的工作以使这些东西也能正常工作。
等待几秒钟让 Systemd 启动,然后:
这进入了命名空间,您现在可以使用它
ps -efH
来查看它systemd
在该命名空间中作为 PID 1 运行。此时,您应该可以运行
systemctl
.在向自己证明这是可能的之后,我建议完全退出所有 WSL 实例,然后执行
wsl --shutdown
. 否则,在您这样做之前,您将有一些事情被“破坏”。它们可能是“固定的”,但这超出了任何一个 Ask Ubuntu 问题的范围;-)。我的建议是参考上面的项目,看看他们是如何处理的。脚注 1 - 捕捉
Ubuntu 中的某些应用程序和功能非常复杂,以至于它们不太可能从 Systemd 中分离出来。这里最明显的例子是 Snap 系统。我确信理论上可以在不使用 Systemd 的情况下创建 Snap 系统的一个版本。然而,这不会发生有两个很好的理由(至少很快):
Snap 是由 Canonical 创建和支持的系统。
Canonical已选择 Systemd 作为 Ubuntu 初始化系统。仅仅因为 WSL 不支持它(很容易)并不会改变这一点。Canonical 开发人员编写 Snap 系统时期望 Systemd 的功能存在。
目前似乎没有任何第三方希望将 Snap 移植到非 Systemd 发行版。这些发行版通常使用 Flatpak 代替 Snap。然而,应该注意的是,即使是 Flatpak 也倾向于在可用的发行版上使用 Systemd。但是,Flatpak 也可用于非 Systemd 发行版。
脚注 2 - 侏儒
Gnome 也是一个与 Systemd 紧密耦合的应用程序(生态系统),但它非常流行,以至于有非Systemd 初始化系统的端口。也就是说,在 Ubuntu 上运行它确实假设存在 Systemd,因此如果您想在不使用 Systemd 的情况下在 Ubuntu/WSL 上运行它,则必须对其他发行版上使用的过程进行逆向工程。
脚注 3 - 其他依赖于 Systemd 的应用程序
在某些情况下,某些软件需要Systemd 并且如果它不存在就无法工作(或至少不能完全工作)。我最近遇到的一个是Cockpit。
虽然我能够在没有 Systemd 的情况下启动并运行它,但它最终希望 Systemd 存在以便执行许多(如果不是大多数)功能。实际上,Cockpit 的一部分是 Systemd 的前端。
这种执行Systemd 命令(例如
systemctl
)的软件可能是“有替代方案”规则的例外。好的,我的回答可能与问题无关,但我有类似的问题。我想用“sudo systemctl start nginx”启动一个 Nginx,但它在 Ubuntu WSL 上不起作用。但我发现命令“sudo service nginx start”的作用完全相同。它可以在不调用“systemctl”的情况下启动 Nginx