跳到内容跳到页面导航:上一页 [access key p]/下一页 [access key n]
documentation.suse.com / SUSE Linux Enterprise Server 文档 / 管理指南 / 引导 Linux 系统 / systemd 守护程序
适用范围 SUSE Linux Enterprise Server 15 SP3

15 systemd 守护程序

systemd 负责初始化系统,它的进程 ID 为 1。systemd 由内核直接启动,信号 9(该信号通常会终止进程)对它不起作用。所有其他程序或由 systemd 直接启动,或由它的其中一个子进程启动。systemd 取代了 System V init 守护程序,并且通过支持 init 脚本与 System V init 完全兼容。

systemd 的主要优点是通过并行化服务启动,大大加快了引导速度。另外,systemd 只在确实有需要时才会启动服务。即不会在系统引导时无条件启动守护程序,而是在第一次需要时才会启动。systemd 还支持内核控制组 (cgroup)、创建快照和恢复系统状态。有关更多细节,请参见 http://www.freedesktop.org/wiki/Software/systemd/

15.1 systemd 概念

下面的部分解释了 systemd 背后的概念。

systemd 是适用于 Linux 的系统和会话管理器,它与 System V 及 LSB init 脚本兼容。systemd 的主要功能包括:

  • 并行化能力

  • 使用套接字及 D-Bus 激活来启动服务

  • 按需启动守护程序

  • 使用 Linux cgroup 跟踪进程

  • 创建快照和恢复系统状态

  • 维护挂载点和自动挂载点

  • 实施精细的、基于事务依赖性的服务控制逻辑

15.1.1 单元文件

单元配置文件包含有关以下项目的信息:服务、套接字、设备、挂载点、自动挂载点、交换文件或分区、启动目标、监控的文件系统路径、受 systemd 控制和监管的计时器、临时系统状态快照、资源管理部分或一组外部创建的进程。

单元文件是 systemd 用于描述下列各项的通用术语:

  • 服务: 进程相关信息(例如运行守护程序);文件以 .service 结尾

  • 目标: 用于将单元分组以及在启动期间用作同步点;文件以 .target 结尾

  • 套接字: IPC 或网络套接字或文件系统 FIFO 相关信息,适用于基于套接字的激活(如 inetd);文件以 .socket 结尾

  • 路径: 用于触发其他单元(例如,在文件更改时运行服务);文件以 .path 结尾

  • 计时器: 受控制计时器相关信息,适用于基于计时器的激活;文件以 .timer 结尾

  • 挂载点: 通常由 fstab 生成器自动生成;文件以 .mount 结尾

  • 自动挂载点: 文件系统自动挂载点相关信息;文件以 .automount 结尾

  • 交换: 内存分页的交换设备或文件相关信息;文件以 .swap 结尾

  • 设备: sysfs/udev(7) 设备树中公开的设备相关信息;文件以 .device 结尾

  • 范围/部分: 有关分层管理一组进程的资源的概念;文件以 .scope/.slice 结尾

有关 systemd 单元文件的详细信息,请参见 http://www.freedesktop.org/software/systemd/man/systemd.unit.html

15.2 基本用法

System V init 系统使用若干命令来处理服务:init 脚本、insservtelinit 及其他。systemd 可简化服务管理,因为对于大部分处理服务的任务,只需要记住一条命令:systemctl。它使用命令加子命令表示法,与 gitzypper 相似:

systemctl GENERAL OPTIONS SUBCOMMAND SUBCOMMAND OPTIONS

有关完整的手册,请参见 man 1 systemctl

提示
提示:终端输出和 Bash 补全

如果输出传递到某个终端(而不是某个管道或文件),systemd 命令默认会将长输出发送到分页器。使用 --no-pager 选项可关闭分页模式。

systemd 还支持 bash 补全,允许您输入子命令的头几个字母,然后按 →|。此功能只能在 bash 外壳中使用,并且需要安装 bash-completion 软件包。

15.2.1 管理正在运行的系统中的服务

用于管理服务的子命令与使用 System V init 管理服务的子命令相同(startstop 等)。服务管理命令的一般语法如下所示:

systemd
systemctl reload|restart|start|status|stop|... MY_SERVICE(S)
System V init
rcMY_SERVICE(S) reload|restart|start|status|stop|...

systemd 允许您一次管理多个服务。不用像 System V init 要逐个执行 init 脚本,而是执行如下命令:

tux > sudo systemctl start MY_1ST_SERVICE MY_2ND_SERVICE

要列出系统上所有可用的服务,请运行:

tux > sudo systemctl list-unit-files --type=service

下表列出了 systemd 和 System V init 最重要的服务管理命令:

表 15.1︰ 服务管理命令

任务

systemd 命令

System V init 命令

启动:

start
start

停止:

stop
stop

重启动: 关闭服务,然后再启动这些服务。如果某项服务尚未运行,它将会启动。

