9.10. Systemd 使用和配置

9.10.1. 基础设置

/etc/systemd/system.conf 文件包含一组控制 systemd 基本功能的选项。默认文件中所有条目都被注释掉,并标明了默认值。可以在这里修改日志级别,以及其他一些基本日志设定。参阅 systemd-system.conf(5) man 手册页面了解每个选项的详细信息。

9.10.2. 禁用引导时自动清屏

Systemd 的默认行为是在引导过程结束时清除屏幕。如果希望的话,您可以运行以下命令,修改这一行为:

mkdir -pv /etc/systemd/system/getty@tty1.service.d

cat > /etc/systemd/system/getty@tty1.service.d/noclear.conf << EOF
[Service]
TTYVTDisallocate=no
EOF

您总是可以用 root 身份运行 journalctl -b 命令,查阅引导消息。

9.10.3. 禁止将 tmpfs 挂载到 /tmp

默认情况下,/tmp 将被挂载 tmpfs 文件系统。如果不希望这样,可以执行以下命令覆盖这一行为:

ln -sfv /dev/null /etc/systemd/system/tmp.mount

或者,如果希望使用一个单独的 /tmp 分区,在 /etc/fstab 中为其添加一个条目。

[警告]

警告

如果使用了单独的 /tmp 分区,不要创建上面的符号链接。这会导致根文件系统 (/) 无法重新挂载为可读写,使得系统在引导后不可用。

9.10.4. 配置文件自动创建和删除

有一些创建或删除文件、目录的服务:

  • systemd-tmpfiles-clean.service

  • systemd-tmpfiles-setup-dev.service

  • systemd-tmpfiles-setup.service

