systemd——是的,全部小写,即使在句首——是 init 和 SystemV init 脚本的现代替代品。它也远不止于此。
像大多数系统管理员一样,当我想到 init 程序和 SystemV 时,我想到的是 Linux 启动和关机,而不是其他,比如管理服务一旦它们启动并运行。像 init 一样,systemd 是所有进程之母,它负责将 Linux 主机启动到一个可以进行高效工作的状态。systemd 承担的一些功能,远比旧的 init 程序广泛得多,包括管理正在运行的 Linux 主机的许多方面,包括挂载文件系统、管理硬件、处理计时器,以及启动和管理使 Linux 主机高效运行所需的服务。
本系列文章部分基于我的三卷 Linux 培训课程《使用和管理 Linux:从零到系统管理员》的摘录,探讨了 systemd 在启动时以及启动完成后开始的功能。
Linux 启动
The 将 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 可以有多达 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 并不是一些批评者声称的那样是庞然大物。
作为 PID 1 的 systemd
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,然后才能满足 graphical 目标的依赖项。图 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 的详细技术信息以及创建它的原因,请查看 Freedesktop.org 的 systemd 描述。
- Linux.com 的“更多 systemd 乐趣”提供了更高级的 systemd 信息和技巧。
Lennart Poettering(systemd 的设计者和主要开发者)还为 Linux 系统管理员撰写了一系列深入的技术文章。这些文章写于 2010 年 4 月至 2011 年 9 月之间,但它们现在仍然像当时一样具有现实意义。关于 systemd 及其生态系统的大部分其他优秀文章都基于这些论文。
21 条评论