systemd——是的,全部小写,即使在句首——是 init 和 SystemV init 脚本的现代替代品。它也远不止于此。
和大多数系统管理员一样,当我想到 init 程序和 SystemV 时,我想到的是 Linux 启动和关机,而不是其他太多,比如管理服务一旦它们启动并运行。与 init 类似,systemd 是所有进程之母,它负责将 Linux 主机启动到一个可以进行高效工作的状态。systemd 承担了一些功能,它比旧的 init 程序广泛得多,旨在管理运行中的 Linux 主机的许多方面,包括挂载文件系统、管理硬件、处理定时器以及启动和管理使 Linux 主机高效运行所需的服务。
本系列文章部分基于我的三卷 Linux 培训课程《使用和管理 Linux:从零到系统管理员》的摘录,探讨了 systemd 在启动时以及启动完成后开始的功能。
Linux 启动
将 Linux 主机从关闭状态变为运行状态的完整过程非常复杂,但它是开放且可知的。在深入细节之前,我将快速概述从主机硬件开启到系统准备好供用户登录的过程。大多数时候,“启动过程”被作为一个单一的实体来讨论,但这并不准确。实际上,完整的启动和启动过程分为三个主要部分
- 硬件启动: 初始化系统硬件
- Linux 启动: 加载 Linux 内核,然后加载 systemd
- Linux 启动: systemd 在其中准备主机以进行高效工作
Linux 启动序列在内核加载 init 或 systemd 之后开始,具体取决于发行版使用的是旧的还是新的启动方式。init 和 systemd 程序启动和管理所有其他进程,并且在各自的系统中都被称为“所有进程之母”。
重要的是将硬件启动与 Linux 启动和 Linux 启动分开,并明确定义它们之间的分界点。了解这些差异以及每个部分在使 Linux 系统达到可以高效工作的状态中所起的作用,可以管理这些过程,并更好地确定在大多数人所说的“启动”期间出现问题的位置。
启动过程遵循三步启动过程,并将 Linux 计算机启动到可用于高效工作的操作状态。当内核将主机的控制权移交给 systemd 时,启动过程开始。
systemd 争议
systemd 可能会引起系统管理员和其他负责保持 Linux 系统运行的人员的广泛反应。systemd 在许多 Linux 系统中接管了如此多的任务,这一事实在某些开发人员和系统管理员群体中引发了抵制和不和谐。
SystemV 和 systemd 是执行 Linux 启动序列的两种不同方法。SystemV 启动脚本和 init 程序是旧方法,而使用目标的 systemd 是新方法。尽管大多数现代 Linux 发行版使用较新的 systemd 进行启动、关机和进程管理,但仍有一些发行版不这样做。原因之一是一些发行版维护者和一些系统管理员更喜欢旧的 SystemV 方法而不是较新的 systemd。
我认为两者都有优点。
为什么我更喜欢 SystemV
我更喜欢 SystemV,因为它更开放。启动是通过 Bash 脚本完成的。在内核启动 init 程序(这是一个编译后的二进制文件)后,init 启动 rc.sysinit 脚本,该脚本执行许多系统初始化任务。在 rc.sysinit 完成后,init 启动 /etc/rc.d/rc 脚本,该脚本反过来启动 /etc/rc.d/rcX.d 中 SystemV 启动脚本定义的各种服务,其中“X”是启动的运行级别的编号。
除了 init 程序本身,所有这些程序都是开放且易于理解的脚本。可以通读这些脚本,确切地了解整个启动过程中发生了什么,但我认为没有多少系统管理员真正这样做。每个启动脚本都编号,以便它按特定顺序启动其预期的服务。服务是串行启动的,一次只启动一个服务。
systemd 由 Red Hat 的 Lennart Poettering 和 Kay Sievers 开发,是一个由大型编译二进制可执行文件组成的复杂系统,如果不访问源代码,就无法理解。它是开源的,所以“访问源代码”并不难,只是不太方便。systemd 似乎代表了对 Linux 哲学多项原则的重大反驳。作为二进制文件,systemd 不直接对系统管理员开放以供查看或进行轻松更改。systemd 试图做所有事情,例如管理正在运行的服务,同时提供比 SystemV 明显更多的状态信息。它还管理硬件、进程和进程组、文件系统挂载等等。systemd 几乎存在于现代 Linux 主机的方方面面,使其成为系统管理的一站式工具。所有这些都明显违反了程序应该小而每个程序应该做好一件事的原则。
为什么我更喜欢 systemd
我更喜欢 systemd 作为我的启动机制,因为它根据启动过程的当前阶段并行启动尽可能多的服务。这加快了整体启动速度,并使主机系统比 SystemV 更快地进入登录屏幕。
systemd 管理着运行中的 Linux 系统的几乎每个方面。它可以管理正在运行的服务,同时提供比 SystemV 明显更多的状态信息。它还管理硬件、进程和进程组、文件系统挂载等等。systemd 几乎存在于现代 Linux 操作系统的方方面面,使其成为系统管理的一站式工具。(这听起来熟悉吗?)
systemd 工具是编译后的二进制文件,但该工具套件是开放的,因为所有配置文件都是 ASCII 文本文件。可以通过各种 GUI 和命令行工具修改启动配置,以及添加或修改各种配置文件以满足特定本地计算环境的需求。
真正的问题
您是否认为我可能不喜欢这两种启动系统?我喜欢,我可以与任何一种系统一起工作。
在我看来,SystemV 和 systemd 之间的大部分争议的真正问题和根本原因是,在系统管理员级别没有选择。是否使用 SystemV 或 systemd 的选择已经由各种发行版的开发人员、维护人员和打包人员做出——但这是有充分理由的。由于 init 系统的极端侵入性,将其移除和替换会产生许多后果,这些后果很难在发行版设计过程之外解决。
尽管这个选择是为我做的,但我的 Linux 主机仍然启动并工作,这通常是我最关心的。作为最终用户,甚至作为系统管理员,我主要关心的是我是否可以完成我的工作,例如写书和这篇文章,安装更新,以及编写脚本来自动化一切。只要我可以完成我的工作,我就不太关心我的发行版上使用的启动顺序。
当启动或服务管理过程中出现问题时,我确实关心。无论主机上使用哪种启动系统,我都足够了解事件的顺序,以找到故障并修复它。
替换 SystemV
以前曾尝试用更现代的东西替换 SystemV。大约两个版本,Fedora 使用名为 Upstart 的东西来替换老化的 SystemV,但它没有替换 init,也没有提供我注意到的任何更改。由于 Upstart 没有对 SystemV 周围的问题提供任何重大更改,因此朝着这个方向的努力很快被放弃,转而支持 systemd。
尽管大多数 Linux 开发人员都同意替换旧的 SystemV 启动是一个好主意,但许多开发人员和系统管理员因此不喜欢 systemd。与其重新讨论人们对 systemd 已经或曾经拥有的所有所谓的担忧,我将向您推荐两篇好的文章(如果有点旧),它们应该涵盖所有内容。Linux 内核的创建者 Linus Torvalds 似乎不感兴趣。在 2014 年 ZDNet 的文章《Linus Torvalds 和其他关于 Linux systemd 的人》中,Linus 清楚地表达了他的感受。
“实际上,我对 systemd 本身没有任何特别强烈的意见。我对一些核心开发人员有问题,我认为他们在错误和兼容性方面过于掉以轻心,而且我认为一些设计细节很疯狂(例如,我不喜欢二进制日志),但这些都是细节,而不是大问题。”
如果您不太了解 Linus,我可以告诉您,如果他不喜欢某件事,他会非常直言不讳、明确且非常清楚地表达他的不喜欢。他在表达对事物的厌恶方式上变得更具有社会接受度。
2013 年,Poettering 发表了一篇长篇博客文章,其中他揭穿了关于 systemd 的神话,同时深入了解了创建 systemd 的一些原因。这是一篇非常值得一读的文章,我强烈推荐它。
systemd 任务
根据编译过程中使用的选项(本系列文章中未考虑),systemd 可以有多达 69 个二进制可执行文件来执行以下任务,以及其他任务
- systemd 程序作为 PID 1 运行,并提供系统启动,尽可能并行启动尽可能多的服务,这作为副作用,加快了整体启动时间。它还管理关机序列。
- systemctl 程序为服务管理提供用户界面。
- 为向后兼容性提供对 SystemV 和 LSB 启动脚本的支持。
- 服务管理和报告提供比 SystemV 更多的服务状态数据。
- 它包括用于基本系统配置的工具,例如主机名、日期、区域设置、已登录用户列表、正在运行的容器和虚拟机、系统帐户、运行时目录和设置、用于管理简单网络配置的守护程序、网络时间同步、日志转发和名称解析。
- 它提供套接字管理。
- systemd 定时器提供高级的类似 cron 的功能,包括在相对于系统启动、systemd 启动、上次定时器启动时间等的时间运行脚本。
- 它提供了一个工具来分析定时器规范中使用的日期和时间。
- 具有层次结构意识的文件系统挂载和卸载允许更安全地级联挂载的文件系统。
- 它能够积极创建和管理临时文件,包括删除。
- D-Bus 的接口提供了在插入或移除设备时运行脚本的能力。这允许将所有设备(无论是否可插拔)都视为即插即用,这大大简化了设备处理。
- 其分析启动序列的工具可用于定位花费时间最多的服务。
- 它包括用于存储系统日志消息的日志和用于管理日志的工具。
架构
许多守护程序、控制程序和配置文件支持这些任务以及更多任务。图 1 显示了属于 systemd 的许多组件。这是一个简化的图表,旨在提供高级概述,因此它不包括所有单独的程序或文件。它也没有提供对数据流的任何深入了解,数据流非常复杂,在本系列文章的上下文中,这将是无用的练习。

