系统尚未使用 systemd 作为 init 系统 (PID 1) 进行引导。无法操作

dsh*_*256 200 boot windows-10 windows-subsystem-for-linux

我在 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
Run Code Online (Sandbox Code Playgroud)

我该如何修复它?

Not*_*1ds 243

令人惊讶的是,在使用 WSL 大约 6 年之后,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 中 Systemd 的替代方案部分

  • 好消息是,许多 WSL 系统上的 Ubuntu 现在正式支持 Systemd。请参阅下文,了解如何确定您的系统是否支持它以及如何启用它(如果需要)。

您应该在 WSL 中启用 Systemd 吗?

首先,考虑是否应该在 WSL 中启用 Systemd。启用 Systemd 将自动启动许多在 WSL 下可能不需要的后台服务和任务。因此,它还会增加 WSL 启动时间,尽管影响取决于您的系统。检查下面的“替代方案”部分,看看是否有更好的选择可以满足您的需求。例如,该service命令可以执行您需要的操作,而无需任何额外的工作。

虽然我很高兴 Systemd 可以作为一个选项,但我个人计划尽可能在没有它的情况下继续运行。

如何在 Ubuntu/WSL 中启用 Systemd

作为背景,WSL2 现在有两种不同的“交付机制”(希望我能想到一个更好的术语)。我将它们称为不同的“版本”或“版本”,但我们倾向于已经使用该术语来表示 WSL 版本 1 和 2。

  • 最初,WSL1 和 WSL2 都是作为 Windows功能提供的,可通过打开或关闭 Windows 功能设置来启用。此功能过去(现在仍然)内置于 Windows,被称为 WSL 的“内置”版本。

  • 2021 年 10 月,Microsoft 开始将 WSL2 作为 Windows应用程序提供,可以通过 Microsoft Store(以及下文所述的其他方法)安装。

它是支持 Systemd 的WSL应用程序。目前,WSL 的内置版本不支持 Systemd。要使用新的 WSL 应用程序,您必须使用受支持的 Windows 版本:

  • 使用 Windows 11 22H2 或更高版本的新 WSL 用户将在运行时自动接收 WSL 的应用程序版本wsl --install,除非专门添加该--inbox选项。

  • Windows 11 21H2用户仍然可以使用以下方法安装WSL应用程序。

  • Windows 10 用户将需要KB5020030或更高版本。请注意,在此更新时尚不清楚较旧的 Windows 10 版本是否可以运行。到目前为止,我个人只能在 Windows 10 22H2 上验证它。

准备好必备的 Windows 版本后,您可以使用多种方法安装或升级到 WSL 应用程序的 1.0.0 版本(或更高版本):

  • 通过 Microsoft Store(作为“Linux 的 Windows 子系统”)。

  • 或者从Github 存储库中的发布页面。要手动安装版本:

    1. 重新启动(以确保 WSL 根本未在使用)。简单的wsl --shutdown 可能会起作用,但通常不会。

    2. 从上面的链接下载 1.0.0(或更高版本)版本。

    3. 启动管理员 PowerShell 并:

      Add-AppxPackage <path.to>/Microsoft.WSL_1.0.0.0_x64_ARM64.msixbundle
      wsl --version # to confirm
      
      Run Code Online (Sandbox Code Playgroud)

有些人可能需要运行 wsl update:

wsl --update
Run Code Online (Sandbox Code Playgroud)

要启用此功能,请在 WSL 下启动 Ubuntu(或其他 Systemd)发行版(通常就wsl ~可以工作)。

sudo -e /etc/wsl.conf
Run Code Online (Sandbox Code Playgroud)

添加以下内容:

[boot]
systemd=true
Run Code Online (Sandbox Code Playgroud)

退出 Ubuntu 并再次:

wsl --shutdown
Run Code Online (Sandbox Code Playgroud)

然后重新启动Ubuntu。

sudo systemctl status
Run Code Online (Sandbox Code Playgroud)

...应该显示您的 Systemd 服务。


WSL 中 Systemd 的替代方案

systemctl最常用于在 Ubuntu 下启动服务。对于不支持 Systemd 的旧版本(或者如果您只是选择不启用它),仍然有几种替代方法可以代替该systemctl命令。

幸运的是,Ubuntu 总体来说在没有 Systemd 的情况下也能应付得很好。

如何处理 Systemd 缺失的情况

