我在 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
我该如何修复它?
答案1
令人惊讶的是,在 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 替代品部分。
好消息是,Systemd 现在在许多 WSL 系统上都得到了 Ubuntu 的正式支持。请参阅下文,了解如何确定您的系统是否支持它以及如何启用它(如果您需要它)。
您是否应该在 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 的应用程序版本
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 repo 中的页面。要手动安装版本:
重新启动(以确保 WSL 根本没有被使用)。一个简单的
wsl --shutdown
可能工作,但通常不会。从上面的链接下载 1.0.0(或更高版本)。
启动管理员 PowerShell 并:
Add-AppxPackage <path.to>/Microsoft.WSL_1.0.0.0_x64_ARM64.msixbundle wsl --version # to confirm
有些人可能需要运行 wsl update:
wsl --update
要启用,请在 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/
。因此,例如,您可以
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 可能是许多服务的更好选择。
但有些服务没有对应的 init-script,尤其是在其他发行版上。为简单起见,我们假设
ssh
init.d
脚本不是可用的。在这种情况下,“答案”是弄清楚 Systemd 单元文件正在做什么,并尝试手动复制它。这可能在复杂性上有很大差异。但我首先要查看您尝试运行的 Systemd 单元文件:
less /lib/systemd/system/ssh.service
# Trimmed [Service] EnvironmentFile=-/etc/default/ssh ExecStartPre=/usr/sbin/sshd -t ExecStart=/usr/sbin/sshd -D $SSHD_OPTS RuntimeDirectory=sshd RuntimeDirectoryMode=0755
我删除了一些不太相关的行以便于理解其行为,但您可以使用
man systemd.exec
、man systemd.service
和其他命令来查看大多数选项的作用。在这种情况下,当你 时
sudo systemctl start ssh
,它:$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 Interop、临时文件等的方式!由于 WSL2 的共享 VM 特性,其中一些更改甚至会影响您正在使用的其他发行版没有系統。
我个人的建议是:(a) 如果你使用其中一种技术,请确保你了解幕后发生的情况;(b) 不要这样做!或者 (c) 至少,当询问为什么某些东西不起作用时,一定要让人们知道你在 WSL 下使用 Systemd 帮助脚本(以及哪一个)。
这样就解决了...
让我们从一些在 WSL 中启用 Systemd 的比较流行的项目开始:
我个人并不经常运行其中任何一个,但它们都是开源的,我扫描了源代码以比较这些技术。从核心上讲,每个都会创建一个新的命名空间或容器,Systemd 可以在其中作为 PID 1 运行。
您可以按照以下步骤实际操作:
跑步:
sudo -b unshare --pid --fork --mount-proc /lib/systemd/systemd --system-unit=basic.target
这将在具有自己的 PID 映射的新命名空间中启动 Systemd。在该命名空间内,Systemd 将成为 PID1(这是它必须具备的功能)并拥有所有其他进程。但是,“真实”PID 映射仍然存在于该命名空间之外。
请注意,这是启动 Systemd 的“最低限度”命令行。它至少不支持:
- Windows Interop(运行 Windows 的能力
.exe
) - Windows PATH(如果没有 Windows Interop 则没有必要)
上面列出的脚本和项目做了额外的工作以使这些事情也能正常运转。
- Windows Interop(运行 Windows 的能力
等待几秒钟让 Systemd 启动,然后:
sudo -E nsenter --all -t $(pgrep -xo systemd) runuser -P -l $USER -c "exec $SHELL"
这将进入命名空间,您现在可以使用
ps -efH
它来查看systemd
在该命名空间中作为 PID 1 运行的进程。此时您应该可以运行了
systemctl
。在向自己证明这是可行的之后,我建议完全退出所有 WSL 实例,然后执行
wsl --shutdown
。否则,在你这样做之前,有些东西会“损坏”。它们很可能会被“修复”,但这超出了任何一个 Ask Ubuntu 问题的范围 ;-)。我的建议是参考上述项目,看看他们如何处理它。
脚注 1 - Snap
Ubuntu 中的某些应用程序和功能非常复杂,以至于它们不太可能脱离 Systemd。这里最明显的例子就是 Snap 系统。我相信它理论上可能可以不使用 Systemd 来创建 Snap 系统的一个版本。但是,有两个很好的理由说明这不会发生(至少在短期内不会):
Snap 是由 Canonical 创建和支持的系统。
典范有选择 Systemd 作为 Ubuntu 初始化系统。仅仅因为 WSL 不支持它(很容易)并不能改变这一点。Canonical 开发人员编写 Snap 系统时期望 Systemd 的功能存在。
目前似乎没有任何第三方希望将 Snap 移植到非 Systemd 发行版。这些发行版通常使用 Flatpak 代替 Snap。但值得注意的是,即使是 Flatpak 也倾向于在可用 Systemd 的发行版上使用 Systemd。但是,Flatpak 也可用于非 Systemd 发行版。
脚注 2 - Gnome
Gnome 也是一个与 Systemd 紧密耦合的应用程序(生态系统),但它非常流行,有已移植到非 Systemd 初始化系统。也就是说,在 Ubuntu 上运行它确实假设存在 Systemd,因此如果您想在不使用 Systemd 的情况下在 Ubuntu/WSL 上运行它,您必须对其他发行版上使用的流程进行逆向工程。
脚注 3 - 其他依赖于 Systemd 的应用程序
也有一些情况是某些软件期望Systemd 无法工作(或者至少无法完全工作),如果没有它的话。我最近遇到的一个是座舱。
虽然我能够在没有 Systemd 的情况下启动并运行它,但它最终需要 Systemd 的存在才能执行许多(如果不是大多数)功能。实际上,Cockpit 的某些部分是 Systemd 的前端。
这种类型的软件执行Systemd 命令(例如systemctl
)可能是“有替代”规则的例外。
答案2
我遇到了类似的问题。我想用 启动 Nginx sudo systemctl start nginx
,但它在 Ubuntu WSL 上不起作用。我发现该sudo service nginx start
命令的作用完全相同。它可以在不调用 的情况下启动 Nginx systemctl
。
答案3
这systemctl
现已在 wsl 中可用
将这些行添加到/etc/wsl.conf
注释中,您将需要使用 sudo 权限运行编辑器,例如:sudo nano /etc/wsl.conf
[boot]
systemd=true
然后使用以下方法关闭 nano 编辑器Ctrl+O保存并CTRL+X退出。
完成上述步骤后,关闭 WSL 发行版 Windows 并运行wsl.exe --shutdown从 PowerShell 重新启动 WSL 实例。启动后,systemd 应该正在运行。您可以使用命令检查这一点systemctl 列表单元文件 --type=service它应该显示你的服务状态。