
systemd 守护程序
systemd 程序是进程 ID 为 1 的进程。它负责以所需的方式初始化系统。systemd 由内核直接启动,信号 9(该信号通常会终止进程)对它不起作用。所有其他程序都由 systemd 直接启动,或由它的其中一个子进程启动。
从 SUSE Linux Enterprise Desktop 12 起,systemd 取代了常用的 System V init 守护程序。systemd 与 System V init 完全兼容(通过支持 init 脚本实现)。systemd 的其中一个主要优点是可通过激进方式并行启动多项服务来大幅加快引导速度。另外,systemd 只在确实有需要时才会启动服务。守护程序并不是在系统引导时无条件地启动,而是在第一次需要时启动。systemd 还支持内核控制组 (cgroups),以拍摄系统状态快照以及恢复系统状态等等。有关详细信息,请参见http://www.freedesktop.org/wiki/Software/systemd/。
本节将详细介绍有关 systemd 的概念。
systemd 是适用于 Linux 的系统和会话管理器,它与 System V 及 LSB init 脚本兼容。主要功能包括:
提供激进式并行化功能
使用套接字及 D-Bus 激活来启动服务
提供按需启动守护程序功能
使用 Linux cgroups 跟踪进程
支持拍摄系统状态快照及恢复系统状态
维护安装点和自动安装点
实施精细的、基于事务依赖性的服务控制逻辑
单元配置文件会对有关以下项目的信息进行编码:服务、套接字、设备、安装点、自动安装点、交换文件或分区、启动目标、监控的文件系统路径、受 systemd 控制和监管的计时器、临时系统状态快照、资源管理部分或一组外部创建的进程。“单元文件”是 systemd 用于描述下列各项的通用术语:
服务. 进程相关信息(例如运行守护程序);文件以 .service 结尾
目标. 用于将单元分组以及在启动期间用作同步点;文件以 .target 结尾
套接字.
IPC 或网络套接字或文件系统 FIFO 相关信息,适用于基于套接字的激活(如 inetd);文件以 .socket 结尾
路径. 用于触发其他单元(例如,在文件更改时运行服务);文件以 .path 结尾
计时器. 受控制计时器相关信息,适用于基于计时器的激活;文件以 .timer 结尾
装入点. 通常由 fstab 生成器自动生成;文件以 .mount 结尾
自动安装点. 文件系统自动安装点相关信息;文件以 .automount 结尾
Swap. 内存分页的交换设备或文件相关信息;文件以 .swap 结尾
设备. sysfs/udev(7) 设备树中公开的设备相关信息;文件以 .device 结尾
范围/部分. 有关分层管理一组进程的资源的概念;文件以 .scope/.slice 结尾
有关 systemd.unit 的更多信息,请参见http://www.freedesktop.org/software/systemd/man/systemd.unit.html
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 包。
用于管理服务的子命令与使用 System V init 管理服务的子命令相同(start、stop 等)。服务管理命令的一般语法如下所示:
systemctl reload|restart|start|status|stop|... <my_service(s)>.service
rc<my_service(s)> reload|restart|start|status|stop|...
systemd 允许您一次管理多个服务。不用像 System V init 要逐个执行 init 脚本,而是执行如下命令:
systemctl start <my_1st_service>.service <my_2nd_service>.service
如果您要列出系统上所有可用的服务:
systemctl list-unit-files --type=service
下表列出了 systemd 和 System V init 最重要的服务管理命令:
|
任务 |
systemd 命令 |
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 |
上一节中提到的服务管理命令可让您操控当前会话的服务。systemd 还允许您永久启用或禁用服务,让它们在用户要求时自动启动或永远不可用。您可以使用 YaST 或在命令行上运行命令来实现此目的。
下表列出了 systemd 和 System V init 用于启用和禁用服务的命令:
在命令行上启用服务时,服务不会自动启动。它会安排在下一次系统启动或运行级别/目标发生更改时启动。要在启用服务之后立即启动它,请明确运行 systemctl start <我的服务>.service 或 rc<我的服务> start。
|
任务 |
|
System V init 命令 |
|---|---|---|
|
启用. |
|
|
|
禁用. |
|
|
|
检查. 显示某项服务是否启用。 |
|
无 |
|
重新启用. 与重启动服务相似,此命令先禁用服务,然后再启用该服务。可用来使用默认值重新启用服务。 |
|
无 |
|
屏蔽. “禁用”某项服务之后,仍然可以手动启动它。要彻底禁用服务,您需要屏蔽它。须谨慎使用该功能。 |
|
无 |
|
取消屏蔽. 屏蔽某项服务之后,只有在将其取消屏蔽之后才能再次使用它。 |
|
无 |
启动和关闭系统的整个过程由 systemd 负责维护。从这一点来看,可以将内核视为一个后台进程,其任务是维护所有其他进程,以及根据其他程序的请求来调整 CPU 时间和硬件访问。
使用 System V init 时,系统引导到所谓的“运行级别”。运行级别定义系统如何启动以及正在运行的系统中有哪些服务可用。运行级别是有编号的;最知名的运行级别是 0(关闭系统)、3(联网的多用户模式)和 5(联网并使用显示管理器的多用户模式)。
systemd 使用所谓的“目标单元”引入新的概念。不过,它仍然与运行级别概念完全兼容。目标单元用名称而不是编号来标识,并具有特定的作用。例如,目标 local-fs.target 和 swap.target 用于装入本地文件系统和交换空间。
目标 graphical.target 提供联网并使用显示管理器的多用户系统,作用与运行级别 5 相当。复杂目标(如 graphical.target)通过将一部分其他目标组合起来充当“元”目标。systemd 通过组合现有目标简化了创建自定义目标的工作,从而提供了极大的灵活性。
下面的列表显示了最重要的 systemd 目标单元。有关完整列表,请参见 man 7 systemd.special。
default.target
默认引导的目标。这并不是“实际”目标,而是指向另一个目标(如 graphic.target)的符号链接,可通过 YaST 永久更改(请参见第 11.4 节 “使用 YaST 管理 服务”)。要为某个会话更改它,请在引导提示处使用内核命令行选项 systemd.unit=<我的目标>.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 |
|
系统重引导 |
/etc/inittab
System V init 系统中的运行级别在 /etc/inittab 中配置。systemd 不使用此配置。有关如何创建您自己的可引导目标的指导,请参考第 11.5.3 节 “创建自定义目标”。
可使用下列命令来操作目标单元:
|
任务 |
systemd 命令 |
System V init 命令 |
|---|---|---|
|
更改当前目标/运行级别 |
|
|
|
更改为默认目标/运行级别 |
|
无 |
|
获得当前目标/运行级别 |
使用 systemd 时,一般会有多个活动目标。该命令可列出当前处于活动状态的所有目标。 |
或者
|
|
永久更改默认运行级别 |
使用服务管理器或运行以下命令:
|
使用服务管理器或更改以下行
( |
|
更改当前引导进程的默认运行级别 |
在引导提示处输入以下选项
|
在引导提示处输入所需的运行级别编号。 |
|
显示目标/运行级别的依赖性 |
“Requires” 会列出硬性依赖性(必须解决的依赖性),而 “Wants” 会列出软性依赖性(情况允许时解决的依赖性)。 |
无 |
systemd 提供了分析系统启动过程的方法。您可以方便地查看所有服务及其状态的列表(而不必分析 /varlog/)。systemd 还允许您扫描启动过程,以了解每项服务启动用了多长时间。
要查看系统引导后所启动服务的完整列表,请输入命令 systemctl。该命令会列出所有活动服务,如下所示(已精简)。要获得特定服务的更多信息,请使用 systemctl status <我的服务>.service。
root # systemctl
UNIT LOAD ACTIVE SUB JOB DESCRIPTION
[...]
systemd-random-seed-load.path loaded active waiting Random Seed
acpid.service loaded active running ACPI Event Daemon
apache2.service loaded failed failed apache
avahi-daemon.service loaded active running Avahi mDNS/DNS-SD Stack
bluez-coldplug.service loaded active exited LSB: handles udev coldplug of bluetooth dongles
console-kit...-system-start.service loaded active exited Console System Startup Logging
cron.service loaded active running Command Scheduler
cups.service loaded active running CUPS Printing 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.
JOB = Pending job for the unit.
107 units listed. Pass --all to see inactive units, too.
要想只列出无法启动的服务,请使用 --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
[...]
为了调试系统启动时间,systemd 提供了 systemd-analyze 命令。该命令会显示总启动时间及按启动时间排序的服务列表,还可以生成 SVG 图,以显示各服务相对于其他服务的启动时间。
root # systemd-analyze
Startup finished in 2666ms (kernel) + 21961ms (userspace) = 24628msroot # systemd-analyze blame
6472ms systemd-modules-load.service
5833ms remount-rootfs.service
4597ms network.service
4254ms systemd-vconsole-setup.service
4096ms postfix.service
2998ms xdm.service
2483ms localnet.service
2470ms SuSEfirewall2_init.service
2189ms avahi-daemon.service
2120ms systemd-logind.service
1210ms xinetd.service
1080ms ntp.service
[...]
75ms fbset.service
72ms purge-kernels.service
47ms dev-vda1.swap
38ms bluez-coldplug.service
35ms splash_early.serviceroot # systemd-analyze plot > jupiter.example.com-startup.svg
上面提到的命令可让您查看已启动的服务以及启动各服务所需的时间。如果您需要知道更多细节,可以在引导提示处输入下列参数,让 systemd 详细记录整个启动过程:
systemd.log_level=debug systemd.log_target=kmsg
现在,systemd 会将日志讯息写入内核环缓冲区。使用 dmesg 查看该缓冲区:
dmesg -T | less
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 应用程序.service 启动守护程序。
基本服务管理也可以通过 YaST 服务管理器模块实现。该模块支持启动、停止、启用和禁用服务。它还可让您显示服务的状态以及更改默认目标。要启动 YaST 模块,请选择 › › 。
要更改系统引导到的目标,请从下拉框中选择某个目标。最常用的目标是(启动图形登录屏幕)和(以命令行模式启动系统)。
从表中选择一个服务。列显示它当前是()否()正在运行。通过选择可切换其状态。
为当前正在运行的会话启动或停止服务会更改其状态。要更改服务在整个重引导过程中的状态,您需要启用或禁用服务。
从表中选择一个服务。列显示它当前还是。通过选择可更改其状态。
通过启用或禁用服务,可配置服务在引导期间是否启动(或)。此设置不会影响当前的会话。要更改服务在当前会话中的状态,您需要将其启动或停止。
要查看某个服务的状态讯息,请从列表中选择该服务,然后选择。您看到的输出与 systemctl 命令生成的输出完全相同。
-l status <我的服务>
有问题的运行级别设置可能会导致系统无法使用。在应用您的更改之前,请确保您清楚这些设置可能产生的结果。
systemd 自定义 #
以下几节介绍了 systemd 自定义的一些示例。
一律在 /etc/systemd/ 中进行 systemd 自定义设置,切勿在 /usr/lib/systemd/ 中进行。否则,您的更改将在 systemd 下次更新时被覆盖。
systemd 服务文件位于 /usr/lib/systemd/system 中。如果您要自定义服务文件,请执行下列步骤:
将要修改的文件从 /usr/lib/systemd/system 复制到 /etc/systemd/system。将文件名保持不变。
根据需要修改 /etc/systemd/system 中的副本。
如需配置更改的概述,请使用 systemd-delta 命令。它会比较并识别覆盖了其他配置文件的配置文件。有关细节,请参考 systemd-delta 手册页。
/etc/systemd 中修改过的文件优先于 /usr/lib/systemd/system 中的原始文件,前提是它们的文件名相同。
如果您只想在配置文件中添加几行或修改文件的一小部分,可以使用所谓的“插入式”文件。使用插入式文件,您无需编辑或覆盖单元文件本身,即可扩展单元文件的配置。
例如,要更改位于 /usr/lib/systemd/system/ foobar.service 中 foobar 服务的一个值,请执行下列步骤:
创建名为 /etc/systemd/system/<我的服务>.service.d/ 的目录。
注意 .d 后缀。该目录必须命名为与要用插入式文件修补的服务相似的名称。
在该目录中,创建 whatevermodification.conf 文件。
确保文件中仅包含要修改的值所在的那一行。
将更改保存到 文件中。它将作为原始文件的扩展。
System V init SUSE 系统上未使用运行级别 4,以便允许管理员创建自己的运行级别配置。systemd 允许您创建任意数目的自定义目标。建议您从采用 graphical.target 等现有目标开始。
将配置文件 /usr/lib/systemd/system/graphical.target 复制到 /etc/systemd/system/<我的目标>.target,并根据需要调整该文件。
上一步中复制的配置文件已涵盖目标的必要(“硬性”)依赖性。如果还要涵盖需要的(“软性”)依赖性,请创建目录 /etc/systemd/system/<我的目标>.target.wants。
对每个需要的服务,创建从 /usr/lib/systemd/system 链到 /etc/systemd/system/<我的目标>.target.wants 的符号链接。
设置好目标后,重新装载 systemd 配置以让新目标可用。
systemctl daemon-reload
以下几节介绍了适合系统管理员的高级主题。有关更高级的 systemd 文档,请参考 Lennart Pöttering 撰写的适合管理员的 systemd 相关系列,网址为 http://0pointer.de/blog/projects。
第 11.6.6 节 “调试服务” 介绍如何查看给定服务的日志讯息。但可显示的日志讯息并不仅限于服务日志。您还可以访问和查询 systemd 写入的完整日志,即所谓的“日记”。使用 systemd-journalctl 命令可显示完整的日志讯息,从最早的项开始。有关诸如应用过滤器或更改输出格式的选项,请参考 man 1 systemd-journalctl。
您可以使用 isolate 子命令将 systemd 的当前状态保存到指定快照中,并在日后还原到该状态。此功能在测试服务或自定义目标时非常有用,因为它可让您随时回到定义的状态。快照仅在当前会话中可用,重引导时将自动删除。快照名称必须以 .snapshot 结尾。
systemctl snapshot <my_snapshot>.snapshot
systemctl delete <my_snapshot>.snapshot
systemctl show <my_snapshot>.snapshot
systemctl isolate <my_snapshot>.snapshot
借助 systemd,再通过使用以下位置中的配置文件,可以在引导时自动装载内核模块:
/usr/lib/modules-load.d 和
/etc/modules-load.d
有关详细信息,请参见 modules-load.d(5) 手册页。
在传统 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
├─ntpd.service
│ └─1328 /usr/sbin/ntpd -p /var/run/ntp/ntpd.pid -g -u ntp:ntp -c /etc/ntp.conf
├─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 的更多信息,请参见Chapter 8, Kernel Control Groups, System Analysis and Tuning Guide。
如第 11.6.4 节 “内核控制组 (cgroups) ”中所述,在 System V init 系统中,并不总是能够将某个进程指派给其父服务。这导致终止服务及其所有子进程变得很困难。尚未终止的子进程将一直保持为僵停状态。
systemd 将每个服务限定在某个 cgroup 中的概念使您可以明确识别一个服务的所有子进程,从而向这些进程中的每一个发送信号。您可使用 systemctl kill 向服务发送信号。有关可用信号的列表,请参考 man 7 signals。
SIGTERM
SIGTERM 是发送的默认信号。
systemctl kill <my_service>.service
可使用 -s 选项指定应该发送的信号。
systemctl kill -s SIGNAL <my_service>.service
默认情况下,kill 命令会向指定 cgroup 的所有进程发送信号。您可以将发送范围限制为 control 或 main 进程。后一个选项可用于通过发送 SIGHUP 强制服务重新装载其配置的情况:
systemctl kill -s SIGHUP --kill-who=main <my_service>.service
默认情况下,systemd 的输出不会太详细。如果服务启动成功,则不会产生任何输出。如果服务启动失败,则会显示简短的错误讯息。不过,systemctl status 提供了调试服务的启动和操作的途径。
systemd 附带了自己的日志记录机制(“日志”)来记录系统讯息。这可让您一并显示服务讯息与状态讯息。status 命令的工作方式与 tail 相似,也可以采用不同的格式显示日志讯息,是一个功能强大的调试工具。
当服务启动失败时,使用 systemctl status <我的服务>.service 可获得详细的错误讯息:
root #systemctl start apache2.service Job failed. See system journal and 'systemctl status' for details.root #systemctl status apache2.service Loaded: loaded (/usr/lib/systemd/system/apache2.service; disabled) Active: failed (Result: exit-code) since Mon, 04 Jun 2012 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 Jun 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>
status 子命令的默认行为是显示服务发出的最后 10 条讯息。如想要更改要显示的讯息数目,请使用 --lines=n 参数:
systemctl status ntp.service systemctl --lines=20 status ntp.service
要显示服务讯息的“实时流”,请使用 --follow 选项,效果与 tail 相似:
-f
systemctl --follow status ntp.service
--output=模式 参数可让您更改服务讯息的输出格式。最重要的可用模式包括:
short
默认格式。显示日志讯息,以及用户能看懂的时戳。
verbose
所有字段的完整输出。
cat
精简输出,不含时戳。
有关 systemd 的更多信息,请参考下列联机资源:
作者:Lennart Pöttering,一位 systemd 作家,他撰写了一系列博客(写本章时为 2013 年)。它们可在 http://0pointer.de/blog/projects 找到。
systemd Linux init 系统http://www.h-online.com/open/features/Control-Centre-The-systemd-Linux-init-system-1565543.html
http://www.h-online.com/open/features/Booting-up-Tools-and-tips-for-systemd-1570630.html