restart
restart

有条件地重启动: 如果服务当前正在运行,则重启动它们。对未在运行的服务不执行任何操作。

try-restart
try-restart

重新装载: 让服务在不中断操作的情况下重新装载它们的配置文件。使用案例:让 Apache 重新装载修改过的 httpd.conf 配置文件。请注意,并非所有服务都支持重新装载。

reload
reload

重新装载或重启动: 如果支持重新装载则重新装载服务,否则重启动服务。如果某项服务尚未运行,它将会启动。

reload-or-restart
n/a

有条件地重新装载或重启动: 如果支持重新装载则重新装载服务,否则,如果服务当前正在运行,则重启动服务。对未在运行的服务不执行任何操作。

reload-or-try-restart
n/a

获得详细的状态信息: 列出服务状态的相关信息。systemd 命令会显示说明、可执行文件、状态、cgroup 及服务发出的最新消息等细节(请参见第 15.6.9 节 “调试服务”)。使用 System V init 显示的详细程度因服务而异。

status
status

获得简要的状态信息: 显示服务是否处于活动状态。

is-active
status

15.2.2 永久启用/禁用服务

上一节中提到的服务管理命令可让您操控当前会话的服务。systemd 还允许您永久启用或禁用服务,让它们在用户要求时自动启动或永远不可用。您可以使用 YaST 或在命令行上运行命令来实现此目的。

15.2.2.1 在命令行上启用/禁用服务

下表列出了 systemd 和 System V init 用于启用和禁用服务的命令:

重要
重要:服务启动

在命令行上启用服务时,服务不会自动启动。它会安排在下一次系统启动或运行级别/目标发生更改时启动。要在启用服务之后立即启动它,请显式运行 systemctl start MY_SERVICErc MY_SERVICE start

表 15.2︰ 用于启用和禁用服务的命令

任务

systemd 命令

System V init 命令

启用:

systemctl enable MY_SERVICE(S)

insserv MY_SERVICE(S), chkconfig -a MY_SERVICE(S)

禁用:

systemctl disable MY_SERVICE(S).service

insserv -r MY_SERVICE(S)chkconfig -d MY_SERVICE(S)

检查: 显示某项服务是否启用。

systemctl is-enabled MY_SERVICE

chkconfig MY_SERVICE

重新启用: 与重启动服务相似,此命令先禁用服务,然后再启用该服务。可用来使用默认值重新启用服务。

systemctl reenable MY_SERVICE

屏蔽: 禁用某项服务之后,仍然可以手动启动它。要彻底禁用服务,您需要屏蔽它。须谨慎使用该功能。

systemctl mask MY_SERVICE

取消屏蔽: 屏蔽某项服务之后,只有在将其取消屏蔽之后才能再次使用它。

systemctl unmask MY_SERVICE

15.3 系统启动和目标管理

启动和关闭系统的整个过程由 systemd 负责维护。从这一点来看,可以将内核视为一个后台进程,其任务是维护所有其他进程,以及根据其他程序的请求来调整 CPU 时间和硬件访问。

15.3.1 目标与运行级别的比较

使用 System V init 时,系统引导到所谓的运行级别。运行级别定义系统如何启动以及正在运行的系统中有哪些服务可用。运行级别是有编号的;最知名的运行级别是 0(关闭系统)、3(联网的多用户模式)和 5(联网并使用显示管理器的多用户模式)。

systemd 使用所谓的目标单元引入新的概念。不过,它仍然与运行级别概念完全兼容。目标单元用名称而不是编号来标识,并具有特定的作用。例如,目标 local-fs.targetswap.target 用于挂载本地文件系统和交换空间。

目标 graphical.target 提供联网并使用显示管理器的多用户系统,作用与运行级别 5 相当。复杂目标(如 graphical.target)通过将一部分其他目标组合起来充当目标。systemd 通过组合现有目标简化了创建自定义目标的工作,从而提供了极大的灵活性。

下面的列表显示了最重要的 systemd 目标单元。有关完整列表,请参见 man 7 systemd.special

选定的 systemd 目标单元
default.target

默认引导的目标。这并不是实际目标,而是指向另一个目标(如 graphic.target)的符号链接,可通过 YaST 永久更改(请参见第 15.4 节 “使用 YaST 管理服务”)。要为某个会话更改它,请在引导提示处使用内核参数 systemd.unit=MY_TARGET.target

emergency.target

在控制台上启动紧急外壳。请仅在引导提示处按以下格式使用它:systemd.unit=emergency.target

graphical.target

启动联网的具有多用户支持和显示管理器的系统。

halt.target

关闭系统。

mail-transfer-agent.target

启动发送和接收邮件所需的所有服务。

multi-user.target

启动联网的多用户系统。

reboot.target

重新引导系统。

rescue.target

启动不联网的单用户系统。

