图书节选:Fedora 和红帽企业 Linux 实用指南

作者:Mark Sobell

init 守护进程

init 守护进程是 Linux 的系统和服务管理器。它是 Linux 启动时启动的第一个真实进程,因此进程 ID 为 1,并且是所有进程的祖先。init 守护进程自 UNIX 早期就已存在,许多人为改进它而努力。第一个 Linux init 守护进程基于 UNIX System V init 守护进程,被称为 SysVinit(System V init 守护进程)。

由于 SysVinit 无法很好地处理现代硬件,包括热插拔设备、USB 硬盘和闪存驱动器以及网络挂载的文件系统,Fedora/RHEL 最近用 Upstart init 守护进程取代了它(http://upstart.ubuntu.com/http://upstart.ubuntu.com/wiki)。Fedora 15 已经超越 Upstart,转而使用 systemd init 守护进程,这将在接下来进行描述。还有其他几种 SysVinit 的替代品可用。其中最突出的是 initng (http://initng.sourceforge.net/trac)。此外,Solaris 使用 SMF(服务管理工具),而 MacOS 使用 launchd

systemd init 守护进程 (Fedora)

名称 systemdsystem(systemd 管理的对象)和 d 组成。在 UNIX/Linux 下,守护进程名称通常以 d 结尾:systemd 是系统守护进程。在启动时,systemd 将自身重命名为 init,因此您不会看到名为 systemd 的进程。但是,init 只是指向 systemd 的链接

$ ls -l /sbin/init
lrwxrwxrwx. 1 root root 14 04-22 08:47 /sbin/init -> ../bin/systemd

该名称也是对 System D 的文字游戏,指的是法语 dérouillard(解开)或 démerder。System D 是一种应对挑战的方式,需要快速思考、适应和即兴发挥。

systemd init 守护进程是 SysVinit 的直接替代品;大多数与 SysVinit 和 Upstart 一起使用的管理工具也适用于 systemd。尽管 systemd 是新的,但大多数与管理员相关的用户界面将保持稳定(http://www.freedesktop.org/wiki/Software/systemd/InterfaceStabilityPromise)。systemd 的 GUI 正在开发中。

更多信息

本地

使用 apropos 列出与 systemd 相关的 man 页面 (apropos systemd)。其中最有趣的一些是 systemd、systemctl、systemd.unit 和 systemd.special。

网站

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

Fedora systemd 首页:fedoraproject.org/wiki/Systemd

Fedora systemd 功能列表:fedoraproject.org/wiki/Features/systemd

SysVinit 到 systemd 转换注意事项:fedoraproject.org/wiki/SysVinit_to_Systemd_Cheatsheet

在 systemd 下原生运行的服务列表:http://fedoraproject.org/wiki/User:Johannbg/QA/Systemd/compatability

systemd 创建者 Lennart Poettering 关于 systemd 的博客:0pointer.de/blog/projects/systemd.html

systemd 稳定性承诺:http://www.freedesktop.org/wiki/Software/systemd/InterfaceStabilityPromise

cgroups:https://linuxkernel.org.cn/doc/Documentation/cgroups/cgroups.txt

服务单元和目标单元

systemd init 守护进程基于单元的概念,每个单元都有名称和类型。通常,关于单元的信息存储在与单元名称相同的文件中(例如,dbus.service)。单元的类型包括 service、socket、device、mount、automount、target、snapshot、timer、swap 和 path。本节讨论服务单元和目标单元,这对于控制 systemd 下的守护进程和运行级别至关重要。

服务单元

服务单元指的是 systemd 控制的守护进程(服务),包括由 systemd 原生控制的守护进程以及由 systemd 通过 SysVinit 脚本控制的守护进程。例如,systemd 通过 ntpd.service 服务单元原生控制 ntpd 守护进程。

目标单元

目标单元对其他单元进行分组。本节关注的是控制系统运行级别的目标。默认情况下,Fedora 激活 graphical.target,这会将系统带到相当于以前称为运行级别 5(多用户图形模式)的运行级别。激活 multi-user.target 会将系统带到以前称为运行级别 3(多用户文本模式)的运行级别。

术语:服务器、服务、守护进程

守护进程,例如 ntpdcupsd,提供在服务器上运行的服务。守护进程本身有时也称为服务器。这三个术语可以互换使用。

运行级别

systemd init 守护进程不支持 SysVinit 那样的运行级别。它支持目标单元,这与运行级别相似但又不同。为了方便过渡,本书继续使用术语运行级别来指代目标单元。SysVinit 运行级别和 systemd 目标单元之间的一个区别是,前者只能在系统更改运行级别时更改,而后者可以由一大组触发器激活。另一个区别是,基于 systemd 的系统可以一次激活多个目标单元,从而允许系统同时处于多个运行级别。例如,graphical.target 拉入 multi-user.target,因此它们同时处于活动状态。


systemd 运行级别与 SysVinit 运行级别不同 - 为了在从 SysVinit 过渡到 systemd 期间保持一致性和清晰度,本书将 systemd 目标单元称为运行级别。目标单元不是真正的运行级别,但它们执行的功能类似于 SysVinit 运行级别执行的功能。


Wants 和 Requires

在 systemd 下,术语 wantsrequires 指定在激活想要或需要另一个单元的单元时要激活的单元。如果另一个单元不可用,则requires 另一个单元的单元将不会启动,并且如果另一个单元在第一个单元活动时变得不可用,则将退出。Wants 类似于 requires,不同之处在于,如果想要的单元不可用,则 wants 另一个单元的单元不会失败。

显示属性

以下 systemctl show 命令显示 graphical.target 单元的 Requires 属性。它表明 graphical.target 需要 multi-user.target

$ systemctl show --property "Requires" graphical.target
Requires=multi-user.target

这种关系导致 systemd 在 multi-user.target 不可用时不会启动 graphical.target。这意味着 graphical.target 需要 multi-user.target 需要的单元,并想要 multi-user.target 想要的单元。由于这种关系,multi-user.target(运行级别)与 graphical.target(运行级别)同时处于活动状态。

您还可以使用 systemctl show 命令来显示目标的 Wants 属性

$ systemctl show --property "Wants" multi-user.target
Wants=systemd-update-utmp-runlevel.service NetworkManager.service ...
(END) q

列表很长。尽管 systemctl 通过分页器传递输出,但它会超出屏幕的右边缘。当命令显示 (END) 时,按 q 返回到 shell 提示符。将输出通过 fmt 文本格式化程序,并指定行长为 10,将以每行一个服务的形式显示列表

$ systemctl show --property "Wants" multi-user.target | fmt -10
Wants=systemd-update-utmp-runlevel.service
NetworkManager.service
abrtd.service
ntpd.service
mcelog.service
rsyslog.service
...

要查看目标是否想要特定服务,请将先前命令的输出通过 grep

$ systemctl show --property "Wants" multi-user.target | fmt -10 | grep ntpd
ntpd.service
ntpdate.service

输出显示 multi-user.target 想要 ntpd.service 服务。由于 graphical.target 需要 multi-user.target,并且 multi-user.target 想要 ntpd.service,因此当系统进入由 graphical.target 定义的运行级别时,systemd 将启动 ntpd.service

/etc/systemd/system 层次结构:控制服务和持久运行级别

运行级别目标想要的服务出现在 /etc/systemd/system 目录下名为 .wants 的目录中

$ ls -ld /etc/systemd/system/.wants
...
drwxr-xr-x. 2 root root 4096 04-20 17:10 /etc/systemd/system/graphical.target.wants
drwxr-xr-x. 2 root root 4096 04-20 17:10 /etc/systemd/system/multi-user.target.wants
...

以下命令列出想要 ntpd.service 的运行级别目标

$ ls /etc/systemd/system/.wants/ntpd.service
/etc/systemd/system/multi-user.target.wants/ntpd.service

如前一节所述,您也可以使用 systemctl show 命令显示此信息。

/etc/systemd/system 为根的目录层次结构控制系统的持久运行级别。也就是说,此目录层次结构指定在系统启动或以其他方式更改运行级别或守护进程因其他原因激活时将启动哪些守护进程。

所有服务单元文件都保存在 /lib/systemd/system 目录中。/etc/systemd/system 层次结构中的所有普通文件都是指向 /lib/systemd/system 层次结构中文件的链接。例如,前面示例中显示的 ntpd.service 是指向 /lib/systemd/system 中相应服务单元文件的链接

$ ls -l /etc/systemd/system/multi-user.target.wants/ntpd.service
lrwxrwxrwx. 1 root root 32 04-08 14:34 /etc/systemd/system/multi-user.target.wants/ntpd.service -> 
/lib/systemd/system/ntpd.service

服务单元文件为 systemd 提供了启动服务所需的信息,并指定了想要该服务的系统运行级别目标

$ cat /lib/systemd/system/ntpd.service
[Unit]
Description=Network Time Service
After=syslog.target ntpdate.service

[Service]
EnvironmentFile=/etc/sysconfig/ntpd
ExecStart=/usr/sbin/ntpd -n -u ntp:ntp $OPTIONS

[Install]
WantedBy=multi-user.target

当您指示 systemd 在系统启动时启动服务(使服务持久化)时,它会在服务文件中由 _WantedBy 指定的目录中放置指向服务文件的链接。继续以示例为例,systemd 在 multi-user.target.wants 目录中放置指向 ntpd.service 的链接,如前所示。当您指示 systemd 在系统启动时不启动服务时,它会删除该链接。“设置守护进程(服务)的持久状态”解释了如何使用 systemctl 进行这些更改。

持久(默认)运行级别也由链接控制

$ ls -l /etc/systemd/system/default.target
lrwxrwxrwx. 1 root root 36 04-20 10:07 /etc/systemd/system/default.target -> 
/lib/systemd/system/runlevel5.target

有关更多信息,请参阅“设置持久运行级别”。

自定义服务文件

如前一节所述,/etc/systemd/system 目录层次结构中的文件是指向 /lib/systemd/system 目录层次结构中文件的符号链接。systemd init 守护进程以相同的方式处理 /etc/systemd/system 目录层次结构中的文件和 /lib/systemd/system 目录层次结构中的文件,/etc/systemd/system 中的文件会覆盖 /lib/systemd/system 中同名的文件。这些目录层次结构之间的一个重要区别是 /lib/systemd/system 由 yum/RPM 管理,而 /etc/systemd/system 由系统管理员管理。

将自定义服务文件放在 /etc/systemd/system 层次结构中。如果要修改服务文件,请将其从 /lib/systemd/system 层次结构复制到 /etc/systemd/system 层次结构并编辑副本。/etc/systemd/system 层次结构中的自定义文件不会被 yum/RPM 覆盖,并且将优先于 /lib/systemd/system 层次结构中同名的文件。

确定 systemd 是否原生运行守护进程

为了简化从 SysVinit 和 Upstart 到 systemd 的迁移,并提供与其他发行版软件的兼容性,systemd 可以通过 SysVinit 脚本控制守护进程。您可以使用 systemctl status 命令来确定 systemd 是原生控制守护进程还是通过 SysVinit 脚本控制守护进程。下面,systemctl 显示 dhcpdsshd 的状态

$ systemctl status dhcpd.service
dhcpd.service - DHCPv4 Server Daemon
          Loaded: loaded (/lib/systemd/system/dhcpd.service)
          Active: inactive (dead)
          CGroup: name=systemd:/system/dhcpd.service
$ systemctl status sshd.service
sshd.service - LSB: Start up the OpenSSH server daemon
          Loaded: loaded (/etc/rc.d/init.d/sshd)
          Active: active (running) since Wed, 20 Apr 2011 19:08:32 -0700; 19h ago
        Main PID: 817 (sshd)
          CGroup: name=systemd:/system/sshd.service
                  + 817 /usr/sbin/sshd

systemctl 实用程序需要在单元名称(前面示例中的 dhcpdsshd)后跟句点和单元类型(前面示例中的 .service)。以 Loaded 开头的行命名控制每个守护进程(服务)的文件。dhcpd 守护进程由 /lib/systemd/system/dhcpd.service 控制。文件的位置(/lib/systemd 层次结构)及其文件名扩展名(.service)表明 systemd 正在原生运行守护进程。sshd 守护进程由 /etc/rc.d/init.d/sshd 控制。文件的位置(init.d 目录)以及缺少文件名扩展名表明 systemd 正在通过 SysVinit 脚本运行守护进程。有关已移植到 systemd(并由 systemd 原生运行)的服务列表,请参阅 fedoraproject.org/wiki/User:Johannbg/QA/Systemd/compatability

您可以使用 service 显示与 systemctl status 相同的信息。但是,service 不接受句点和单元类型。

# service dhcpd status
dhcpd.service - DHCPv4 Server Daemon
          Loaded: loaded (/lib/systemd/system/dhcpd.service)
          Active: inactive (dead)
          CGroup: name=systemd:/system/dhcpd.service
# service sshd status
sshd.service - LSB: Start up the OpenSSH server daemon
          Loaded: loaded (/etc/rc.d/init.d/sshd)
          Active: active (running) since Wed, 20 Apr 2011 19:08:32 -0700; 19h ago
        Main PID: 817 (sshd)
          CGroup: name=systemd:/system/sshd.service
                  + 817 /usr/sbin/sshd
设置和更改运行级别

运行级别指定系统上正在运行哪些守护进程以及哪些接口可用。有关更多信息,请参阅“运行级别”和表 11-1。本节介绍如何设置持久(默认)运行级别(系统启动时进入的运行级别)以及如何更改当前运行级别。

设置持久运行级别

在 systemd 下,不存在真正的运行级别;请参阅“运行级别”。例如,Fedora 下的默认运行级别是 graphical.target,并且有一个别名 runlevel5.target。在 SysVinit 下,此运行级别称为运行级别 5(多用户图形模式)。/etc/systemd/system/default.target 文件是指向指定系统默认启动目标的文件的链接

$ ls -l /etc/systemd/system/default.target
lrwxrwxrwx. 1 root root 36 04-20 10:07 /etc/systemd/system/default.target -> /lib/systemd/system/runlevel5.target

以下命令显示 runlevel5.target 是指向 graphical.target 的链接

$ ls -l /lib/systemd/system/runlevel5.target
lrwxrwxrwx. 1 root root 16 04-08 14:33 /lib/systemd/system/runlevel5.target -> graphical.target

multi-user.target 文件(以及指向它的链接 runlevel3.target)会导致系统启动到多用户运行级别(多用户文本模式;SysVinit 运行级别 3)。以下命令替换了前面示例中显示的链接,并将导致系统每次启动时都进入多用户文本模式。此命令不会更改当前运行级别。

# ln -sf /lib/systemd/system/multi-user.target /etc/systemd/system/default.target

–s(符号)选项创建符号链接,–f(强制)选项覆盖任何现有文件。在给出前面的命令并重新启动系统后,systemctl list-units 命令显示系统处于多用户模式

$ systemctl list-units --type=target
...
multi-user.target         loaded active active     Multi-User
...

更改当前运行级别

systemctl isolate 命令更改系统的当前运行级别。以下命令将运行级别更改为多用户图形模式 (graphical.target)。当系统重新启动时,它将返回到 /etc/systemd/system/default.target 中的链接指定的默认运行级别。

# systemctl isolate graphical.target

片刻之后,systemctl 显示系统处于 graphical.target 指定的运行级别

$ systemctl list-units --type=target
...
graphical.target          loaded active active     Graphical Interface
...

前面的示例是从 ssh 登录运行的。如果您从 GUI 中运行的终端模拟器给出这些命令,则每次系统更改运行级别时,系统都会注销您。

配置守护进程(服务)

当您考虑守护进程时,有两个状态很重要:它的当前状态和它的持久状态(系统启动后它将处于的状态)。可能的状态是运行和停止。在 Fedora 下,守护进程在安装时已停止,并设置为在系统启动后停止。

systemctl 实用程序控制原生在 systemd 下运行的守护进程的当前状态和持久状态。service 和 chkconfig 实用程序最初控制在 SysVinit 下运行的守护进程,并已升级为控制在 Upstart 下运行的守护进程。现在,这些实用程序已进行改造,以控制在 systemd 下运行的守护进程,它们通过调用 systemctl 来实现这一点。您仍然可以使用 service 来控制守护进程的当前状态,并使用 chkconfig 来控制守护进程的持久状态。

接下来的部分描述控制守护进程的 systemctl 命令,然后是执行相同功能的 service 或 chkconfig 命令。

设置守护进程(服务)的持久状态

systemctl disable 命令导致守护进程在系统启动时不启动。此命令对守护进程的当前状态没有影响。您必须指定服务名称的 .service 部分。

# systemctl disable ntpd.service
rm '/etc/systemd/system/multi-user.target.wants/ntpd.service'

前面的命令删除导致 systemd 在系统进入多用户运行级别以及继承的图形运行级别时启动 ntpd 的链接。有关这些链接的讨论,请参阅“/etc/systemd/system 层次结构:控制服务和持久运行级别”。

前面的命令适用于由 systemd 原生运行的 ntpd 守护进程。如果您在由 SysVinit 脚本控制的守护进程(例如 cups)上运行相同的命令,它会调用 chkconfig(稍后介绍)。即使不存在 cups.service 服务或文件,您也必须指定服务名称的 .service 部分。

# systemctl disable cups.service
cups.service is not a native service, redirecting to /sbin/chkconfig.
Executing /sbin/chkconfig cups off

以下每个命令都验证 ntpd 守护进程在系统启动时不会启动。第一个命令显示 ntpd.service.wants 目录中没有链接。第二个命令使用 systemctl is-enabled,如果服务已启用,则将其退出状态设置为 0(零),否则设置为非零。如果 systemctl 返回非零退出状态(失败),则 || 布尔运算符执行 echo 命令。

# ls /etc/systemd/system/.wants/ntpd.service
ls: cannot access /etc/systemd/system/.wants/ntpd.service: No such file or directory
# systemctl is-enabled ntpd.service || echo ntpd is not enabled
ntpd is not enabled

systemctl enable 命令导致守护进程在系统启动时启动。此命令对守护进程的当前状态没有影响。它创建链接,使 systemd 在系统进入多用户文本模式以及继承的多用户图形模式时启动 ntpd。如果您在由 SysVinit 脚本控制的守护进程上运行相同的命令,它会调用 chkconfig(稍后介绍)。

# systemctl enable ntpd.service
ln -s '/lib/systemd/system/ntpd.service' '/etc/systemd/system/multi-user.target.wants/ntpd.service'

与前面的示例一样,接下来的两个命令检查守护进程是否将在系统启动时启动。

$ ls /etc/systemd/system/.wants/ntpd.service
/etc/systemd/system/multi-user.target.wants/ntpd.service

$ systemctl is-enabled ntpd.service || echo ntpd is not enabled
$

chkconfig offon 命令对应于 systemctl disableenable 命令。在 systemd 原生控制的守护进程上运行时,命令显示的消息表明它们调用 systemctl。由于 chkconfig – –list 选项不显示 systemd 原生控制的守护进程的正确信息;您必须使用前面的技术来确定是否启用了此类守护进程。

# chkconfig ntpd off
Note: Forwarding request to 'systemctl disable ntpd.service'.
rm '/etc/systemd/system/multi-user.target.wants/ntpd.service'

# chkconfig ntpd on
Note: Forwarding request to 'systemctl enable ntpd.service'.
ln -s '/lib/systemd/system/ntpd.service' '/etc/systemd/system/multi-user.target.wants/ntpd.service'

可选

上一节讨论了 systemctl enable 命令,因为它会导致守护进程在系统启动时启动。大多数时候,此命令都以这种方式工作。但是,systemctl enable 命令可以根据各种触发器(而不仅仅是系统启动)来启动服务。

例如,当启用 bluetooth.service 时,它由蓝牙设备逻辑控制,该逻辑在插入蓝牙设备时启动 bluetooth.service。如果蓝牙设备内置于计算机中,则这种区别并不重要。但是,如果蓝牙设备连接到 USB 加密狗,则运行 systemctl enable 意味着将来,蓝牙服务将在插入加密狗后立即启动,但在此之前不会启动。

类似地,在 Fedora 的未来版本中,cupsd 守护进程将不再在系统启动时启动。相反,运行 systemctl enable 将仅为 cupsd 建立通信套接字。只有当进程尝试访问 cupsd 时(当有人将作业发送到打印机时),cupsd 守护进程才会启动。


更改守护进程的当前状态

systemctl stop 命令立即停止守护进程运行。此命令对守护进程是否在系统启动时启动没有影响。以下命令适用于由 systemd 原生运行的 ntpd 守护进程。它也适用于 systemd 通过 SysVinit 脚本控制的守护进程。您必须始终指定服务名称的 .service 部分。

# systemctl stop ntpd.service

前面的命令停止 ntpd 守护进程。即使您错误地键入守护进程的名称,它也不会显示任何输出。以下每个命令都验证 ntpd 守护进程未运行。

# systemctl status ntpd.service
ntpd.service - Network Time Service
          Loaded: loaded (/lib/systemd/system/ntpd.service)
          Active: inactive (dead) since Fri, 22 Apr 2011 08:50:59 -0700; 17ms ago
         Process: 1036 ExecStart=/usr/sbin/ntpd -n -u ntp:ntp $OPTIONS (code=exited, status=0/SUCCESS)
          CGroup: name=systemd:/system/ntpd.service

# systemctl is-active ntpd.service
inactive

systemctl status 命令显示 Active 状态为 inactive (dead)。systemctl is-active 命令显示状态为 inactive。您还可以使用 ps –ef | grep ntpd 来确定守护进程是否正在运行。

systemctl start 命令立即启动守护进程运行。此命令对守护进程是否在系统启动时启动没有影响。

# systemctl start ntpd.service

接下来的两个命令都显示守护进程正在运行。

# systemctl status ntpd.service
ntpd.service - Network Time Service
          Loaded: loaded (/lib/systemd/system/ntpd.service)
          Active: active (running) since Fri, 22 Apr 2011 08:50:59 -0700; 33ms ago
        Main PID: 1562 (ntpd)
          CGroup: name=systemd:/system/ntpd.service
                  + 1562 /usr/sbin/ntpd -n -u ntp:ntp -g

# systemctl is-active ntpd.service
active

service stopstartstatus 命令对应于 systemctl stopstartstatus 命令。stopstart 命令显示的消息表明它们只是调用 systemctl。您可以使用 service status 命令(或 systemctl status 命令)来显示守护进程的状态。

# service ntpd stop
Stopping ntpd (via systemctl):                             [  OK  ]

# service ntpd start
Starting ntpd (via systemctl):                             [  OK  ]

# service ntpd status
ntpd.service - Network Time Service
          Loaded: loaded (/lib/systemd/system/ntpd.service)
          Active: active (running) since Fri, 22 Apr 2011 08:50:59 -0700; 102ms ago
        Main PID: 1615 (ntpd)
          CGroup: name=systemd:/system/ntpd.service
                  + 1615 /usr/sbin/ntpd -n -u ntp:ntp -g

此节选来自 Mark G. Sobell 的新书《Fedora 和红帽企业 Linux 实用指南》第 6 版,由 Pearson/Prentice Hall Professional 出版,2011 年 8 月,ISBN 0132757273,2012 Mark G. Sobell 版权所有。有关更多信息,请访问 http://sobell.com 或出版社网站:www.informit.com/title/0132757273

加载 Disqus 评论