图 1:systemd 的架构,由 Shmuel Csaba Otto Traian (CC BY-SA 3.0) 绘制
图 1:systemd 的架构,由 Shmuel Csaba Otto Traian (CC BY-SA 3.0) 绘制
systemd 的全面阐述本身就需要一本书。您无需了解图 1 中 systemd 组件如何组合在一起的细节;了解启用管理各种 Linux 服务以及处理日志文件和日志的程序和组件就足够了。但很明显,systemd 并非一些批评者所声称的那样是一个庞大、单一且不可知的庞然大物。
systemd 作为 PID 1
systemd 是 PID 1。它的一些功能(远比旧的 SystemV3 init 程序广泛)是管理运行中的 Linux 主机的许多方面,包括挂载文件系统以及启动和管理使 Linux 主机高效运行所需的服务。systemd 的任何与启动序列无关的任务都不在本文章的范围之内(但其中一些将在本系列文章的后面探讨)。
首先,systemd 挂载 /etc/fstab 定义的文件系统,包括任何交换文件或分区。此时,它可以访问位于 /etc 中的配置文件,包括它自己的配置文件。它使用其配置链接 /etc/systemd/system/default.target 来确定应将主机启动到哪种状态或目标。default.target 文件是指向真实目标文件的符号链接。对于桌面工作站,这通常是 graphical.target,它等同于 SystemV 中的运行级别 5。对于服务器,默认更可能是 multi-user.target,它类似于 SystemV 中的运行级别 3。emergency.target 类似于单用户模式。目标和服务是 systemd 单元。
下表(图 2)将 systemd 目标与旧的 SystemV 启动运行级别进行了比较。systemd 提供 systemd 目标别名以实现向后兼容性。目标别名允许脚本——以及许多系统管理员——使用 SystemV 命令(如 init 3)来更改运行级别。当然,SystemV 命令被转发到 systemd 进行解释和执行。
systemd 目标 | SystemV 运行级别 | 目标别名 | 描述 |
default.target | 此目标始终通过符号链接别名为 multi-user.target 或 graphical.target。systemd 始终使用 default.target 启动系统。default.target 永远不应别名为 halt.target、poweroff.target 或 reboot.target。 | ||
graphical.target | 5 | runlevel5.target | 具有 GUI 的 Multi-user.target |
4 | runlevel4.target | 未使用。在 SystemV 世界中,运行级别 4 与运行级别 3 相同。可以创建和自定义此目标以启动本地服务,而无需更改默认的 multi-user.target。 | |
multi-user.target | 3 | runlevel3.target | 所有服务都在运行,但仅限命令行界面 (CLI) |
2 | runlevel2.target | 多用户,没有 NFS,但所有其他非 GUI 服务都在运行 | |
rescue.target | 1 | runlevel1.target | 基本系统,包括挂载文件系统,仅运行最基本的服务,并在主控制台上提供救援 shell |
emergency.target | S | 单用户模式——没有服务在运行;文件系统未挂载。这是最基本的操作级别,只有紧急 shell 在主控制台上运行,供用户与系统交互。 | |
halt.target | 停止系统,但不关闭电源 | ||
reboot.target | 6 | runlevel6.target | 重启 |
poweroff.target | 0 | runlevel0.target | 停止系统并关闭电源 |
图 2:SystemV 运行级别与 systemd 目标和一些目标别名的比较
每个目标在其配置文件中都有一组依赖项。systemd 启动所需的依赖项,这些依赖项是在特定功能级别运行 Linux 主机所需的服务。当目标配置文件中列出的所有依赖项都已加载并运行时,系统在该目标级别运行。在图 2 中,功能最多的目标位于表格顶部,功能向表格底部递减。
systemd 还查看旧的 SystemV init 目录,以查看那里是否存在任何启动文件。如果存在,systemd 会将它们用作配置文件来启动文件描述的服务。已弃用的网络服务是一个很好的例子,它仍然在 Fedora 中使用 SystemV 启动文件。
图 3(下方)直接从 bootup 手册页复制而来。它显示了 systemd 启动期间事件的一般顺序图,以及确保成功启动的基本排序要求。
cryptsetup-pre.target
|
(various low-level v
API VFS mounts: (various cryptsetup devices...)
mqueue, configfs, | |
debugfs, ...) v |
| cryptsetup.target |
| (various swap | | remote-fs-pre.target
| devices...) | | | |
| | | | | v
| v local-fs-pre.target | | | (network file systems)
| swap.target | | v v |
| | v | remote-cryptsetup.target |
| | (various low-level (various mounts and | | |
| | services: udevd, fsck services...) | | remote-fs.target
| | tmpfiles, random | | | /
| | seed, sysctl, ...) v | | /
| | | local-fs.target | | /
| | | | | | /
\____|______|_______________ ______|___________/ | /
\ / | /
v | /
sysinit.target | /
| | /
______________________/|\_____________________ | /
/ | | | \ | /
| | | | | | /
v v | v | | /
(various (various | (various | |/
timers...) paths...) | sockets...) | |
| | | | | |
v v | v | |
timers.target paths.target | sockets.target | |
| | | | v |
v \_______ | _____/ rescue.service |
\|/ | |
v v |
basic.target rescue.target |
| |
________v____________________ |
/ | \ |
| | | |
v v v |
display- (various system (various system |
manager.service services services) |
| required for | |
| graphical UIs) v v
| | multi-user.target
emergency.service | | |
| \_____________ | _____________/
v \|/
emergency.target v
graphical.target
图 3:systemd 启动图
sysinit.target 和 basic.target 目标可以被认为是启动过程中的检查点。尽管 systemd 的设计目标之一是并行启动系统服务,但在其他服务和目标可以启动之前,必须先启动某些服务和功能目标。在满足该检查点所需的所有服务和目标之前,无法通过这些检查点。
当其依赖的所有单元都完成时,将达到 sysinit.target。所有这些单元(挂载文件系统、设置交换文件、启动 udev、设置随机生成器种子、启动低级服务和设置加密服务(如果一个或多个文件系统已加密))都必须完成,但在 sysinit.target 中,这些任务可以并行执行。
sysinit.target 启动系统勉强运行所需的所有低级服务和单元,并且这些服务和单元是启用移动到 basic.target 所必需的。
在满足 sysinit.target 后,systemd 然后启动满足下一个目标所需的所有单元。基本目标通过启动所有后续目标所需的单元来提供一些额外的功能。这些包括设置各种可执行目录的路径、通信套接字和定时器等。
最后,可以初始化用户级目标 multi-user.target 或 graphical.target。必须先达到 multi-user.target,然后才能满足图形目标依赖项。图 3 中带下划线的目标是常用的启动目标。当达到这些目标之一时,启动已完成。如果 multi-user.target 是默认值,那么您应该在控制台上看到文本模式登录。如果 graphical.target 是默认值,那么您应该看到图形登录;您看到的特定 GUI 登录屏幕取决于您的默认显示管理器。
bootup 手册页还描述并提供了启动到初始 RAM 磁盘和 systemd 关机过程的图。
systemd 还提供了一个工具,用于列出完整启动或指定单元的依赖项。单元是一个可控制的 systemd 资源实体,范围从特定服务(例如 httpd 或 sshd)到定时器、挂载、套接字等等。尝试以下命令并滚动浏览结果。
systemctl list-dependencies graphical.target
请注意,这完全展开了将系统启动到图形目标运行模式所需的顶级目标单元列表。使用 --all 选项也可展开所有其他单元。
systemctl list-dependencies --all graphical.target
您可以使用 less 命令的搜索工具搜索诸如“target”、“slice”和“socket”之类的字符串。
所以现在,尝试以下操作。
systemctl list-dependencies multi-user.target
和
systemctl list-dependencies rescue.target
和
systemctl list-dependencies local-fs.target
和
systemctl list-dependencies dbus.service
此工具可帮助我可视化我正在使用的主机的启动依赖项的具体情况。继续花一些时间探索一个或多个 Linux 主机的启动树。但请注意,因为 systemctl 手册页包含以下注释
“请注意,此命令仅列出服务管理器当前加载到内存中的单元。特别是,此命令不适合获取特定单元上所有反向依赖项的完整列表,因为它不会列出当前未加载的单元声明的依赖项。”
最后的想法
即使在深入了解 systemd 之前,也很明显它既强大又复杂。同样明显的是,systemd 不是一个单一、庞大、单一且不可知的二进制文件。相反,它由许多较小的组件和子命令组成,这些组件和子命令旨在执行特定任务。
本系列文章的下一篇文章将更详细地探讨 systemd 启动,以及 systemd 配置文件、更改默认目标以及如何创建简单的服务单元。
资源
互联网上有大量关于 systemd 的信息,但其中许多信息都很简洁、晦涩甚至具有误导性。除了本文中提到的资源外,以下网页还提供了关于 systemd 启动的更详细和可靠的信息。
- Fedora 项目有一个很好的、实用的 指南 到 systemd。它几乎包含了您需要了解的所有内容,以便使用 systemd 配置、管理和维护 Fedora 计算机。
- Fedora 项目还有一个很好的 速查表,它将旧的 SystemV 命令与可比较的 systemd 命令进行了交叉引用。
- 有关 systemd 的详细技术信息以及创建 systemd 的原因,请查看 Freedesktop.org 的 systemd 描述。
- Linux.com 的 “更多 systemd 乐趣” 提供了更高级的 systemd 信息和技巧。
Lennart Poettering(systemd 的设计师和主要开发人员)还为 Linux 系统管理员撰写了一系列深入的技术文章。这些文章写于 2010 年 4 月至 2011 年 9 月之间,但它们现在与当时一样具有相关性。其他所有关于 systemd 及其生态系统的优秀文章都基于这些论文。
21 条评论