Systemd 的核心只是一种(可能过于简单化)“完成系统任务的方式”。通常(但并非总是如此,请参见下面的脚注)有一种无需 Systemd 即可完成相同任务的方法,而且通常不止一种方法。

  • 选项一:“老方法”

    在 WSL 上的 Ubuntu 中,许多常见的系统服务仍然具有init.d可用于代替systemctlSystemd 单元的“旧”脚本。您可以使用 来查看这些 ls /etc/init.d/

    因此,例如,您可以ssh从开始sudo service ssh start,它将/etc/init.d/ssh使用start参数运行脚本。

    即使某些非默认软件包(例如 MySql/MariaDB)也会安装 Systemd 单元文件init.d脚本,因此您仍然可以对service它们使用该命令。

    要在启动时自动启动服务(a la systemctl enable),请参阅超级用户上的此答案,了解如何使用 执行此操作/etc/wsl.conf

  • 选项 2:Docker

    许多包/服务都可以作为 Docker 镜像提供。Docker 在 WSL2 上的 Ubuntu 下运行良好(特别是 WSL2;它无法在 WSL1 上运行)。如果您尝试启动的服务没有 SysVinit“服务”脚本,则很可能有一个在容器化环境中运行的可用 Docker 映像。

    示例:Elasticsearch,如这个问题和我的回答

    • 好处#1:不会干扰已安装的其他软件包(没有依赖性问题)。
    • 好处#2:Docker 镜像本身几乎从不使用 Systemd,因此您可以经常检查Dockerfile以了解服务是如何在没有 Systemd 的情况下启动的。有关详细信息,请参阅下一个选项 - “手动方式”。
  • 选项 3:“‘手动’方式”

    编辑:从之前的“选项 2”位置下降了一个档次,因为 Docker 可能是许多服务的更好替代方案。

    但有些服务没有等效的初始化脚本,尤其是在其他发行版上。为简单起见,我们假设该ssh init.d脚本不可用。

    在这种情况下,“答案”是找出 Systemd 单元文件正在做什么,并尝试手动复制它。这在复杂性上可能有很大差异。但我首先查看您尝试运行的 Systemd 单元文件:

    less /lib/systemd/system/ssh.service
    
    Run Code Online (Sandbox Code Playgroud)
    # Trimmed
    [Service]
    EnvironmentFile=-/etc/default/ssh
    ExecStartPre=/usr/sbin/sshd -t
    ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
    RuntimeDirectory=sshd
    RuntimeDirectoryMode=0755
    
    Run Code Online (Sandbox Code Playgroud)

    我已经删除了一些与理解其行为不太相关的行,但是您可以man systemd.execman systemd.service和其他人来查看大多数选项的作用。

    在这种情况下,当您 时sudo systemctl start ssh,它:

    • 读取环境变量 (the $SSHD_OPTS)/etc/default/ssh
    • 测试配置,如果失败则退出
    • 确保 RuntimeDirectory 存在并具有指定的权限。这翻译为/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 运行。

    您可以按照以下步骤查看实际效果:

    1. 跑步:

      sudo -b unshare --pid --fork --mount-proc /lib/systemd/systemd --system-unit=basic.target
      
      Run Code Online (Sandbox Code Playgroud)

      这将在一个具有自己的 PID 映射的新命名空间中启动 Systemd。在该命名空间内,Systemd 将是 PID1(因为它必须运行)并拥有所有其他进程。然而,“真正的”PID 映射仍然存在于该命名空间之外。

      请注意,这是启动 Systemd 的“最低限度”命令行。它至少不会支持:

      • Windows Interop(运行 Windows 的能力.exe
      • Windows 路径(无论如何,如果没有 Windows Interop,则不需要)

      上面列出的脚本和项目需要做额外的工作才能让这些东西正常工作。

    2. 等待几秒钟 Systemd 启动,然后:

      sudo -E nsenter --all -t $(pgrep -xo systemd) runuser -P -l $USER -c "exec $SHELL"
      
      Run Code Online (Sandbox Code Playgroud)

      这将进入命名空间,您现在可以使用ps -efH它来查看它systemd在该命名空间中作为 PID 1 运行。

      此时,您应该可以运行了systemctl

    3. 在向自己证明这是可能的之后,我建议完全退出所有 WSL 实例,然后执行wsl --shutdown. 否则,你将会有一些东西被“破坏”,直到你做到为止。它们可能会被“修复”,但这超出了任何一个询问 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 init 系统的端口。也就是说,在 Ubuntu 上运行它确实假定存在 Systemd,因此如果您想在不使用 Systemd 的情况下在 Ubuntu/WSL 上运行它,则必须对其他发行版上使用的进程进行逆向工程。

脚注 3 - 其他依赖于 Systemd 的应用程序

在某些情况下,某些软件需要Systemd,如果不存在,则无法运行(或至少不能完全运行)。我最近遇到的一个是Cockpit

虽然我能够在没有 Systemd 的情况下启动并运行它,但它最终希望 Systemd 存在才能执行许多(如果不是大多数)功能。实际上,Cockpit 的一部分是 Systemd 的前端。

这种类型的软件,即执行Systemd 命令(例如systemctl)的软件,可能是“有替代方案”规则的例外。

  • 一个好问题,**一个好答案**,所以加一。我认为`service` cmd属于`systemd`。我在 wsl 上遇到来自 OP 的错误,但是 `mariadb` 可与 `service` 一起使用。[service](https://askubuntu.com/a/903405/321926) 是一个 `wrapper`,可以与 `init 一起使用.d` 和 `systemctl`。 (3认同)

小智 19

好吧,我的回答可能与问题无关,但我也遇到过类似的问题。我想使用“sudo systemctl start nginx”启动 Nginx,但它在 Ubuntu WSL 上不起作用。但我发现命令“sudo service nginx start”的作用完全相同。它可以在不调用“systemctl”的情况下启动Nginx

  • 是的 - 我在现有的答案中介绍了使用“service”命令来执行此操作。请参阅标题为*“旧方法”*的部分。 (4认同)