如果没有 systemd,WSL/WSL2/WSLg 如何工作?

Cae*_*ste 37 linux process daemon systemd windows-subsystem-for-linux

据我了解,systemd 是 Linux 的“主”守护进程,在启动并运行其 init 函数后立即管理所有其他进程。由于我遇到了这个(现已解决)问题,即无法在 WSL 上使用任何 systemd 命令,我意识到它根本没有 systemd 进程。

现在,出于好奇,我想知道 WSL 依赖于哪个进程管理而不是 systemd。由于我在“一般谷歌搜索”上没有找到令人满意的答案,我想,让我们在这里尝试一下。

Not*_*1ds 46

更新: Systemd 支持现已在 WSL2 中提供,并且(更新 #2)现已在Windows 10 和 Windows 11上提供。正如我的原始答案(如下)和其他人所指出的那样,这不是必需的,并且可以选择加入。

Systemd 要求您使用更新的 WSL。有关如何更新到最新版本并启用官方 Systemd 支持的详细信息,请参阅我在 Ask Ubuntu 上的回答。


原始答案,仍然普遍适用于 WSL 的运作方式:

好问题——这里有很多有趣的内容!

首先,让我们建立一些术语:

systemd 是 Linux 的“主”守护进程,在启动并运行其 init 函数后立即管理所有其他进程。

首先,@mascoj 在评论中提出的一个很好的观点是Linux 根本不需要Systemd。它肯定在绝大多数 Linux 发行版中使用,但还有其他替代方案(如@user1686 的答案提到的),它们都早于 Systemd 并自 Systemd 以来出现。一些发行版默认使用这些替代方案,并且(个人观点)其中一些发行版可能因此在 WSL 下工作得更好。

从高层次来看,Systemd 通常具有以下几个功能:

  • 初始化系统:执行启动时系统初始化(例如创建或清理临时文件等)
  • 在启动时运行服务(例如cronsshdmariadb等)
  • PID 1 进程:所有其他进程所在的主进程
  • 进程主管(又名进程管理器):启动、监视、重新启动附加服务
  • 附加服务(Systemd 做了很多事情,例如日志记录、挂载等等)

这些功能中的大多数都可以单独处理,但 Systemd“包揽了这一切”。

一些发行版和系统不依赖 Systemd,并且做事的方式也不太单一。例如,某些系统在启动过程中的某个时刻让 init 系统将控制权移交给单独的进程管理程序。进程主管可能是也可能不是 PID1。如果不是,则通常 Init 进程仍保留为 PID1,并且进程管理程序在其下运行。进程管理器通常具有启动时所需的服务列表,并且它执行和监视这些服务。

一些发行版(我想到了 Artix,我也相当肯定 Gentoo)允许您混合和匹配几个不同的 init 系统和进程管理程序。


现在让我们从高层次上讨论标题中的问题:

如果没有 Systemd,WSL/WSL2/WSLg 如何工作?

  • WSL2:

    重要的是要了解,当您运行 WSL2 发行版时,该发行版并不是在虚拟机中运行。WSL2本身正在运行一个具有自己的发行版的虚拟机(如果我不得不猜测的话,可能是基于Mariner的)。

    在隐藏的虚拟机内部,您的发行版在其自己的命名空间集中运行。如果您在 WSL2 中同时运行多个发行版,它们在同一个虚拟机中运行,每个发行版都有自己的:

    • PID命名空间
    • 挂载命名空间
    • IPC命名空间
    • 悉尼科技大学命名空间
    • WSLg 系统分发(仅限 Windows 11)

    但是,它们都与父 WSL2 VM 共享以下内容(因此彼此共享):

    • 用户命名空间
    • 网络命名空间
    • Cgroup命名空间
    • 设备树(除了/dev/pts
    • CPU/内核/内存/交换(显然)
    • /init二进制(但不是进程)

    这与 Docker 或 Podman(以及其他)等容器系统的工作方式非常非常相似。

    在大多数(但肯定不是全部)容器内,您会发现很少有进程管理程序正在运行。

    大多数容器由启动它们的“外部”进程(例如 Docker)告知要启动哪些服务。对于 WSL,传统上有一个wsl命令告诉 WSL 要启动哪些服务。例如(一个过于简单化且不一定是一个很好的例子):

    wsl -e crond
    
    Run Code Online (Sandbox Code Playgroud)

    然而,一个重要的区别是,与传统容器不同,WSL 始终有自己的 Init 进程,以 PID1 运行(原因见下文)。对于大多数其他容器类型,PID1 是您告诉它首先启动的进程。

  • WSL1

    虽然 WSL1 从技术上讲并不像 WSL2 那样“在容器/命名空间中运行”,但它确实共享相同的 Init 概念以实现互操作性。

    同样重要的是要记住,WSL1 并不支持所有 Linux 系统调用。当 WSL1 首次发布时,其覆盖率约为 70%。它在运行大量工具方面做得相当出色,但我有一种感觉,Systemd 通常尝试启动的单元数量可能会暴露一些差距。

  • WSLg

    WSLg 在所谓的“系统发行版”中运行,该发行版绝对基于 Mariner 发行版。为每个尝试运行 GUI 应用程序的 WSL2 发行版创建一个 WSLg 系统发行版。

    在这种情况下,真正由微软来决定如何推出必要的服务。如果您愿意,您可以创建自己的系统发行版,并且 Microsoft 提供了一个参考实现作为开始,但可能很少需要 Systemd 的功能。


这并不是说在 WSL(1 或 2)中运行进程管理程序没有用——在某些情况下是有用的。但就我个人而言,我很高兴 WSL 将其留给用户。这使得它在默认情况下像容器一样运行(快速启动,高效的资源使用),但在其他情况下更像(但不完全)成熟的“虚拟操作系统”。


主要问题是:

现在,出于好奇,我想知道 WSL 依赖于哪个进程管理而不是 Systemd。

让我们将其分解为上面提到的 Systemd 处理的函数:

  • PID1/Init 系统:如上所述,WSL 的专有/init系统用于这两个功能。/init需要这个特殊功能,因为它处理 Linux 和 Windows 之间的深度互操作集成。传统的 Linux init 系统(例如 Systemd)不知道如何处理这个问题。

    理论上,WSL2 可以使用 Systemd 来启动并设置一些特殊服务来处理集成,但是:

    • 这会增加非常精简的启动的开销

    • 有些发行版不使用 Systemd,因此他们必须以不同的方式配置每个发行版(如果需要,最好将其留给用户)。

    • 无论如何,可能/init仍然需要 PID1,以便即使在启动后也能继续处理某些互操作功能。

      由于 Systemd要求它是 PID1,这会产生一些冲突。我确实认为微软团队正在研究这个问题,但这显然还没有得到解决。

  • 进程主管/经理:WSL2 默认情况下确实没有。然而,正如 @user1686 在另一个答案中指出的那样,直到最近这才成为问题。 为每个服务创建了脚本service,其中包含用于启动/停止/重新启动/状态的命令(或类似命令)的入口点。

    至少 Ubuntu 仍然提供许多这样的服务脚本。sshd因此,例如,当您想要启动时,您可以只运行sudo service ssh start,这又会调用其脚本。如果您安装 Maridb ( sudo service mysql start),则相同。

    但是,某些服务提供 SysVInit 样式脚本。他们可能只提供 Systemd 单元,至少在基于 Systemd 的发行版上是这样。这些在 WSL 发行版上无法(轻松)工作。请参阅这个答案,其中我介绍了发生这种情况时的替代方案。

  • 启动时运行服务

    在 Windows 10 下,仍然没有很好的方法来处理这个问题。当然,WSL 发行版并不真正“启动”,但它确实有一个定义的“首次启动”,您可能希望在其中运行某些内容。

    在 Windows 10 下,最好的办法是手动启动服务或通过用户启动文件运行它们(例如~/.bashrc)。有关于此的一些想法,请参阅此答案。

    但听起来您使用的是 Windows 11(因为您提到了 WSLg),在这种情况下,有一项功能允许您指定在分发启动时运行一次的命令(或一系列命令)。再次,请参阅此答案以获取有关如何配置它的信息。

在启动时运行进程管理器

使用这些技术,完全可以运行您想要的任何进程管理程序,只要它不要求它是 PID1。

到目前为止我在 WSL 上尝试过的一些:

  • Supervisord设计用于在容器中运行服务。
  • dinit —— 适用于Artix,这是一个基于 Arch 的发行版,它有 5 个不同的 init/进程管理器选项可供您使用。
  • s6,也可与 Artix 一起使用。这个在 WSL2 下有一些问题,我认为它们是在 WSL2 一侧,但我不能确定。

s6 和dinit 都倾向于认为它们是在物理/虚拟机上运行(自然地),因此它们尝试执行一些在WSL 下不需要的启动。我已经能够删除不必要的项目,然后dinit 至少运行得很好。不过,我还没有将这些内容整合成一套可供其他人复制的说明。

运行 Systemd

甚至可以通过伪造 Systemd 来运行 Systemd,以便它在 WSL2(但不是 WSL1)发行版内的新命名空间内以 PID1 身份运行(正如我们所讨论的,它已经在自己的命名空间中运行)。我个人不一定推荐它,但很多人都这样做。我在AU 答案的最后部分介绍了其中的一些内容,所以我不会在这里重复。

  • 有一种非常常见的容器类型确实运行完整的 init(通常是 systemd)——使用 LXC、nspawn 或 OpenVZ 管理的“系统容器”。太多人认为 Docker 发明了容器…… (3认同)
  • 很好的答案,我认为唯一可以用来澄清问题的是 systemd 不是 Linux 的一部分。它是一个为在 Linux 发行版中运行而构建的便利实用程序。 (3认同)

use*_*686 27

Systemd 实际上是一个相当新的项目,于 2010 年开始启动。之前已经使用过许多其他工具:sysvinit、upstart、init-ng、s6、launchd(我认为它曾经有过 Linux 版本)。由于各种原因,一些 Linux 发行版仍然不使用 systemd。

\n

在所有这些中,systemd 是最接近的,甚至可以称为“进程管理器”。Linux 实际上根本不依赖进程管理器;任何进程都可以在决定时直接创建(分叉)一个新的子进程,不受控制。(确实如此不受控制,以至于当 systemd 开始编写诸如“注销应该杀死您剩余的进程”之类的内容时,就引发了战争。)

\n

systemd 和其他此类程序的真正主要工作只是作为服务管理器:自动启动某些特定进程,例如负责显示登录屏幕的守护进程(GDM、agetty)和 \xe2\x80\x93 有时 \xe2 \x80\x93 在崩溃时重新启动它们。但是一旦进入登录屏幕,其他一切都可以在没有 systemd/init 参与的情况下发生。

\n

事实上,对于 sysvinit,实际的 init 进程几乎没有做任何事情:它监督的唯一服务是 Agetty。从字面上看,其他所有事情都是通过普通的 shell 脚本完成的,从未真正接触过 init。启动服务的命令?外壳脚本。整个初始启动过程运行更多 shell 脚本的 Shell 脚本。

\n

因此,对于像 WSL 这样的东西,它不想表现得像一个完整的系统(它不应该像一个完整的虚拟机,你必须在使用之前启动;启动 WSL 意味着是即时的,就好像你真的在运行 Linux 应用程序一样)在 Windows 上),init 进程可以相当小。我真的不知道 WSL2 使用什么,但它可以完全自定义。

\n

(对于 WSL1,甚至可能没有init进程,因为 WSL1 甚至不是 VM,而只是仍然直接在 Windows 上运行的特殊进程的集合。)

\n

  • “Systemd 实际上是一个相当新的项目”——当人们问“X 如何在没有 Y 的情况下工作”时,我总是感到惊讶,因为 Y 是相当新的,而且显然 X 在此之前已经在没有 Y 的情况下工作了几十年。最极端的例子是,人们似乎认为在火星上航行是不可能的,因为火星没有 GPS,而在 GPS 发明之前,人们已经航行了数十万年。 (17认同)
  • @JörgWMittag:我认为这对于在新系统已经到位的情况下长大的人来说是完全正常的。询问的是他们如何_发现_Y是新的并且“显然”X在它之前工作过,这与仅仅得出结论这是不可能的完全不同。 (7认同)
  • @Celesteaka.73chn0 遗憾的是,你们这一代人在成长过程中会隐含地了解到 systemd 是“最好的”甚至是“一种好的”做事方式,因为我们当中有些人(争议警报!)相信它是与 Unix 所代表的一切恰恰相反。但围绕它的争论已经基本平息,如果我有一点机智或礼貌,我根本不会发布这个可能具有煽动性的评论。 (7认同)
  • @SteveSummit 有些人会说老一代拒绝它是一种耻辱,因为它显然更优越。科学的进步与其说是由于新发现的出现,不如说是由于旧范式的虔诚追随者的死亡。 (2认同)

Dan*_*l B 14

WSL 2 有一个非开源的自定义初始化系统(至少我还没有\xe2\x80\x99t 找到源代码)。您可以使用类似ps或的工具查看其流程htop.

\n

它是一个多调用二进制文件 that does at least the following:

\n
    \n
  • 运行 9p 服务器进行文件访问
  • \n
  • 在 WSL 2 分发容器内启动 shell
  • \n
  • 管理 WSL 2 分发容器
  • \n
  • 运行其他互操作内容
  • \n
\n

您无法看到所有这些进程/守护进程,因为有些进程/守护进程在所有 WSL 2 容器之外(在根命名空间中)运行。

\n

发行版中可能存在或不存在的任何初始化系统都不会被使用。相反,shell 是使用配置的用户 ID 直接生成的。

\n

  • @pabouk-Ukrainestaystrong 不,抱歉。我不知道有任何“漏洞”可以访问根命名空间。我确信这是可能的,例如通过逆向工程主机的“wsl”命令如何与虚拟机通信(可能通过 Hyper-V 套接字)。 (3认同)