systemd
From the project web page
- systemd 是 Linux 系统的基本构建模块套件。它提供了一个作为 PID 1 运行并启动系统其余部分的系统和服务管理器。 systemd 提供了强大的并行化能力,使用套接字和 D-Bus 激活来启动服务,提供按需启动守护程序,使用 Linux 控制组 跟踪进程,维护挂载和自动挂载点,并实现了一个精细的基于事务的依赖关系的服务控制逻辑。 systemd 支持 SysV 和 LSB init 脚本,并可以替代 sysvinit。其他部分包括日志守护程序、控制基本系统配置(如主机名、日期、区域设置)的实用程序、维护已登录用户和正在运行的容器和虚拟机列表、系统帐户、运行时目录和设置,以及管理简单网络配置、网络时间同步、日志转发和名称解析的守护程序。
从历史上看,systemd 称之为“服务”的东西曾被命名为守护进程:任何作为“后台”进程运行的程序(没有终端或用户界面),通常等待事件发生并提供服务。一个很好的例子是 Web 服务器,它等待请求以交付页面,或者 ssh 服务器,它等待有人尝试登录。虽然这些都是功能齐全的应用程序,但有些守护进程的工作并不那么明显。守护进程用于诸如将消息写入日志文件(例如 syslog
、metalog
)或保持系统时间准确(例如 ntpd)之类的任务。有关更多信息,请参见 daemon(7)。
Basic systemctl usage
用于内省和控制 systemd 的主要命令是 systemctl。它的一些用途是检查系统状态以及管理系统和服务。有关更多详细信息,请参见 systemctl(1)。
- 您可以将以下所有 systemctl 命令与
-H user@host
开关一起使用,以控制远程计算机上的 systemd 实例。这将使用 SSH 连接到远程 systemd 实例。 - Plasma 用户可以安装 systemdgenie 作为 systemctl 的图形前端。安装后,该模块将添加到系统下。
Using units
单元通常包括但不限于服务 (.service)、挂载点 (.mount)、设备 (.device) 和套接字 (.socket)。
使用 systemctl 时,通常必须指定单元文件的完整名称,包括其后缀,例如 sshd.socket
。但是,在以下 systemctl 命令中指定单元时,有一些简短的形式
- 如果您未指定后缀,systemctl 将假定为 .service。例如,
netctl
和netctl.service
是等效的。 - 挂载点将自动转换为适当的 .mount 单元。例如,指定
/home
等效于home.mount
。 - 与挂载点类似,设备会自动转换为适当的 .device 单元,因此指定
/dev/sda2
等效于dev-sda2.device
。
有关详细信息,请参见 systemd.unit(5)。
@
符号(例如 name@string.service
):这意味着它们是 template 单元的实例,其实际文件名不包含 string
部分(例如 name@.service
)。string
称为实例标识符,类似于传递给模板单元的参数,当使用 systemctl 命令调用时:在单元文件中,它将替换 %i
说明符。更准确地说,在尝试实例化 name@.suffix
模板单元之前,systemd 实际上会查找具有完全 name@string.suffix
文件名的单元,尽管按照惯例,这种“冲突”很少发生,即大多数包含 @
符号的单元文件都旨在作为模板。此外,如果调用模板单元时没有实例标识符,则通常会失败(某些 systemctl 命令除外,例如 cat
)。下表中的命令对系统单元进行操作,因为 --system
是 systemctl 的隐式默认设置。要改为对用户单元(对于调用用户)进行操作,请使用 systemctl --user,无需 root 权限。另请参见 systemd/User#基本设置 以启用/禁用所有用户的用户单元。
- 如果指定了多个单元,则大多数命令也有效,有关更多信息,请参见 systemctl(1)。
--now
开关可以与enable
、disable
和mask
结合使用,以分别立即启动、停止或屏蔽单元,而不是在重新启动后执行。- 软件包可能会为不同的目的提供单元。如果您刚刚安装了一个软件包,则可以使用
pacman -Qql package | grep -Fe .service -e .socket
来检查和查找它们。 - 在可用时,启用
unit.socket
而不是unit.service
可能是有益的,因为套接字会在必要时启动服务。有关更多详细信息,请参见 #套接字激活。
操作 | 命令 | 注意 |
---|---|---|
分析系统状态 | ||
显示系统状态 | systemctl status |
|
列出正在运行的单元 | systemctl 或systemctl list-units |
|
列出失败的单元 | systemctl --failed |
|
列出已安装的单元文件1 | systemctl list-unit-files |
|
显示 PID 的进程状态 | systemctl status pid |
cgroup 切片、内存和父进程 |
检查单元状态 | ||
显示与单元关联的手册页 | systemctl help unit |
单元支持的 |
单元的状态 | systemctl status unit |
包括它是否正在运行 |
检查单元是否已启用 | systemctl is-enabled unit |
|
启动、重启、重新加载单元 | ||
立即启动单元 | systemctl start unit 以 root 身份 |
|
立即停止单元 | systemctl stop unit 以 root 身份 |
|
重启单元 | systemctl restart unit 以 root 身份 |
|
重新加载单元及其配置 | systemctl reload unit 以 root 身份 |
|
重新加载 systemd 管理器配置2 | systemctl daemon-reload 以 root 身份 |
扫描新的或更改的单元 |
启用单元 | ||
启用单元以在启动时自动启动 | systemctl enable unit 以 root 身份 |
|
启用单元以在启动时自动启动并立即启动它 | systemctl enable --now unit 以 root 身份 |
|
禁用单元以不再在启动时启动 | systemctl disable unit 以 root 身份 |
|
重新启用单元3 | systemctl reenable unit 以 root 身份 |
即禁用并重新启用 |
屏蔽单元 | ||
屏蔽单元使其无法启动4 | systemctl mask unit 以 root 身份 |
|
取消屏蔽单元 | systemctl unmask unit 以 root 身份 |
- 有关可用单元文件可以在哪些目录中找到的信息,请参见 systemd.unit(5) § UNIT FILE LOAD PATH。
- 这不会要求更改的单元重新加载自己的配置(请参见重新加载操作)。
- 例如,如果它的
[Install]
部分自上次启用以来已更改。 - 手动和作为依赖项,这使得屏蔽很危险。使用以下命令检查现有屏蔽单元
$ systemctl list-unit-files --state=masked
电源管理
polkit 对于作为非特权用户的电源管理是必需的。如果您在本地 systemd-logind 用户会话中,并且没有其他会话处于活动状态,则以下命令将在没有 root 权限的情况下工作。如果不是(例如,因为另一个用户已登录到 tty),systemd 将自动要求您输入 root 密码。
操作 | 命令 |
---|---|
关闭并重启系统 | systemctl reboot
|
关闭并断电系统 | systemctl poweroff
|
暂停系统 | systemctl suspend
|
使系统进入休眠状态(将 RAM 写入磁盘) | systemctl hibernate
|
使系统进入混合睡眠状态(也称为 suspend-to-both,它将 RAM 保存到磁盘,然后暂停) | systemctl hybrid-sleep
|
首先暂停系统,然后在配置的时间后唤醒,以便仅休眠系统 | systemctl suspend-then-hibernate
|
使用#软重启执行仅用户空间的重启。 | systemctl soft-reboot
|
软重启
软重启是一种特殊类型的仅用户空间重启操作,不涉及内核。它由 systemd-soft-reboot.service(8) 实现,可以通过 systemctl soft-reboot
调用。与 kexec 一样,它跳过固件重新初始化,但此外,系统不会经历内核初始化和 initramfs,并且解锁的 dm-crypt 设备保持连接。
当 /run/nextroot/
包含有效的根文件系统层次结构时(例如,是另一个发行版或另一个快照的根挂载),软重启会将系统根切换到其中,从而允许切换到另一个安装,而不会丢失内核管理的状态,例如 网络。
/run/nextroot/
不一定是挂载点或由物理设备支持。例如,它可以驻留在 /run/
tmpfs 中。 systemd 会在软重启时自动将 /run/nextroot/
转换为挂载点。systemctl soft-reboot
。编写单元文件
systemd 的单元文件(systemd.unit(5))的语法灵感来自 XDG Desktop Entry Specification .desktop 文件,而后者又受到 Microsoft Windows .ini 文件 的启发。单元文件从多个位置加载(要查看完整列表,请运行 systemctl show --property=UnitPath
),但主要的加载位置是(从最低优先级到最高优先级列出)
/usr/lib/systemd/system/
:已安装软件包提供的单元/etc/systemd/system/
:系统管理员安装的单元
- 在 用户模式 下运行 systemd 时,加载路径完全不同。
- systemd 单元名称只能包含 ASCII 字母数字字符、下划线和句点。所有其他字符都必须替换为 C 风格的“\x2d”转义符,或使用其预定义的语义('@'、'-')。有关更多信息,请参见 systemd.unit(5) 和 systemd-escape(1)。
查看您的软件包安装的单元以获取示例,以及 systemd.service(5) § 示例。
#
的注释也可以在单元文件中使用,但只能在新行中使用。请勿在 systemd 参数之后使用行尾注释,否则单元将无法激活。systemd-analyze(1) 可以帮助验证工作。请参见该页面的 systemd-analyze verify FILE...
部分。
处理依赖关系
使用 systemd,可以通过正确设计单元文件来解决依赖关系。最典型的情况是,单元 A 要求单元 B 在 A 启动之前运行。在这种情况下,将 Requires=B
和 After=B
添加到 A 的 [Unit]
部分。如果依赖关系是可选的,请添加 Wants=B
和 After=B
。请注意,Wants=
和 Requires=
并不意味着 After=
,这意味着如果未指定 After=
,则两个单元将并行启动。
依赖关系通常放在服务上,而不是 #目标 上。例如,network.target
由配置您的网络接口的任何服务拉入,因此在您的自定义单元之后对其进行排序就足够了,因为无论如何都会启动 network.target
。
服务类型
在编写自定义服务文件时,需要考虑几种不同的启动类型。这是通过 [Service]
部分中的 Type=
参数设置的
Type=simple
(默认):systemd 认为服务已立即启动。该进程不得派生。如果其他服务需要在此服务上排序,则不要使用此类型,除非它是套接字激活的。Type=forking
:systemd 认为服务在进程派生且父进程退出后启动。对于经典守护进程,除非您知道没有必要,否则请使用此类型。您还应该指定PIDFile=
,以便 systemd 可以跟踪主进程。Type=oneshot
:这对于执行单个作业然后退出的脚本很有用。您可能还需要设置RemainAfterExit=yes
,以便 systemd 在进程退出后仍将该服务视为活动状态。设置RemainAfterExit=yes
适用于更改系统状态的单元(例如,挂载某些分区)。另请参见 [1],了解 simple 和 oneshot 的区别。Type=notify
:与Type=simple
相同,但规定守护进程在准备就绪时将向 systemd 发送信号。此通知的参考实现由 libsystemd-daemon.so 提供。Type=dbus
:当指定的BusName
出现在 DBus 的系统总线上时,服务被视为已准备就绪。Type=idle
:systemd 将延迟服务二进制文件的执行,直到所有作业都已分派。除此之外,行为与Type=simple
非常相似。
有关 Type
值的更详细说明,请参见 systemd.service(5) § OPTIONS 手册页。
编辑提供的单元
为避免与 pacman 冲突,不应直接编辑软件包提供的单元文件。有两种安全的方法可以在不触及原始文件的情况下修改单元:创建一个新的单元文件,该文件覆盖原始单元或创建 drop-in 代码片段,这些代码片段应用于原始单元之上。对于这两种方法,您都必须在之后重新加载单元才能应用更改。这可以通过使用 systemctl edit
编辑单元(它会自动重新加载单元)或通过使用以下命令重新加载所有单元来完成
# systemctl daemon-reload
- 您可以使用 systemd-delta 来查看哪些单元文件已被覆盖或扩展,以及具体更改了哪些内容。
- 使用
systemctl cat unit
查看单元文件的内容和所有关联的 drop-in 代码片段。
替换单元文件
要替换单元文件 /usr/lib/systemd/system/unit
,请创建文件 /etc/systemd/system/unit
并重新启用该单元以更新符号链接。
或者,运行
# systemctl edit --full unit
这将在您的编辑器中打开 /etc/systemd/system/unit
(如果尚不存在,则复制已安装的版本),并在您完成编辑后自动重新加载它。
Drop-in 文件
要为单元文件 /usr/lib/systemd/system/unit
创建 drop-in 文件,请创建目录 /etc/systemd/system/unit.d/
,并将 .conf 文件放在此处以覆盖或添加新选项。 systemd 将解析这些文件并将它们应用于原始单元之上。
执行此操作的最简单方法是运行
# systemctl edit unit --drop-in=drop_in_name
这将在您的文本编辑器中打开文件 /etc/systemd/system/unit.d/drop_in_name.conf
(如果需要,则创建它),并在您完成编辑后自动重新加载该单元。省略 --drop-in=
选项将导致 systemd 使用默认文件名 override.conf
。
- 密钥仍必须放置在覆盖文件中的适当部分中。
- 并非所有密钥都可以使用 drop-in 文件覆盖。例如,要更改
Conflicts=
,需要替换文件 是必要的。 - 您可以使用顶级 drop-in 文件来影响同一类型的所有单元。例如,
/etc/systemd/system/service.d/
中的 drop-in 文件会影响所有 .service 单元。您可以在 #通知有关失败的服务 中看到一个示例
恢复到供应商版本
要恢复使用 systemctl edit
对单元所做的任何更改,请执行
# systemctl revert unit
示例
例如,如果您只想向单元添加额外的依赖项,则可以创建以下文件
/etc/systemd/system/unit.d/customdependency.conf
[Unit] Requires=new dependency After=new dependency
作为另一个示例,为了替换 ExecStart
指令,请创建以下文件
/etc/systemd/system/unit.d/customexec.conf
[Service] ExecStart= ExecStart=new command
请注意,必须先清除 ExecStart
,然后才能重新分配它 [2]。对于可以多次指定的每个项目也是如此,例如 timers 的 OnCalendar
。
自动重启服务的另一个示例
/etc/systemd/system/unit.d/restart.conf
[Service] Restart=always RestartSec=30
服务日志级别
对于直接将日志发送到 journald 或 syslog 的服务,您可以使用上述方法通过在 [Service]
部分中为 LogLevelMax=
参数设置介于 0 和 6 之间的数值来控制其详细程度。例如
/etc/systemd/system/unit.d/override.conf
[Service] LogLevelMax=3
标准日志级别与用于过滤 日志 的日志级别相同。设置较低的数字会从您的日志中排除所有较高和不太重要的日志消息。
抑制服务的标准输出
如果服务正在回显 stdout 和/或 stderr 输出,则默认情况下,这也将最终出现在日志中。可以通过在 [Service]
部分中设置 StandardOutput=null
和/或 StandardError=null
来抑制此行为。可以使用除 null
之外的其他值来进一步调整此行为。请参见 systemd.exec(5) § LOGGING_AND_STANDARD_INPUT/OUTPUT。
目标
systemd 使用目标通过依赖关系将单元组合在一起,并作为标准化的同步点。它们的作用类似于运行级别,但行为略有不同。每个目标都有名称而不是编号,旨在服务于特定目的,并且可以同时激活多个目标。某些目标通过继承另一个目标的所有服务并向其添加其他服务来实现。有一些 systemd 目标 模仿了常见的 SystemVinit 运行级别。
获取当前目标
在 systemd 下,应使用以下命令代替运行 runlevel
$ systemctl list-units --type=target
创建自定义目标
在 sysvinit 下具有明确含义的运行级别(即 0、1、3、5 和 6);与特定的 systemd 目标 具有 1:1 映射。不幸的是,对于用户定义的运行级别(如 2 和 4)来说,没有好的方法可以做到这一点。如果您使用这些运行级别,建议您创建一个新的命名 systemd 目标,如 /etc/systemd/system/your target
,它以现有运行级别之一作为基础(您可以查看 /usr/lib/systemd/system/graphical.target
作为示例),创建一个目录 /etc/systemd/system/your target.wants
,然后从 /usr/lib/systemd/system/
符号链接您希望启用的其他服务。
SysV 运行级别和 systemd 目标之间的映射
SysV 运行级别 | systemd 目标 | 注释 |
---|---|---|
0 | poweroff.target | 停止系统。 |
1, s, single | rescue.target | 单用户模式。 |
2, 4 | multi-user.target | 用户定义/特定站点的运行级别。默认情况下,与 3 相同。 |
3 | multi-user.target | 多用户,非图形界面。用户通常可以通过多个控制台或通过网络登录。 |
5 | graphical.target | 多用户,图形界面。通常具有运行级别 3 的所有服务以及图形登录。 |
6 | reboot.target | 重启 |
emergency | emergency.target | 紧急 Shell |
更改当前目标
在 systemd 中,目标通过目标单元公开。您可以像这样更改它们
# systemctl isolate graphical.target
这只会更改当前目标,对下次启动没有影响。这等效于 Sysvinit 中的命令(如 telinit 3
或 telinit 5
)。
更改默认启动目标
标准目标是 default.target
,它是 graphical.target
的符号链接。这大致对应于旧的运行级别 5。
要使用 systemctl 验证当前目标
$ systemctl get-default
要更改默认启动目标,请更改 default.target
符号链接。使用 systemctl
# systemctl set-default multi-user.target
Removed /etc/systemd/system/default.target. Created symlink /etc/systemd/system/default.target -> /usr/lib/systemd/system/multi-user.target.
或者,将以下内核参数之一附加到您的启动加载器
systemd.unit=multi-user.target
(大致对应于旧的运行级别 3),systemd.unit=rescue.target
(大致对应于旧的运行级别 1)。
默认目标顺序
systemd 根据以下顺序选择 default.target
- 上面显示的内核参数
/etc/systemd/system/default.target
的符号链接/usr/lib/systemd/system/default.target
的符号链接
systemd 组件
systemd 的一些(非详尽)组件是
- kernel-install — 用于自动移动内核及其各自的 initramfs 镜像到启动分区;
- systemd-analyze(1) — 可用于确定启动性能、统计信息和检索其他状态及跟踪信息,并验证单元文件的正确性。它还用于访问对高级调试有用的特殊功能。
- systemd-boot — 简单的 UEFI 启动管理器;
- systemd-creds — 用于安全地存储和检索 systemd 单元使用的凭据;
- systemd-cryptenroll — 将 PKCS#11、FIDO2、TPM2 令牌/设备注册到 LUKS2 加密卷;
- systemd-firstboot — 首次启动前的基本系统设置初始化;
- systemd-homed — 可移植的人类用户账户;
- systemd-logind(8) — 会话管理;
- systemd-networkd — 网络配置管理;
- systemd-nspawn — 轻量级命名空间容器;
- systemd-repart — 创建分区表,添加或扩展分区;
- systemd-resolved — 网络名称解析;
- systemd-run(1) / run0(1) — 临时且交互式地获取提升的或不同的权限。
- systemd-stub(7) — 用于创建统一内核镜像的 UEFI 启动存根;
- systemd-sysusers(8) — 在软件包安装或启动时创建系统用户和组,并将用户添加到组;
- systemd-timesyncd — 跨网络的系统时间同步;
- systemd/Journal — 系统日志记录;
- systemd/Timers — 用于控制 .service 文件或事件的单调或实时定时器,是 cron 的合理替代方案。
systemd.mount - 挂载
systemd 负责挂载 /etc/fstab
中指定的分区和文件系统。systemd-fstab-generator(8) 将 /etc/fstab
中的所有条目转换为 systemd 单元;这在启动时以及系统管理器配置重新加载时执行。
systemd 扩展了通常的 fstab 功能,并提供了额外的挂载选项。这些选项影响挂载单元的依赖关系。例如,它们可以确保仅在网络启动后或另一个分区挂载后才执行挂载。以 x-systemd.
为前缀的特定 systemd 挂载选项的完整列表,详见 systemd.mount(5) § FSTAB。
这些挂载选项的一个例子是自动挂载,这意味着仅在需要资源时才挂载,而不是在启动时自动挂载。这在 fstab#Automount with systemd 中提供。
GPT 分区自动挂载
在 UEFI 启动的系统上,root、home、swap 等 GPT 分区可以按照 Discoverable Partitions Specification 自动挂载。因此,这些分区可以从 fstab 中省略,如果 root 分区是自动挂载的,则 root=
可以从内核命令行中省略。请参阅 systemd-gpt-auto-generator(8)。
前提条件是
- 当使用 mkinitcpio 时,需要 systemd hook。
- 所有自动挂载的分区必须与 ESP 位于同一物理磁盘上。
- 必须设置正确的 GPT 分区类型。请参阅 Partitioning#Partition scheme。
- 引导加载程序必须设置 LoaderDevicePartUUID EFI 变量,以便可以识别使用的 EFI 系统分区。systemd-boot、systemd-stub(7)、GRUB (使用 grub-mkconfig 生成的
grub.cfg
;自定义grub.cfg
需要加载 bli 模块) 和 rEFInd (默认情况下未启用) 支持此功能。可以通过运行bootctl
并检查Boot loader sets ESP information
的状态,或者在使用统一内核镜像启动时检查Stub sets ESP information
的状态来验证这一点。
udev 将创建一个指向根卷块设备的 /dev/gpt-auto-root
符号链接。如果根分区使用 LUKS 加密,/dev/gpt-auto-root
将指向解锁/映射的卷,而 /dev/gpt-auto-root-luks
将指向加密的分区。
/var
为了使 /var
自动挂载工作,PARTUUID 必须与由机器 ID 键控的分区类型 UUID 的 SHA256 HMAC 哈希匹配。所需的 PARTUUID 可以使用以下命令获得
$ systemd-id128 -u var-partition-uuid
/etc/machine-id
读取机器 ID,这使得在系统安装之前无法知道所需的 PARTUUID。systemd-sysvcompat
systemd-sysvcompat (base
所必需) 的主要作用是提供传统的 linux init 二进制文件。对于 systemd 控制的系统,init
只是指向其 systemd
可执行文件的符号链接。
此外,它还提供了 SysVinit 用户可能习惯的四个便捷快捷方式。这些便捷快捷方式是 halt(8)、poweroff(8)、reboot(8) 和 shutdown(8)。这四个命令中的每一个都是指向 systemctl
的符号链接,并受 systemd 行为的管辖。因此,#电源管理 中的讨论适用。
基于 systemd 的系统可以通过使用 init=
启动参数 (例如,请参阅 /bin/init is in systemd-sysvcompat ?) 和 systemd 原生的 systemctl
命令参数来放弃那些 System V 兼容性方法。
systemd-tmpfiles - 临时文件
systemd-tmpfiles 创建、删除和清理易失性和临时文件及目录。它读取 /etc/tmpfiles.d/
和 /usr/lib/tmpfiles.d/
中的配置文件,以发现要执行的操作。前一个目录中的配置文件优先于后一个目录中的配置文件。
配置文件通常与服务文件一起提供,并且以 /usr/lib/tmpfiles.d/program.conf
的风格命名。例如,Samba 守护程序期望目录 /run/samba
存在并具有正确的权限。因此,samba
软件包附带此配置
/usr/lib/tmpfiles.d/samba.conf
D /run/samba 0755 root root
配置文件也可以用于在启动时将值写入某些文件。例如,如果您过去使用 /etc/rc.local
和 echo USBE > /proc/acpi/wakeup
来禁用 USB 设备唤醒,则可以使用以下 tmpfile 代替
/etc/tmpfiles.d/disable-usb-wake.conf
# Path Mode UID GID Age Argument w /proc/acpi/wakeup - - - - USBE
可以将多行写入同一文件,可以使用参数中的 \n
,也可以在多行 (包括第一行) 上使用 w+
类型进行追加
/etc/tmpfiles.d/disable-usb-wake.conf
# Path Mode UID GID Age Argument w+ /proc/acpi/wakeup - - - - USBE w+ /proc/acpi/wakeup - - - - LID0
有关详细信息,请参阅 systemd-tmpfiles(8) 和 tmpfiles.d(5) 手册页。
/sys
中设置选项,因为 systemd-tmpfiles-setup 服务可能在加载适当的设备模块之前运行。在这种情况下,您可以检查模块是否具有要设置的选项的参数,使用 modinfo module
,并使用 /etc/modprobe.d 中的配置文件设置此选项。否则,您将必须编写 udev 规则,以便在设备出现时立即设置相应的属性。
Drop-in 配置文件
不应直接编辑软件包提供的配置文件,以避免与 pacman 更新冲突。为此,许多 (但并非所有) systemd 软件包都提供了一种修改配置的方法,但无需通过创建 drop-in 代码段来修改原始文件。检查软件包手册以查看是否支持 drop-in 配置文件。
要为单元文件 /etc/systemd/unit.conf
创建 drop-in 配置文件,请创建目录 /etc/systemd/unit.conf.d/
,并将 .conf 文件放在那里以覆盖或添加新选项。systemd 将解析这些文件并将它们应用到原始单元之上。
检查整体配置
$ systemd-analyze cat-config systemd/unit.conf
应用的 drop-in 代码段文件和内容将列在末尾。重启服务以使更改生效。
技巧与窍门
Socket 激活
某些软件包提供 .socket 单元。例如,cups
提供了 cups.socket
单元[3]。如果 cups.socket
已启用 (且 cups.service
保持禁用状态),systemd 不会立即启动 CUPS;它只会监听相应的 socket。然后,每当程序尝试连接到这些 CUPS socket 之一时,systemd 将启动 cups.service
并透明地将这些端口的控制权移交给 CUPS 进程。
GUI 配置工具
- systemadm — systemd 单元的图形浏览器。它可以显示单元列表,可能按类型过滤。
- SystemdGenie — 基于 KDE 技术的 systemd 管理实用程序。
在网络启动后运行服务
要延迟服务直到网络启动后,请在 .service 文件中包含以下依赖项
/etc/systemd/system/foo.service
[Unit] ... Wants=network-online.target After=network-online.target ...
也必须启用正在使用的网络管理器的网络等待服务,以便 network-online.target
正确反映网络状态。
- 如果使用 NetworkManager,则应同时启用
NetworkManager-wait-online.service
和NetworkManager.service
。使用systemctl is-enabled NetworkManager-wait-online.service
检查是否是这种情况。如果未启用,则重新启用NetworkManager.service
。 - 在 netctl 的情况下,启用
netctl-wait-online.service
(除非您正在使用 netctl-auto;请参阅 FS#75836)。 - 如果使用 systemd-networkd,则应同时启用
systemd-networkd-wait-online.service
和systemd-networkd.service
。使用systemctl is-enabled systemd-networkd-wait-online.service
检查是否是这种情况。如果未启用,则重新启用systemd-networkd.service
。
有关更详细的解释,请参阅 网络配置同步点中的讨论。
如果服务需要执行 DNS 查询,则还应将其排序在 nss-lookup.target
之后
/etc/systemd/system/foo.service
[Unit] ... Wants=network-online.target After=network-online.target nss-lookup.target ...
请参阅 systemd.special(7) § 特殊被动系统单元。
为了使 nss-lookup.target
产生任何效果,它需要一个通过 Wants=nss-lookup.target
拉入它并通过 Before=nss-lookup.target
将自身排序在其之前的服务。通常,这是由本地 DNS 解析器完成的。
使用以下命令检查哪个活动服务 (如果有) 正在拉入 nss-lookup.target
$ systemctl list-dependencies --reverse nss-lookup.target
默认启用已安装的单元
Arch Linux 附带包含 disable *
的 /usr/lib/systemd/system-preset/99-default.preset
。这导致 systemctl preset 默认禁用所有单元,这样,当安装新软件包时,用户必须手动启用该单元。
如果不希望这种行为,只需创建从 /etc/systemd/system-preset/99-default.preset
到 /dev/null
的符号链接,以覆盖配置文件。这将导致 systemctl preset 启用所有已安装的单元 (无论单元类型如何),除非在 systemctl preset 的配置目录中的另一个文件中指定。用户单元不受影响。有关更多信息,请参阅 systemd.preset(5)。
沙盒化应用程序环境
可以创建一个单元文件作为沙箱,以在强化的虚拟环境中隔离应用程序及其进程。systemd 利用 命名空间、允许/拒绝的 功能列表和 控制组,通过广泛的执行环境配置 — systemd.exec(5) 来容器化进程。
使用应用程序沙盒增强现有 systemd 单元文件通常需要反复试验测试,并大量使用 strace
、stderr 和 journalctl(1) 错误日志记录和输出工具。您可能需要首先搜索上游文档,以查找已完成的测试,以便以此为基础进行试验。要获得可能的强化选项的起点,请运行
$ systemd-analyze security unit
systemd 沙盒化部署方式的一些示例
CapabilityBoundingSet
定义了单元允许或拒绝的 capabilities(7) 功能列表。请参阅 systemd.exec(5) § CAPABILITIES。- 例如,
CAP_SYS_ADM
功能,它应该是安全沙箱的目标之一:CapabilityBoundingSet=~ CAP_SYS_ADM
- 例如,
通知有关失败的服务
为了通知有关服务失败,需要将 OnFailure=
指令添加到相应的服务文件中,例如通过使用 drop-in 配置文件。可以使用顶层 drop-in 配置文件将此指令添加到每个服务单元。有关顶层 drop-in 的详细信息,请参阅 systemd.unit(5)。
为服务创建顶层 drop-in
/etc/systemd/system/service.d/toplevel-override.conf
[Unit] OnFailure=failure-notification@%n.service
这会将 OnFailure=failure-notification@%n.service
添加到每个服务文件。如果 some_service_unit 失败,将启动 failure-notification@some_service_unit.service
以处理通知传递 (或配置为执行的任何任务)。
创建 failure-notification@.service
模板单元
/etc/systemd/system/failure-notification@.service
[Unit] Description=Send a notification about a failed systemd unit [Service] Type=oneshot ExecStart=/path/to/failure-notification.sh %i # runs as a temporary user/group and enables several other security precautions DynamicUser=true
您可以创建 failure-notification.sh
脚本并定义要执行的操作或如何通知。示例包括发送电子邮件、显示桌面通知、使用 gotify、XMPP 等。%i
将是失败的服务单元的名称,并将作为参数传递给脚本。
为了防止在启动失败时反复启动 failure-notification@.service
实例的递归,请创建一个与顶层 drop-in 同名的空 drop-in 配置文件 (空服务级别 drop-in 配置文件优先于顶层 drop-in 并覆盖后者)
# mkdir -p /etc/systemd/system/failure-notification@.service.d # touch /etc/systemd/system/failure-notification@.service.d/toplevel-override.conf
通过电子邮件通知
您可以将 systemd 设置为在单元失败时发送电子邮件。如果作业输出到 stdout 或 stderr,Cron 会将邮件发送到 MAILTO
,但许多作业设置为仅在错误时输出。首先,您需要两个文件:一个用于发送邮件的可执行文件和一个用于启动可执行文件的 .service 文件。对于此示例,可执行文件只是一个使用 sendmail
的 shell 脚本,它位于提供 smtp-forwarder
的软件包中。
/usr/local/bin/systemd-email
#!/bin/sh /usr/bin/sendmail -t <<ERRMAIL To: $1 From: systemd <root@$HOSTNAME> Subject: $2 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 $(systemctl status --full "$2") ERRMAIL
无论您使用什么可执行文件,它都应该像这个 shell 脚本一样至少接受两个参数:要发送到的地址和要获取其状态的单元文件。我们创建的 .service 文件将传递这些参数
/etc/systemd/system/status_email_user@.service
[Unit] Description=status email for %i to user [Service] Type=oneshot ExecStart=/usr/local/bin/systemd-email address %i User=nobody Group=systemd-journal
其中 user
是要发送电子邮件的用户,address
是该用户的电子邮件地址。尽管收件人是硬编码的,但要报告的单元文件作为实例参数传递,因此这项服务可以为许多其他单元发送电子邮件。此时,您可以启动 status_email_user@dbus.service
以验证您是否可以收到电子邮件。
然后只需编辑您想要接收电子邮件的服务,并将 OnFailure=status_email_user@%n.service
添加到 [Unit]
部分。%n
将单元的名称传递给模板。
- 如果您根据 sSMTP#Security 设置了 sSMTP 安全性,则用户
nobody
将无法访问/etc/ssmtp/ssmtp.conf
,并且systemctl start status_email_user@dbus.service
命令将失败。一种解决方案是在status_email_user@.service
单元中使用root
作为 User。 - 如果您尝试在电子邮件脚本中使用
mail -s somelogs address
,则mail
将 fork,并且当 systemd 看到您的脚本退出时,将杀死 mail 进程。通过执行mail -Ssendwait -s somelogs address
使 mail 非 fork。
DynamicUser=true
作为 User=nobody
的替代方案,后者现在不鼓励使用。有关更多详细信息,请参阅 GitHub issue 428。在关机时自动关闭外部 HDD
请参阅 udisks#Automatically turn off an external HDD at shutdown。
故障排除
调查失败的服务
查找未能启动的 systemd 服务
$ systemctl --state=failed
要找出它们失败的原因,请检查它们的日志输出。有关详细信息,请参阅 systemd/Journal#Filtering output。
诊断启动问题
systemd 有几个选项用于诊断启动过程中的问题。请参阅 boot debugging 以获取更通用的说明和选项,以便在 systemd 接管启动过程之前捕获启动消息。另请参阅 systemd debugging documentation。
诊断服务
如果某个 systemd 服务行为异常,或者您想获得有关正在发生的事情的更多信息,请将 SYSTEMD_LOG_LEVEL
环境变量 设置为 debug
。例如,要在调试模式下运行 systemd-networkd 守护程序
为服务添加一个 drop-in 文件,添加以下两行
[Service] Environment=SYSTEMD_LOG_LEVEL=debug
或者,等效地,手动设置环境变量
# SYSTEMD_LOG_LEVEL=debug /lib/systemd/systemd-networkd
然后重启 systemd-networkd,并使用 -f
/--follow
选项查看服务的日志。
关机/重启耗时过长
如果关机过程花费很长时间 (或似乎冻结),则很可能是某个服务未退出造成的。systemd 会等待每个服务退出一段时间,然后尝试终止它。要了解您是否受到影响,请参阅 systemd 文档中的 Shutdown completes eventually。
常见问题是关机或挂起过程停滞。要验证是否是这种情况,您可以运行以下任一命令并检查输出
# systemctl poweroff
Failed to power off system via logind: There's already a shutdown or sleep operation in progress
# systemctl list-jobs
JOB UNIT TYPE STATE ... 21593 systemd-suspend.service start running 21592 suspend.target start waiting ..
解决此问题的方法是通过运行以下命令取消这些作业
# systemctl cancel # systemctl stop systemd-suspend.service
然后再次尝试关机或重启。
短暂存在的进程似乎没有记录任何输出
如果以 root 身份运行 journalctl -u foounit
没有显示任何短暂服务的输出,请查看 PID。例如,如果 systemd-modules-load.service
失败,并且 systemctl status systemd-modules-load
显示它作为 PID 123 运行,那么您可能能够在日志中看到该 PID 的输出,即通过以 root 身份运行 journalctl -b _PID=123
。日志的元数据字段 (如 _SYSTEMD_UNIT
和 _COMM
) 是异步收集的,并且依赖于 /proc
目录来表示进程的存在。修复此问题需要修复内核以通过 socket 连接提供此数据,类似于 SCM_CREDENTIALS
。简而言之,这是一个 bug。请记住,根据 systemd 的设计,立即失败的服务可能不会在日志中打印任何内容。
启动时间随时间推移而增加
在使用 systemd-analyze
后,许多用户注意到他们的启动时间与过去相比显着增加。在使用 systemd-analyze blame
后,NetworkManager 被报告为启动时间异常长。
对于某些用户来说,问题是由于 /var/log/journal
变得太大。这可能会对性能产生其他影响,例如 systemctl status
或 journalctl
。因此,解决方案是删除文件夹中的每个文件 (理想情况下,至少暂时在某处备份它),然后设置日志文件大小限制,如 Systemd/Journal#Journal size limit 中所述。
systemd-tmpfiles-setup.service 在启动时启动失败
从 systemd 219 开始,/usr/lib/tmpfiles.d/systemd.conf
为 /var/log/journal
下的目录指定 ACL 属性,因此,需要为日志所在的文件系统启用 ACL 支持。
有关如何在容纳 /var/log/journal
的文件系统上启用 ACL 的说明,请参阅 Access Control Lists#Enable ACL。
在远程计算机上禁用紧急模式
您可能希望在远程计算机上禁用紧急模式,例如,Azure 或 Google Cloud 上托管的虚拟机。这是因为如果触发紧急模式,计算机将被阻止连接到网络。
要禁用它,请 mask emergency.service
和 emergency.target
。
错误 “Unit xxx.service not found”,但服务确实存在
您可能正在尝试将用户单元作为系统单元启动或启用。systemd.unit(5) 指示了单元的驻留位置。默认情况下,systemctl 对系统服务进行操作。
有关更多详细信息,请参阅 Systemd/User。
参见
- Wikipedia:systemd
- 官方网站
- systemd(1)
- 其他发行版
- Lennart 的博客故事, 更新 1, 更新 2, 更新 3, 摘要
- 调试 Systemd 服务
- 面向管理员的 systemd (PDF)
- 如何使用 Systemctl 管理 Systemd 服务和单元
- 使用 systemd-logind 进行会话管理
- Systemd 文件的 Emacs 语法高亮
- 两 部分 The H Open 杂志上的介绍性文章。