为了与 System V init 运行级别系统保持兼容,systemd 提供了名为 runlevelX.target 的特殊目标,与编号为 X 的相应运行级别相对应。

如果您想知道当前的目标,请使用命令:systemctl get-default

表 15.3︰ System V 运行级别和 systemd 目标单元

System V 运行级别

systemd 目标

用途

0

runlevel0.targethalt.targetpoweroff.target

系统关闭

1、S

runlevel1.targetrescue.target

单用户模式

2

runlevel2.targetmulti-user.target

无远程联网的本地多用户模式

3

runlevel3.targetmulti-user.target

完整的联网多用户模式

4

runlevel4.target

未使用/用户定义

5

runlevel5.targetgraphical.target

联网并使用显示管理器的完整多用户模式

6

runlevel6.targetreboot.target

系统重引导

重要
重要:systemd 会忽略 /etc/inittab

System V init 系统中的运行级别在 /etc/inittab 中配置。systemd 使用此配置。有关如何创建您自己的可引导目标的指导,请参考第 15.5.4 节 “创建自定义目标”

15.3.1.1 用于更改目标的命令

可使用下列命令来操作目标单元:

任务

systemd 命令

System V init 命令

更改当前目标/运行级别

systemctl isolate MY_TARGET.target

telinit X

更改为默认目标/运行级别

systemctl default

获得当前目标/运行级别

systemctl list-units --type=target

对于 systemd,一般会有多个活动目标。该命令可列出当前处于活动状态的所有目标。

who -r

runlevel

永久更改默认运行级别

使用服务管理器或运行以下命令:

ln -sf /usr/lib/systemd/system/ MY_TARGET.target /etc/systemd/system/default.target

使用服务管理器或更改以下行

id: X:initdefault:

/etc/inittab 中)

更改当前引导进程的默认运行级别

在引导提示处输入以下选项

systemd.unit= MY_TARGET.target

在引导提示处输入所需的运行级别编号。

显示目标/运行级别的依赖项

systemctl show -p "Requires" MY_TARGET.target

systemctl show -p "Wants" MY_TARGET.target

Requires 会列出硬性依赖项(必须解决的依赖项),而 Wants 会列出软性依赖项(情况允许时解决的依赖项)。

15.3.2 调试系统的启动

systemd 提供了分析系统启动过程的方法。您可以查看所有服务及其状态的列表(而不必分析 /var/log/)。systemd 还允许您扫描启动过程,以了解每项服务启动用了多长时间。

15.3.2.1 查看服务的启动情况

要查看系统引导后所启动服务的完整列表,请输入命令 systemctl。该命令会列出所有活动服务,如下所示(已精简)。要获得特定服务的详细信息,请使用 systemctl status MY_SERVICE

例 15.1︰ 列出活动服务
root # systemctl
UNIT                        LOAD   ACTIVE SUB       JOB DESCRIPTION
[...]
iscsi.service               loaded active exited    Login and scanning of iSC+
kmod-static-nodes.service   loaded active exited    Create list of required s+
libvirtd.service            loaded active running   Virtualization daemon
nscd.service                loaded active running   Name Service Cache Daemon
chronyd.service             loaded active running   NTP Server Daemon
polkit.service              loaded active running   Authorization Manager
postfix.service             loaded active running   Postfix Mail Transport Ag+
rc-local.service            loaded active exited    /etc/init.d/boot.local Co+
rsyslog.service             loaded active running   System Logging Service
[...]
LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

161 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

要想只列出无法启动的服务,请使用 --failed 选项。

例 15.2︰ 列出失败的服务
root # systemctl --failed
UNIT                   LOAD   ACTIVE SUB    JOB DESCRIPTION
apache2.service        loaded failed failed     apache
NetworkManager.service loaded failed failed     Network Manager
plymouth-start.service loaded failed failed     Show Plymouth Boot Screen

[...]

15.3.2.2 调试启动时间

为了调试系统启动时间,systemd 提供了 systemd-analyze 命令。该命令会显示总启动时间及按启动时间排序的服务列表,还可以生成 SVG 图,以显示各服务相对于其他服务的启动时间。

列出系统启动时间
root # systemd-analyze
Startup finished in 2666ms (kernel) + 21961ms (userspace) = 24628ms
列出服务启动时间
root # systemd-analyze blame
    15.000s backup-rpmdb.service
    14.879s mandb.service
     7.646s backup-sysconfig.service
     4.940s postfix.service
     4.921s logrotate.service
     4.640s libvirtd.service
     4.519s display-manager.service
     3.921s btrfsmaintenance-refresh.service
     3.466s lvm2-monitor.service
     2.774s plymouth-quit-wait.service
     2.591s firewalld.service
     2.137s initrd-switch-root.service
     1.954s ModemManager.service
     1.528s rsyslog.service
     1.378s apparmor.service
    [...]
服务启动时间图
root # systemd-analyze plot > jupiter.example.com-startup.svg
Image