它们的系统配置文件位于 /usr/lib/tmpfiles.d/*.conf。本地配置文件位于 /etc/tmpfiles.d/etc/tmpfiles.d 中的文件覆盖 /usr/lib/tmpfiles.d 中的同名文件。参阅 tmpfiles.d(5) man 手册页面,了解配置文件格式的细节。

注意 /usr/lib/tmpfiles.d/*.conf 文件的语法较难理解。例如,删除 /tmp 目录下文件的默认规则是文件 /usr/lib/tmpfiles.d/tmp.conf 的一行:

q /tmp 1777 root root 10d

类别字段 q 表示创建一个带有配额的子卷,它实际上只适用于 btrfs 文件系统。它引用类别 v,类别 v 又引用类别 d (目录)。对于类别 d,会在目录不存在时自动创建它,并根据配置文件调整其权限和所有者。如果 age 参数被指定,该目录中较老的文件会被自动清理。

如果默认参数不符合您的期望,您可以将文件复制到 /etc/tmpfiles.d 目录,再编辑复制得到的副本。例如:

mkdir -p /etc/tmpfiles.d
cp /usr/lib/tmpfiles.d/tmp.conf /etc/tmpfiles.d

9.10.5. 覆盖系统服务默认行为

Systemd 单元的参数可以通过在 /etc/systemd/system 中创建一个包含配置文件的目录而覆盖。例如:

mkdir -pv /etc/systemd/system/foobar.service.d

cat > /etc/systemd/system/foobar.service.d/foobar.conf << EOF
[Service]
Restart=always
RestartSec=30
EOF

参阅 systemd.unit(5) man 手册页面获取更多信息。在创建配置文件后,执行 systemctl daemon-reloadsystemctl restart foobar,激活对服务进行的修改。

9.10.6. 调试引导过程

与 SysVinit 或 BSD 风格 init 系统不同,systemd 使用统一格式处理不同种类的引导文件 (或称为单元)。命令 systemctl 能够启用、禁用单元文件,或控制、查询单元文件的状态。以下是一些常用的命令:

  • systemctl list-units -t <service> [--all]: 列出已加载的服务 (service) 类型单元文件。

  • systemctl list-units -t <target> [--all]: 列出已加载的引导目标 (target) 类型单元文件。

  • systemctl show -p Wants <multi-user.target>: 显示所有依赖于 multi-user 引导目标的单元,引导目标 (target)是一种和 SysVinit 中运行级别 (runlevel) 地位相同的特殊单元文件。

  • systemctl status <servicename.service>: 显示名为 servicename 的服务的状态。如果没有同名的其他类型单元文件,可以省略 .service 后缀。其他类型的单元文件有 .socket 文件 (它创建一个监听套接字,提供和 inetd/xinetd 类似的功能)。

9.10.7. 使用 systemd 日志

(默认情况下) 在使用 systemd 引导的系统上,systemd-journald 服务负责处理日志,它取代了传统的 Unix syslog 守护进程。如果您希望的话,也可以添加一个普通 syslog 守护进程,它和 systemd-journald 可以一起工作。systemd-journald 程序将日志项储存为二进制格式,而不是纯文本日志文件。为了解析日志文件,需要使用 systemd 提供的 journalctl 命令。下面是该命令的常见用法:

  • journalctl -r:按时间顺序,倒序显示所有日志内容。

  • journalctl -u UNIT: 显示与给定单元文件 UNIT 关联的日志。

  • journalctl -b[=ID] -r: 按时间倒序,显示自上次引导以来 (或编号为 ID 的引导中) 的所有日志。

  • journalctl -f: 提供类似 tail -f 的功能 (不断将新日志项输出到屏幕)。

9.10.8. 处理核心转储

核心转储在调试崩溃的程序时非常有用,特别是对于守护进程崩溃的情况。在 systemd 引导的系统上,核心转储由 systemd-coredump 处理。它会在日志中记录核心转储,并且将核心转储文件本身存储到 /var/lib/systemd/coredump 中。如果要获取和处理核心转储文件,可以使用 coredumpctl 工具。下面给出它的常用命令的示例:

  • coredumpctl -r:按时间顺序,倒序显示所有核心转储记录。

  • coredumpctl -1 info:显示最近一次核心转储的信息。

  • coredumpctl -1 debug:将最后一次核心转储加载到 GDB 中。

核心转储可能使用大量磁盘空间。为了限制核心转储使用的最大磁盘空间,可以在 /etc/systemd/coredump.conf.d 中创建一个配置文件。例如:

mkdir -pv /etc/systemd/coredump.conf.d

cat > /etc/systemd/coredump.conf.d/maxuse.conf << EOF
[Coredump]
MaxUse=5G
EOF

参阅 man 手册页面 systemd-coredump(8)coredumpctl(1),以及 coredump.conf.d(5) 了解更多信息。

9.10.9. 持续运行进程

从 systemd 的 230 版本开始,在用户会话结束时,所有用户进程都被杀死,即使使用了 nohup 或 daemon()setsid() 等函数也不例外。这是开发者有意做出的修改,将传统的宽松环境改为更加严格的环境。如果您需要让持续运行的程序 (例如 screentmux) 在用户会话结束后保持运行,这项新的行为会导致问题。有三种方法使得这类驻留进程在用户会话结束后继续运行:

  • 仅为选定的用户启用进程驻留:普通用户有执行命令 loginctl enable-linger 启用进程驻留的权限,管理员可以使用带 user 参数的该命令,为特定用户启用进程驻留。在启用进程驻留后,可以使用 systemd-run 命令启动持续运行的进程。例如,systemd-run --scope --user /usr/bin/screen。如果您为您的用户启用了进程驻留,则 user@.service 将持续运行,甚至在所有登录会话关闭后仍然运行,而且会在系统引导时自动启动。这种方法的好处是可以显式地允许或禁止进程在用户会话结束后继续运行,但却破坏了和 nohup 等工具,和使用 daemon() 函数的工具的兼容性。

  • 为整个系统启用进程驻留:您可以在将 KillUserProcesses=no 设置行加入 /etc/systemd/logind.conf,为所有用户全局地启用进程驻留。它的好处是允许所有用户继续使用旧方法,但无法进行明确控制。

  • 在编译时禁用该功能:您可以在构建 systemd 时传递参数 -Ddefault-kill-user-process=nomeson,使得 systemd 默认启用进程驻留。这完全禁用了 systemd 在会话结束时杀死用户进程的功能。