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

我在Windows 11上使用WSL2。我想在Ubuntu 20.04中运行systemctl命令,但是它给了我以下错误:
System has not been booted with systemd as init system (PID 1). 
Can't operate. Failed to connect to bus: Host is down

我该如何修复它?


7systemctl 命令在WSL上无法正常工作,除非进行一些严重的黑客操作。不建议使用。 - user535733
为什么你想在Windows 11上使用systemctl?你应该使用Windows命令。你想要实现什么目标? - WinEunuuchs2Unix
我想在运行WSL2的Ubuntu 20.04中重新启动ssh服务。 - dsha256
4@WinEunuuchs2Unix OP正在WSL2中运行Ubuntu。问题不是关于在Windows中运行systemctl,而是在Ubuntu中运行。话虽如此,user535733是完全正确的。 - ChanganAuto
好的,谢谢! - dsha256
4尝试使用“service”命令代替。 - user535733
3具体来说,sudo service ssh restart。但要注意,在WSL2下,ssh的工作方式可能与您预期的不太相同。 - NotTheDr01ds
谢谢大家! - dsha256
为什么?他很可能是在按照安装指南操作。例如,https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-redis-on-ubuntu-20-04 - dylanh724
2个回答

令人惊讶的是,在经历了大约6年的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中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月,微软开始将WSL2作为Windows的一个应用程序提供,可以通过Microsoft Store(以及下面描述的其他方法)进行安装。
正是WSL应用程序支持Systemd。目前,内置版本的WSL不支持Systemd。要使用新的WSL应用程序,您必须使用受支持的Windows版本。
  • 新的 Windows 11 22H2 或更高版本的 WSL 用户在运行 wsl --install 命令时,将自动安装 WSL 应用程序版本,除非明确添加 --inbox 选项。

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

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

在满足先决条件的 Windows 版本后,您可以使用多种方法安装或升级到 WSL 应用程序的 1.0.0 版本(或更高版本):

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

  • 或者从Github存储库的Releases页面。要手动安装一个版本:

    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 # 确认版本
      
要启用,请在WSL下启动您的Ubuntu(或其他Systemd)发行版(通常只需wsl ~即可)。
sudo -e /etc/wsl.conf

添加以下内容:
[boot]
systemd=true

退出Ubuntu然后再次启动:
wsl --shutdown

然后重新启动Ubuntu。
sudo systemctl status

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

在WSL中替代Systemd的选择

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

幸运的是,Ubuntu整体上对没有Systemd也能很好地适应。

如何处理缺乏Systemd

Systemd本质上只是一种(可能是过度简化的)"完成系统任务的方式"。通常情况下(但并非总是,见下面的脚注),可以找到一种无需Systemd的方法来完成相同的任务,而且通常还有多种方法可供选择。

  • 选项1:“旧方法”

    在WSL上的Ubuntu中,许多常见的系统服务仍然可以使用“旧的”init.d脚本来替代systemctl与Systemd单元一起使用。您可以使用ls /etc/init.d/命令查看这些脚本。

    例如,您可以使用sudo service ssh start启动ssh,它将运行/etc/init.d/ssh脚本并传递start参数。

    甚至一些非默认安装的软件包,如MySql/MariaDB,也会安装Systemd单元文件和旧的init.d脚本,因此您仍然可以对它们使用service命令。

    要在启动时自动启动服务(类似于systemctl enable),请参阅Super User上的此答案以了解如何使用/etc/wsl.conf实现此目的。

  • 选项2:Docker

    许多软件包/服务都可以作为Docker镜像使用。Docker在WSL2上运行得很好(特别是WSL2;在WSL1上无法运行)。如果您要启动的服务没有SysVinit“service”脚本,很可能有一个可用的Docker镜像可以在容器化环境中运行。

    例如:Elasticsearch,如此问题和我的答案

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

    编辑:由于Docker可能是许多服务的更好选择,因此将其从原来的“选项2”降低了一级。

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

    在这种情况下,“答案”是弄清楚Systemd单元文件在做什么,并尝试手动复制。这可能会因复杂性而有所不同。但是,我建议首先查看您要运行的Systemd单元文件:

    less /lib/systemd/system/ssh.service
    
    # 省略部分内容
    [Service]
    EnvironmentFile=-/etc/default/ssh
    ExecStartPre=/usr/sbin/sshd -t
    ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
    RuntimeDirectory=sshd
    RuntimeDirectoryMode=0755
    

    为了理解其行为,我省略了一些不太相关的行,但您可以使用man systemd.execman systemd.service和其他命令来了解大多数选项的作用。

    在这种情况下,当您运行sudo systemctl start ssh时,它会执行以下操作:

      脚注1 - Snap

      在Ubuntu中,有一些应用程序和功能非常复杂,以至于很难从Systemd中解开。最明显的例子就是Snap系统。我相信理论上可能创建一个不使用Systemd的Snap系统版本。然而,这不会发生的两个很好的原因(至少目前不会发生):

      • Snap是由Canonical创建和支持的系统。

      • Canonical已经选择了Systemd作为Ubuntu的init系统。即使WSL不容易支持它,这也不会改变。Canonical的开发人员编写Snap系统时期望Systemd的功能存在。

      • 目前似乎没有第三方希望将Snap移植到非Systemd发行版。这些发行版通常使用Flatpak代替Snap。然而,值得注意的是,即使在可用Systemd的发行版上,Flatpak也倾向于使用Systemd。但是,Flatpak也适用于非Systemd发行版。

      脚注2 - Gnome

      Gnome也是一个与Systemd紧密耦合的应用程序(生态系统),但它足够受欢迎,以至于已经有了适用于非Systemd init系统的移植版本。尽管如此,在Ubuntu上运行它需要假设存在Systemd,因此如果您想在Ubuntu/WSL上不使用Systemd运行它,您将不得不反向工程处理其他发行版上使用的流程。

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

      还有一些软件在没有Systemd的情况下可能无法正常工作(或者至少不完全正常)。我最近遇到的一个例子是Cockpit

      虽然我能够在没有Systemd的情况下使其运行起来,但它最终需要Systemd存在才能执行许多(如果不是大部分)功能。实际上,Cockpit的一部分是Systemd的前端。

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


