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 脚本、insserv
、telinit
及其他。systemd
可简化服务管理,因为对于大部分处理服务的任务,只需要记住一条命令:systemctl
。它使用“命令加子命令”表示法,与 git
或 zypper
相似:
systemctl GENERAL OPTIONS SUBCOMMAND SUBCOMMAND OPTIONS
有关完整的手册,请参见 man 1 systemctl
。
如果输出传递到某个终端(而不是某个管道或文件),systemd
命令默认会将长输出发送到分页器。使用 --no-pager
选项可关闭分页模式。
systemd
还支持 bash 补全,允许您输入子命令的头几个字母,然后按 →|。此功能只能在 bash
外壳中使用,并且需要安装 bash-completion
软件包。
15.2.1 管理正在运行的系统中的服务 #
用于管理服务的子命令与使用 System V init 管理服务的子命令相同(start
、stop
等)。服务管理命令的一般语法如下所示:
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 最重要的服务管理命令:
任务 |
|
System V init 命令 |
---|---|---|
启动: |
start |
start |
停止: |
stop |
stop |
重启动: 关闭服务,然后再启动这些服务。如果某项服务尚未运行,它将会启动。 |
restart |
restart |
有条件地重启动: 如果服务当前正在运行,则重启动它们。对未在运行的服务不执行任何操作。 |
try-restart |
try-restart |
重新装载:
让服务在不中断操作的情况下重新装载它们的配置文件。使用案例:让 Apache 重新装载修改过的 |
reload |
reload |
重新装载或重启动: 如果支持重新装载则重新装载服务,否则重启动服务。如果某项服务尚未运行,它将会启动。 |
reload-or-restart |
n/a |
有条件地重新装载或重启动: 如果支持重新装载则重新装载服务,否则,如果服务当前正在运行,则重启动服务。对未在运行的服务不执行任何操作。 |
reload-or-try-restart |
n/a |
获得详细的状态信息:
列出服务状态的相关信息。 |
status |
status |
获得简要的状态信息: 显示服务是否处于活动状态。 |
is-active |
status |
15.2.2 永久启用/禁用服务 #
上一节中提到的服务管理命令可让您操控当前会话的服务。systemd 还允许您永久启用或禁用服务,让它们在用户要求时自动启动或永远不可用。
您可以使用 YaST 或在命令行上运行命令来实现此目的。
15.2.2.1 在命令行上启用/禁用服务 #
下表列出了 systemd
和 System V init 用于启用和禁用服务的命令:
在命令行上启用服务时,服务不会自动启动。它会安排在下一次系统启动或运行级别/目标发生更改时启动。要在启用服务之后立即启动它,请显式运行 systemctl start MY_SERVICE
或 rc MY_SERVICE start
。
任务 |
|
System V init 命令 |
---|---|---|
启用: |
|
|
禁用: |
|
|
检查: 显示某项服务是否启用。 |
|
|
重新启用: 与重启动服务相似,此命令先禁用服务,然后再启用该服务。可用来使用默认值重新启用服务。 |
|
无 |
屏蔽: “禁用”某项服务之后,仍然可以手动启动它。要彻底禁用服务,您需要屏蔽它。须谨慎使用该功能。 |
|
无 |
取消屏蔽: 屏蔽某项服务之后,只有在将其取消屏蔽之后才能再次使用它。 |
|
无 |
15.3 系统启动和目标管理 #
启动和关闭系统的整个过程由 systemd
负责维护。从这一点来看,可以将内核视为一个后台进程,其任务是维护所有其他进程,以及根据其他程序的请求来调整 CPU 时间和硬件访问。
15.3.1 目标与运行级别的比较 #
使用 System V init 时,系统引导到所谓的“运行级别”。运行级别定义系统如何启动以及正在运行的系统中有哪些服务可用。运行级别是有编号的;最知名的运行级别是 0
(关闭系统)、3
(联网的多用户模式)和 5
(联网并使用显示管理器的多用户模式)。
systemd
使用所谓的“目标单元”引入新的概念。不过,它仍然与运行级别概念完全兼容。目标单元用名称而不是编号来标识,并具有特定的作用。例如,目标 local-fs.target
和 swap.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
systemd
目标单元 #
System V 运行级别 |
|
用途 |
---|---|---|
0 |
|
系统关闭 |
1、S |
|
单用户模式 |
2 |
|
无远程联网的本地多用户模式 |
3 |
|
完整的联网多用户模式 |
4 |
|
未使用/用户定义 |
5 |
|
联网并使用显示管理器的完整多用户模式 |
6 |
|
系统重引导 |
systemd
会忽略 /etc/inittab
System V init 系统中的运行级别在 /etc/inittab
中配置。systemd 不使用此配置。有关如何创建您自己的可引导目标的指导,请参考第 15.5.4 节 “创建自定义目标”。
15.3.1.1 用于更改目标的命令 #
可使用下列命令来操作目标单元:
任务 |
|
System V init 命令 |
---|---|---|
更改当前目标/运行级别 |
|
|
更改为默认目标/运行级别 |
|
无 |
获得当前目标/运行级别 |
对于 |
或
|
永久更改默认运行级别 |
使用服务管理器或运行以下命令:
|
使用服务管理器或更改以下行
( |
更改当前引导进程的默认运行级别 |
在引导提示处输入以下选项
|
在引导提示处输入所需的运行级别编号。 |
显示目标/运行级别的依赖项 |
“Requires” 会列出硬性依赖项(必须解决的依赖项),而 “Wants” 会列出软性依赖项(情况允许时解决的依赖项)。 |
无 |
15.3.2 调试系统的启动 #
systemd 提供了分析系统启动过程的方法。
您可以查看所有服务及其状态的列表(而不必分析 /var/log/
)。systemd 还允许您扫描启动过程,以了解每项服务启动用了多长时间。
15.3.2.1 查看服务的启动情况 #
要查看系统引导后所启动服务的完整列表,请输入命令 systemctl
。该命令会列出所有活动服务,如下所示(已精简)。要获得特定服务的详细信息,请使用 systemctl status MY_SERVICE
。
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
选项。
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
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 脚本中的 su
或 sudo
以其他用户身份启动服务会导致脚本失败,生成“访问被拒绝”错误。
使用 su
或 sudo
更改用户时,会启动 PAM 会话。完成 init 脚本后会终止此会话。因此,init 脚本启动的服务也会终止。要解决此问题,请执行以下步骤:
创建与 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 中写入的所有值替换为适当的值。
使用
systemctl start 应用程序
启动守护程序。
15.4 使用 YaST 管理服务 #
基本服务管理也可以通过 YaST 服务管理器模块实现。该模块支持启动、停止、启用和禁用服务。它还可让您显示服务的状态以及更改默认目标。要启动 YaST 模块,请选择
› › 。- 更改
要更改系统引导到的目标,请从
下拉框中选择某个目标。最常用的目标是 (启动图形登录屏幕)和 (以命令行模式启动系统)。- 启动或停止服务
从表中选择一个服务。
列显示它当前是( )否( )正在运行。通过选择 或 可切换其状态。为当前正在运行的会话启动或停止服务会更改其状态。要更改服务在整个重引导过程中的状态,您需要启用或禁用服务。
- 定义服务启动行为
服务可以在引导时自动启动,也可以手动启动。从表中选择一个服务。
列显示它当前是 启动还是 启动。通过选择 可切换其状态。要在当前会话中更改服务状态,您需要按照上述方式启动或停止服务。
- 查看状态消息
要查看某个服务的状态消息,请从列表中选择该服务,然后选择
。您看到的输出与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.SERVICE
中 FOOBAR 服务的单个值,请按以下步骤操作:
创建名为
/etc/systemd/system/FOOBAR.service.d/
的目录。注意
.d
后缀。该目录必须命名为与要用插入式文件修补的服务相似的名称。在该目录中,创建
your_modification.conf
文件。确保文件中仅包含要修改的值所在的那一行。
将更改保存到 文件中。
为避免插入式文件与 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.socket
、man 5 systemd.service
)。
15.5.4 创建自定义目标 #
System V init SUSE 系统上未使用运行级别 4,以便允许管理员创建自己的运行级别配置。systemd 允许您创建任意数目的自定义目标。
建议您从采用 graphical.target
等现有目标开始。
将配置文件
/usr/lib/systemd/system/graphical.target
复制到/etc/systemd/system/MY_TARGET.target
,并根据需要调整该文件。上一步中复制的配置文件已涵盖目标的必要(“硬性”)依赖项。如果还要涵盖需要的(“软性”)依赖项,请创建目录
/etc/systemd/system/MY_TARGET.target.wants
。对每个需要的服务,创建从
/usr/lib/systemd/system
链到/etc/systemd/system/MY_TARGET.target.wants
的符号链接。设置好目标后,重新装载
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-reloadtux >
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
。结果将如下所示(已精简):
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 的所有
进程发送信号。您可以将发送范围限制为control
或main
进程。后一个选项可用于通过发送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 chronydtux >
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
进行定义。单调计时器将从某个特定起点开始经过指定时间后触发。后者可以是系统引导或系统单元激活事件。有几个选项可用于定义单调计时器,包括
OnBootSec
、OnUnitActiveSec
和OnTypeSec
。单调计时器不是永久的,每次重引导后都将被重置。
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
的详细信息,请参考以下联机资源:
- 主页
- 适用于管理员的
systemd
Lennart Pöttering 是
systemd
的作者之一,他撰写了一系列博客文章(写本章时已有 13 篇)。它们可在 http://0pointer.de/blog/projects 找到。