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 程序是旧方法,而使用 targets 的 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(如下所示)直接从启动手册页复制而来。 它显示了 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 登录屏幕取决于您的默认显示管理器。
启动手册页还描述并提供了启动到初始 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 条评论