2一个好问题,以及一个好答案,所以加一分。我认为service命令属于systemd。我在wsl上遇到了OP的错误,但是mariadb可以使用serviceservice是一个wrapper,可以与init.dsystemctl一起使用。 - Timo
我很困惑。WSL曾经有systemctl/d,WSL曾经可以很好地使用挂载的驱动器,WSL曾经是Ubuntu非常稳定的代表...现在我会称它为Winbuntu,因为它似乎不再是Ubuntu,而是Windows版本的Ubuntu被破坏以适应WSL...这很奇怪,因为我记得当WSL 1推出时,我能够通过powershell而不是Windows商店无问题地安装真正的Ubuntu。WSL发生了什么?有没有办法恢复真正的Ubuntu? - gunslingor
@gunslingor 我同意...你有点困惑 ;-). 但是说真的,你几乎肯定记错了(或者可能是怀旧)。WSL从来没有支持过Systemd。这是关于这个话题的Github问题,在第一个WSL1测试版发布后仅15天就被提出了。 - NotTheDr01ds
在这个问题中,一个相关的评论:“在没有cron、syslog、sshd或终端仿真器(我们所拥有的只是一种控制台仿真器)以及其他服务器/守护进程/后台任务的情况下运行WSL,并不等同于运行一个Ubuntu开发机器”,表明人们甚至在那时都不认为它是“真正的Ubuntu”。自那时以来,WSL在多年间取得了巨大的进步,但它仍然是Windows上的一个“开发工具”,而不是旨在复制“完整的Ubuntu(或其他Linux)环境”的虚拟机。 - NotTheDr01ds
是的,HyperV可能是我记错了,纯Ubuntu镜像。我怀疑WSL使用了一些预先调整过的组件,并将其路由到主机系统以便更容易地提供服务...或者是lxssmanager之类的东西,我忘了。相比使用WSL和Docker桌面,Docker在WSL Ubuntu上运行得更好,而且当使用挂载的Windows共享时,Ubuntu非常慢,但使用挂载的Ubuntu共享时速度很快...这就是为什么我怀疑是HyperV的原因...我记得有这个问题。 - gunslingor
@gunslingor 对- Hyper-V是有道理的,因为在这种情况下它确实是一个“纯虚拟机”。顺便说一下- LxssManager实际上只是WSL背后的服务。 - NotTheDr01ds
对于选项3,有一个适用于它的脚本,并且对我有效:http://wiki.webperfect.ch/index.php?title=WSL:_System_has_not_been_booted_with_systemd_as_init_system_(PID_1)#:~:text=Failed%20to%20connect%20to%20bus%3A%20Host%20is%20down,is%20not%20enabled%20by%20default%20in%20WSL%202. 同时应用修复方法:https://github.com/DamionGans/ubuntu-wsl2-systemd-script/issues/36 - LingYan Meng
@LingYanMeng 有相当多的脚本,其中一些比其他脚本更强大。对于所有的脚本,我建议了解它们的工作原理,因为没有一个脚本能在所有情况下都起作用,最终都需要进行一些故障排除。 - NotTheDr01ds
我怎么知道我是否有收件箱版本呢?wsl --version打印出:无效的命令行选项:--version - Quolonel Questions
1@QuolonelQuestions 很好的问题 - 那里的结果显示了收件箱版本。如果你有商店版本,它会返回实际版本(以及一些额外信息)。 - NotTheDr01ds
你的回答很好,但没有涵盖使用/etc/wsl.conf文件启动服务的另一种方式。你可以添加以下指令:[boot] command="service apache2 start; service mariadb start"来源 - Arthur Lacoste
@ArthurLacoste 很有道理 - 我在这个回答中只关注了如何启动服务,但没有涉及到如何在开机时自动启动服务。根据您的建议,我已经添加了一个链接,该链接涵盖了这方面的内容。谢谢! - NotTheDr01ds

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

4没问题 - 我在我之前的回答中已经涵盖了使用service命令来完成这个任务。请查看标题为“旧方法”的部分。 - NotTheDr01ds
@NotTheDr01ds 你说得对。对不起,我漏掉了那个要点。 - Anynomius
它有效,sudo service docker start - infiniteLearner