15.3.2.3 查看完整的启动过程

上面的命令列出了已启动的服务及其启动时间。如需更详细的概述,请在引导提示符处指定以下参数,以指示 systemd 创建完整启动过程的详细日志。

systemd.log_level=debug systemd.log_target=kmsg

现在,systemd 会将日志消息写入内核环缓冲区。使用 dmesg 查看该缓冲区:

tux > dmesg -T | less

15.3.3 System V 兼容性

systemd 与 System V 兼容,因此,您仍可以使用现有的 System V init 脚本。但是,至少有一个已知问题会导致 System V init 脚本不能立即与 systemd 配合使用:通过 init 脚本中的 susudo 以其他用户身份启动服务会导致脚本失败,生成访问被拒绝错误。

使用 susudo 更改用户时,会启动 PAM 会话。完成 init 脚本后会终止此会话。因此,init 脚本启动的服务也会终止。要解决此问题,请执行以下步骤:

  1. 创建与 init 脚本同名、扩展名为 .service 的服务文件封装程序:

    [Unit]
    Description=DESCRIPTION
    After=network.target
    
    [Service]
    User=USER
    Type=forking1
    PIDFile=PATH TO PID FILE1
    ExecStart=PATH TO INIT SCRIPT start
    ExecStop=PATH TO INIT SCRIPT stop
    ExecStopPost=/usr/bin/rm -f PATH TO PID FILE1
    
    [Install]
    WantedBy=multi-user.target2

    UPPERCASE LETTERS 中写入的所有值替换为适当的值。

    1

    可选 — 仅当 init 脚本启动守护程序时才使用。

    2

    multi-user.target 在引导进入 graphical.target 时也会启动 init 脚本。如果只应在引导进入显示管理器时才将它启动,请在此处使用 graphical.target

  2. 使用 systemctl start 应用程序启动守护程序。

15.4 使用 YaST 管理服务

基本服务管理也可以通过 YaST 服务管理器模块实现。该模块支持启动、停止、启用和禁用服务。它还可让您显示服务的状态以及更改默认目标。要启动 YaST 模块,请选择 YaST ›  系统 ›  服务管理器

服务管理器
图 15.1︰ 服务管理器
更改默认系统目标

要更改系统引导到的目标,请从默认系统目标下拉框中选择某个目标。最常用的目标是图形界面(启动图形登录屏幕)和多用户(以命令行模式启动系统)。

启动或停止服务

从表中选择一个服务。状态列显示它当前是(活动)否(非活动)正在运行。通过选择启动停止可切换其状态。

为当前正在运行的会话启动或停止服务会更改其状态。要更改服务在整个重引导过程中的状态,您需要启用或禁用服务。

定义服务启动行为

服务可以在引导时自动启动,也可以手动启动。从表中选择一个服务。启动列显示它当前是手动启动还是引导时启动。通过选择启动模式可切换其状态。

要在当前会话中更改服务状态,您需要按照上述方式启动或停止服务。

查看状态消息

要查看某个服务的状态消息,请从列表中选择该服务,然后选择显示细节。您看到的输出与 systemctl -l status MY_SERVICE 命令生成的输出完全相同。

15.5 自定义 systemd

以下几节介绍了 systemd 自定义的一些示例。

警告
警告:防止您的自定义被覆盖

在自定义 systemd 时,请务必使用目录 /etc/systemd/切勿使用 /usr/lib/systemd/。否则,您的更改将在 systemd 下次更新时被覆盖。

15.5.1 自定义单元文件

建议使用 systemctl edit SERVICE 命令来自定义单元文件。此命令会启动默认的文本编辑器,并创建一个在 /etc/systemd/system/NAME.service.d/ 中包含 override.conf 文件的目录。该命令还确保会向正在运行的 systemd 进程通知这些更改。

或者,您可以通过运行 systemctl edit --full SERVICE 打开原始文件的副本进行编辑,而不是打开空白文件。编辑文件时,请确保未去除任何现有部分。

下面将练习如何更改系统等待 MariaDB 启动的时间。以 root 身份运行 systemctl edit --full mariadb.service。打开的文件如下所示:

[Unit]
Description=MySQL server
Wants=basic.target
Conflicts=mariadb.target
After=basic.target network.target

[Install]
WantedBy=multi-user.target
Alias=mysql.service

[Service]
Restart=on-abort
Type=notify
ExecStartPre=/usr/lib/mysql/mysql-systemd-helper  install
ExecStartPre=/usr/lib/mysql/mysql-systemd-helper  upgrade
ExecStart=/usr/lib/mysql/mysql-systemd-helper     start

# Configures the time to wait for start-up/stop
TimeoutSec=300

# Prevent writes to /usr, /boot, and /etc
ProtectSystem=full

# Prevent accessing /home, /root and /run/user
ProtectHome=true

UMask=007

