systemd——是的,全部小写,即使在句子的开头——是 init 和 SystemV init 脚本的现代替代品。 它也远不止于此。
像大多数系统管理员一样,当我想到 init 程序和 SystemV 时,我想到的只是 Linux 启动和关闭,以及其他方面的内容,例如服务启动和运行后的管理。 像 init 一样,systemd 是所有进程之母,它负责将 Linux 主机启动到可以进行高效工作的状态。 systemd承担的一些功能,比旧的 init 程序广泛得多,包括管理运行 Linux 主机的许多方面,包括挂载文件系统、管理硬件、处理计时器以及启动和管理拥有一个高效 Linux 主机所需的服务。
本系列文章基于我三卷 Linux 培训课程使用和管理 Linux:从零到系统管理员的部分摘录,探讨了 systemd 在启动时以及启动完成后开始的各种功能。
Linux 启动
将 Linux 主机从关闭状态转变为运行状态的完整过程非常复杂,但它是开放且可知的。 在深入了解细节之前,我将从主机硬件开启到系统准备好让用户登录的过程进行简要概述。 大多数情况下,“启动过程”被作为一个单独的实体进行讨论,但这并不准确。 事实上,完整的启动和启动过程有三个主要部分
- 硬件启动: 初始化系统硬件
- Linux 启动: 加载 Linux 内核,然后加载 systemd
- Linux 启动: systemd 在这里为高效工作准备主机
在内核加载 init 或 systemd 之后,Linux 启动序列开始,具体取决于发行版是使用旧启动还是新启动。 init 和 systemd 程序启动和管理所有其他进程,并且在各自的系统中都被称为“所有进程之母”。
将硬件启动与 Linux 启动以及 Linux 启动分开,并明确定义它们之间的分界点非常重要。 了解这些差异以及每个部分在将 Linux 系统置于可以高效工作的状态中所起的作用,可以管理这些过程,并更好地确定在大多数人所说的“启动”期间出现问题的位置。
启动过程遵循三步启动过程,并将 Linux 计算机启动到可以用于高效工作的可操作状态。 当内核将主机控制权转移到 systemd 时,启动过程开始。
systemd 争议
systemd 可能会引起系统管理员和其他负责保持 Linux 系统启动和运行的人员的各种反应。 systemd 正在许多 Linux 系统中接管如此多的任务,这一事实引起了某些开发人员和系统管理员的反击和不和谐。
SystemV 和 systemd 是执行 Linux 启动序列的两种不同方法。 SystemV 启动脚本和 init 程序是旧方法,而 systemd 使用 targets 是新方法。 尽管大多数现代 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 并非某些批评者所声称的那样是一个庞大而单一的怪物。
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 直接从启动手册页复制而来。它显示了 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 的详细技术信息以及创建原因,请查看 Freedesktop.org 的 systemd 描述。
- Linux.com 的“更多 systemd 乐趣”提供了更高级的 systemd 信息和技巧。
此外,Lennart Poettering(systemd 的设计师和主要开发者)还为 Linux 系统管理员撰写了一系列深入的技术文章。 这些文章写于 2010 年 4 月至 2011 年 9 月期间,但它们现在仍然像当时一样具有现实意义。 关于 systemd 及其生态系统的大部分优秀文章都基于这些论文。
21 条评论