调整 TimeoutSec 值并保存更改。要启用更改,请以 root 身份运行 systemctl daemon-reload

有关详细信息,请参考可使用 man 1 systemctl 命令调用的手册页。

15.5.2 创建插入式文件

要对配置文件进行细微更改,请使用所谓的插入式文件。使用插入式文件,您无需编辑或覆盖单元文件本身,即可扩展单元文件的配置。

例如,要更改位于 /usr/lib/systemd/system/FOOBAR.SERVICEFOOBAR 服务的单个值,请按以下步骤操作:

  1. 创建名为 /etc/systemd/system/FOOBAR.service.d/ 的目录。

    注意 .d 后缀。该目录必须命名为与要用插入式文件修补的服务相似的名称。

  2. 在该目录中,创建 your_modification.conf 文件。

    确保文件中仅包含要修改的值所在的那一行。

  3. 将更改保存到 文件中。

注意
注意:避免名称冲突

为避免插入式文件与 SUSE 自带的文件之间出现名称冲突,建议在所有插入式文件名前加上一个两位数和一个短划线:例如,80-override.conf

以下范围为预留值范围:

  • 0-19,为 systemd 上游预留

  • 20-25,为 SUSE 自带的 systemd 预留

  • 26-29,为 SUSE 软件包(systemd 除外)预留

  • 50,为使用 systemctl set-property 创建的插入式文件预留

请使用大于此范围的两位数,以确保 SUSE 自带的任何插入式文件都不会覆盖您自己的插入式文件。

您可以使用 systemctl cat $UNIT 来列出并校验哪些文件考虑纳入单元配置。

15.5.3 xinetd 服务转换为 systemd

SUSE Linux Enterprise Server 15 版本开始,去除了 xinetd 基础架构。本节概述如何将现有的自定义 xinetd 服务文件转换为 systemd 套接字。

对于每个 xinetd 服务文件,您至少要有两个 systemd 单元文件:套接字文件 (*.socket) 和关联的服务文件 (*.service)。套接字文件告诉 systemd 要创建哪个套接字,服务文件告诉 systemd 要启动哪个可执行文件。

以下面的 xinetd 服务文件为例:

root # cat /etc/xinetd.d/example
service example
{
  socket_type = stream
  protocol = tcp
  port = 10085
  wait = no
  user = user
  group = users
  groups = yes
  server = /usr/libexec/example/exampled
  server_args = -auth=bsdtcp exampledump
  disable = no
}

要将它转换为 systemd,需要下面两个配套的文件:

root # cat /usr/lib/systemd/system/example.socket
[Socket]
ListenStream=0.0.0.0:10085
Accept=false

[Install]
WantedBy=sockets.target
root # cat /usr/lib/systemd/system/example.service
[Unit]
Description=example

[Service]
ExecStart=/usr/libexec/example/exampled -auth=bsdtcp exampledump
User=user
Group=users
StandardInput=socket

有关 systemd 的“套接字”和“服务”文件选项的完整列表,请参见 systemd.socket 和 systemd.service 手册页(man 5 systemd.socketman 5 systemd.service)。

15.5.4 创建自定义目标

System V init SUSE 系统上未使用运行级别 4,以便允许管理员创建自己的运行级别配置。systemd 允许您创建任意数目的自定义目标。建议您从采用 graphical.target 等现有目标开始。

  1. 将配置文件 /usr/lib/systemd/system/graphical.target 复制到 /etc/systemd/system/MY_TARGET.target,并根据需要调整该文件。

  2. 上一步中复制的配置文件已涵盖目标的必要(硬性)依赖项。如果还要涵盖需要的(软性)依赖项,请创建目录 /etc/systemd/system/MY_TARGET.target.wants

  3. 对每个需要的服务,创建从 /usr/lib/systemd/system 链到 /etc/systemd/system/MY_TARGET.target.wants 的符号链接。

  4. 设置好目标后,重新装载 systemd 配置以使新目标可用:

    tux > sudo systemctl daemon-reload

15.6 高级用法

以下几节介绍了适合系统管理员的高级主题。有关更高级的 systemd 文档,请参考 Lennart Pöttering 撰写的适用于管理员的 systemd 相关系列,网址为 http://0pointer.de/blog/projects

15.6.1 清理临时目录

systemd 支持定期清理临时目录。将会自动迁移并激活前一系统版本中的配置。tmpfiles.d(负责管理临时文件)将从 /etc/tmpfiles.d/*.conf/run/tmpfiles.d/*.conf/usr/lib/tmpfiles.d/*.conf 文件中读取其配置。/etc/tmpfiles.d/*.conf 中的配置将覆盖其他两个目录中的相关配置(/usr/lib/tmpfiles.d/*.conf 是软件包用于储存其配置文件的位置)。

配置格式为每个路径一行,该行包含操作与路径、(可选)模式、所有权、期限和参数字段,具体取决于操作。以下示例将取消链接 X11 锁定文件:

Type Path               Mode UID  GID  Age Argument
r    /tmp/.X[0-9]*-lock

要获取 tmpfile 计时器的状态:

tux > sudo systemctl status systemd-tmpfiles-clean.timer
systemd-tmpfiles-clean.timer - Daily Cleanup of Temporary Directories
 Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-clean.timer; static)
 Active: active (waiting) since Tue 2018-04-09 15:30:36 CEST; 1 weeks 6 days ago
   Docs: man:tmpfiles.d(5)
         man:systemd-tmpfiles(8)

Apr 09 15:30:36 jupiter systemd[1]: Starting Daily Cleanup of Temporary Directories.
Apr 09 15:30:36 jupiter systemd[1]: Started Daily Cleanup of Temporary Directories.

有关处理临时文件的详细信息,请参见 man 5 tmpfiles.d

15.6.2 系统日志

第 15.6.9 节 “调试服务” 介绍如何查看给定服务的日志消息。但可显示的日志消息并不仅限于服务日志。您还可以访问和查询 systemd 写入的完整日志,即所谓的日志。使用 journalctl 命令可显示完整的日志消息,从最早的项开始。有关诸如应用过滤器或更改输出格式的选项,请参考 man 1 journalctl

15.6.3 快照

您可以使用 isolate 子命令将 systemd 的当前状态保存到指定快照中,并在日后还原到该状态。此功能在测试服务或自定义目标时非常有用,因为它可让您随时回到定义的状态。快照仅在当前会话中可用,重引导时将自动删除。快照名称必须以 .snapshot 结尾。

创建快照
tux > sudo systemctl snapshot MY_SNAPSHOT.snapshot
删除快照
tux > sudo systemctl delete MY_SNAPSHOT.snapshot
查看快照
tux > sudo systemctl show MY_SNAPSHOT.snapshot
激活快照
tux > sudo systemctl isolate MY_SNAPSHOT.snapshot

15.6.4 装载内核模块

通过使用 systemd 以及 /etc/modules-load.d 中的配置文件,可以在引导时自动装载内核模块。该文件应该命名为 MODULE.conf 并包含以下内容:

# load module MODULE at boot time
MODULE

如果某个软件包安装了用于装载内核模块的配置文件,该文件将安装到 /usr/lib/modules-load.d。如果存在两个同名的配置文件,将优先使用 /etc/modules-load.d 中的那个配置文件。

有关详细信息,请参见 modules-load.d(5) 手册页。

15.6.5 装载服务之前执行操作

使用 System V init 时,需要在装载服务之前执行的操作必须在 /etc/init.d/before.local 中指定。systemd 不再支持此过程。如果您需要在启动服务之前执行操作,请执行以下步骤:

装载内核模块

/etc/modules-load.d 目录中创建一个 drop-in 文件(有关语法,请参见 man modules-load.d

创建文件或目录、清理目录、更改所有权

/etc/tmpfiles.d 中创建一个 drop-in 文件(有关语法,请参见 man tmpfiles.d

其他任务

基于下面的模板创建一个系统服务文件,例如 /etc/systemd/system/before.service

[Unit]
Before=NAME OF THE SERVICE YOU WANT THIS SERVICE TO BE STARTED BEFORE
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=YOUR_COMMAND
# beware, executable is run directly, not through a shell, check the man pages
# systemd.service and systemd.unit for full syntax
[Install]
# target in which to start the service
WantedBy=multi-user.target
#WantedBy=graphical.target

创建服务文件后,应运行以下命令(以 root 身份):

tux > sudo systemctl daemon-reload
tux > sudo systemctl enable before

每次修改服务文件时,都需要运行:

tux > sudo systemctl daemon-reload

15.6.6 内核控制组 (cgroup)

在传统 System V init 系统上,并不总是能够明确地将某个进程指派给生成它的服务。一些服务(例如 Apache)会生成大量第三方进程(例如 CGI 或 Java 进程),这些进程本身又会生成更多进程。这使得明确指派变得非常困难,甚至无法做到。另外,服务可能不会正常终止,导致部分子服务仍保持运行状态。

systemd 通过将每个服务放入它自己的 cgroup 中,解决了这个问题。cgroups 是一项内核功能,允许将进程及其所有子进程聚合到分层组织的组中。systemd 根据每个 cgroup 的服务名称命名各 cgroup。因为非特权进程不允许离开它的 cgroup,这提供了一种行之有效的方式,可通过服务名称来标记该服务生成的所有进程。

要列出属于某个服务的所有进程,请使用命令 systemd-cgls。结果将如下所示(已精简):

例 15.3︰ 列出属于某个服务的所有进程
root # systemd-cgls --no-pager
├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 20
├─user.slice
│ └─user-1000.slice
│   ├─session-102.scope
│   │ ├─12426 gdm-session-worker [pam/gdm-password]
│   │ ├─15831 gdm-session-worker [pam/gdm-password]
│   │ ├─15839 gdm-session-worker [pam/gdm-password]
│   │ ├─15858 /usr/lib/gnome-terminal-server

[...]

└─system.slice
  ├─systemd-hostnamed.service
  │ └─17616 /usr/lib/systemd/systemd-hostnamed
  ├─cron.service
  │ └─1689 /usr/sbin/cron -n
  ├─postfix.service
  │ ├─ 1676 /usr/lib/postfix/master -w
  │ ├─ 1679 qmgr -l -t fifo -u
  │ └─15590 pickup -l -t fifo -u
  ├─sshd.service
  │ └─1436 /usr/sbin/sshd -D

[...]

有关 cgroups 的更多信息,请参见第 9 章 “内核控制组

15.6.7 终止服务(发送信号)

第 15.6.6 节 “内核控制组 (cgroup)”中所述,在 System V init 系统中,并不总是能够将某个进程指派给其父服务。这导致终止服务及其所有子进程变得很困难。尚未终止的子进程将一直保持为僵停状态。

systemd 的概念是将每个服务限定在某个 cgroup 中,从而可以明确识别一个服务的所有子进程,因此可让您将信号发送到这些进程中的每一个进程。您可使用 systemctl kill 向服务发送信号。有关可用信号的列表,请参考 man 7 signals

向服务发送 SIGTERM

SIGTERM 是发送的默认信号。

tux > sudo systemctl kill MY_SERVICE
向服务发送 SIGNAL

可使用 -s 选项指定应该发送的信号。

tux > sudo systemctl kill -s SIGNAL MY_SERVICE
选择进程

默认情况下,kill 命令会向指定 cgroup 的所有进程发送信号。您可以将发送范围限制为 controlmain 进程。后一个选项可用于通过发送 SIGHUP 强制服务重新装载其配置的情况:

tux > sudo systemctl kill -s SIGHUP --kill-who=main MY_SERVICE

15.6.8 有关 D-Bus 服务的重要说明

D-Bus 服务是 systemd 客户端与作为 pid 1 运行的 systemd 管理器之间进行通讯的消息总线。虽然 dbus 是个独立的守护程序,但它也是 init 基础架构的组成部分。

在正在运行的系统中终止或重启动 dbus 的效果类似于尝试终止或重启动 pid 1。此操作将中断 systemd 客户端与服务器间的通讯,并使大部分 systemd 功能不可用。

因此,不建议也不支持终止或重启动 dbus

更新 dbus 或与 dbus 有关的软件包需要重引导。如果不确定是否需要重引导,请运行 sudo zypper ps -s。如果 dbus 显示在所列服务之中,则表明您需要重引导系统。

请记住,即使自动更新配置为跳过需要重引导的软件包,dbus 仍会更新。

15.6.9 调试服务

默认情况下,systemd 的输出不会太详细。如果服务启动成功,则不会产生任何输出。如果服务启动失败,则会显示简短的错误消息。不过,systemctl status 提供了调试服务的启动和操作的途径。

systemd 附带了自己的日志记录机制(日志)来记录系统消息。这可让您一并显示服务消息与状态消息。status 命令的工作方式与 tail 相似,也可以采用不同的格式显示日志消息,是一个功能强大的调试工具。

显示服务启动失败消息

每当服务启动失败时,使用 systemctl status MY_SERVICE 可获得详细的错误消息:

root # systemctl start apache2
Job failed. See system journal and 'systemctl status' for details.
root # systemctl status apache2
   Loaded: loaded (/usr/lib/systemd/system/apache2.service; disabled)
   Active: failed (Result: exit-code) since Mon, 04 Apr 2018 16:52:26 +0200; 29s ago
   Process: 3088 ExecStart=/usr/sbin/start_apache2 -D SYSTEMD -k start (code=exited, status=1/FAILURE)
   CGroup: name=systemd:/system/apache2.service

Apr 04 16:52:26 g144 start_apache2[3088]: httpd2-prefork: Syntax error on line
205 of /etc/apache2/httpd.conf: Syntax error on li...alHost>
显示最后 N 条服务消息

status 子命令的默认行为是显示服务发出的最后 10 条消息。若要更改要显示的消息数目,请使用 --lines=N 参数:

tux > sudo systemctl status chronyd
tux > sudo systemctl --lines=20 status chronyd
以附加模式显示服务消息

要显示服务消息的实时流,请使用 --follow 选项,效果与 tail -f 相似:

tux > sudo systemctl --follow status chronyd
消息输出格式

--output=模式参数可让您更改服务消息的输出格式。最重要的可用模式包括:

short

默认格式。显示日志消息,以及用户能看懂的时戳。

verbose

所有字段的完整输出。

cat

精简输出,不含时戳。

15.7 systemd 计时器单元

与 cron 类似,systemd 计时器单元提供了一种在 Linux 上安排作业的机制。虽然 systemd 计时器单元的用途与 cron 相同,但其具备几项优点。

  • 使用计时器单元安排的作业可以依赖其他 systemd 服务。

  • 计时器单元被视为常规 systemd 服务,因此可以使用 systemctl 进行管理。

  • 计时器可以是实时计时器,也可以是单调计时器。

  • 时间单元会被记录到 systemd 日志中,使得更易于监视和查错。

systemd 计时器单元通过 .timer 文件扩展名标识。

15.7.1 systemd 计时器类型

计时器单元可以使用单调和实时计时器。

  • 与 cron 作业类似,实时计时器是根据日历事件触发的。实时计时器使用选项 OnCalendar 进行定义。

  • 单调计时器将从某个特定起点开始经过指定时间后触发。后者可以是系统引导或系统单元激活事件。有几个选项可用于定义单调计时器,包括 OnBootSecOnUnitActiveSecOnTypeSec。单调计时器不是永久的,每次重引导后都将被重置。

15.7.2 systemd 计时器和服务单元

每个计时器单元都必须有一个其所控制的对应 systemd 单元文件。也就是说,将由 .timer 文件激活并管理对应的 .service 文件。使用计时器时,.service 文件不需要 [Install] 部分,因为服务将由计时器管理。

15.7.3 具体示例

为了理解 systemd 计时器单元的基本知识,我们设置了一个触发 foo.sh 外壳脚本的计时器。

第一步是创建用于控制外壳脚本的 systemd 服务单元。为此,请打开一个新的文本文件进行编辑,并添加以下服务单元定义:

[Unit]
Description="Foo shell script"

[Service]
ExecStart=/usr/local/bin/foo.sh

将文件以名称 foo.service 保存到目录 /etc/systemd/system/ 中。

接下来,打开一个新的文本文件进行编辑,并添加以下计时器定义:

[Unit]
Description="Run foo shell script"

[Timer]
OnBootSec=5min
OnUnitActiveSec=24h
Unit=foo.service

[Install]
WantedBy=multi-user.target

上述示例中的 [Timer] 部分指定了要触发的服务 (foo.service) 以及触发时间。在本例中,选项 OnBootSec 指定了一个在系统引导后五分钟触发服务的单调计时器,而选项 OnUnitActiveSec 会在服务被激活后 24 小时触发服务(即计时器将每天触发一次服务)。最后,选项 WantedBy 指定应在系统达到多用户目标时启动计时器。

您也可以不指定单调计时器,而是使用选项 OnCalendar 指定实时计时器。下面的实时计时器定义从星期一 12:00 开始,每周触发一次相关服务单元。

[Timer]
OnCalendar=weekly
Persistent=true

选项 Persistent=true 表示如果计时器错过了上一次启动时间(例如,由于系统关闭),则会在计时器激活后立即触发服务。

选项 OnCalendar 还可以用于使用以下格式来定义触发服务的具体日期和时间:DayOfWeek Year-Month-Day Hour:Minute:Second。下面的示例会在每天早上 5 点触发服务:

OnCalendar=*-*-* 5:00:00

您可以使用星号指定任何值,使用逗号列出可能的值。使用由 .. 分隔的两个值可表示一个连续的范围。下面的示例会在每个月的星期五下午 6 点触发服务:

OnCalendar=Fri *-*-1..7 18:00:00

要在不同的时间触发服务,您可以指定多个 OnCalendar 项:

OnCalendar=Mon..Fri 10:00
OnCalendar=Sat,Sun 22:00

在上面的示例中,会在工作日的上午 10 点和周末的晚上 10 点触发服务。

编辑好计时器单元文件后,使用名称 foo.timer 将其保存到 /etc/systemd/system/ 目录中。要检查所创建的单元文件是否正确,请运行以下命令:

tux > sudo  systemd-analyze verify /etc/systemd/system/foo.*

如果命令未返回任何输出,则表示文件成功通过了校验。

要启动计时器,请使用命令 sudo systemctl start foo.timer。要在引导时启用计时器,请运行命令 sudo systemctl enable foo.timer

15.7.4 管理 systemd 计时器

由于计时器被视为常规 systemd 单元,因此您可以使用 systemctl 来管理它们。您可以使用 systemctl start 启动计时器,使用 systemctl enable 启用计时器,依此类推。除此之外,您还可以使用命令 systemctl list-timers 列出所有活动计时器。要列出包括非活动计时器在内的所有计时器,请运行命令 systemctl list-timers --all

15.8 更多信息

有关 systemd 的详细信息,请参考以下联机资源:

主页

http://www.freedesktop.org/wiki/Software/systemd

适用于管理员的 systemd

Lennart Pöttering 是 systemd 的作者之一,他撰写了一系列博客文章(写本章时已有 13 篇)。它们可在 http://0pointer.de/blog/projects 找到。