systemctl是 Systemd 的主命令,用于管理系统。

1. 系统管理

系统管理
# 重启系统
$ sudo systemctl reboot

# 关闭系统,切断电源
$ sudo systemctl poweroff

# CPU停止工作
$ sudo systemctl halt

# 暂停系统
$ sudo systemctl suspend

# 让系统进入冬眠状态
$ sudo systemctl hibernate

# 让系统进入交互式休眠状态
$ sudo systemctl hybrid-sleep

# 启动进入救援状态(单用户状态)
$ sudo systemctl rescue

2. Unit管理

资源统称为 Unit(单位)

Unit管理命令
# 列出正在运行的 Unit
$ systemctl list-units

# 列出所有Unit,包括没有找到配置文件的或者启动失败的
$ systemctl list-units --all

# 列出所有没有运行的 Unit
$ systemctl list-units --all --state=inactive

# 列出所有加载失败的 Unit
$ systemctl list-units --failed

# 列出所有正在运行的、类型为 service 的 Unit
$ systemctl list-units --type=service

# 显示系统状态
$ systemctl status

# 显示单个 Unit 的状态
$ sysystemctl status bluetooth.service

# 显示远程主机的某个 Unit 的状态
$ systemctl -H root@rhel7.example.com status httpd.service

# 显示某个 Unit 是否正在运行
$ systemctl is-active application.service

# 显示某个 Unit 是否处于启动失败状态
$ systemctl is-failed application.service

# 显示某个 Unit 服务是否建立了启动链接
$ systemctl is-enabled application.service

# 立即启动一个服务
$ sudo systemctl start apache.service

# 立即停止一个服务
$ sudo systemctl stop apache.service

# 重启一个服务
$ sudo systemctl restart apache.service

# 杀死一个服务的所有子进程
$ sudo systemctl kill apache.service

# 重新加载一个服务的配置文件
$ sudo systemctl reload apache.service

# 重载所有修改过的配置文件
$ sudo systemctl daemon-reload

# 显示某个 Unit 的所有底层参数
$ systemctl show httpd.service

# 显示某个 Unit 的指定属性的值
$ systemctl show -p CPUShares httpd.service

# 设置某个 Unit 的指定属性
$ sudo systemctl set-property httpd.service CPUShares=500

# Unit 之间存在依赖关系:A 依赖于 B,就意味着 Systemd 在启动 A 的时候,同时会去启动 B
# 列出一个 Unit 的所有依赖
$ systemctl list-dependencies --all nginx.service

# 激活开机启动
$ sudo systemctl enable clamd@scan.service
# 等同于
$ sudo ln -s '/usr/lib/systemd/system/clamd@scan.service' '/etc/systemd/system/multi-user.target.wants/clamd@scan.service'

# 撤销符号链接关系,相当于撤销开机启动
sudo systemctl disable clamd@scan.service

# 重新加载配置文件
$ sudo systemctl daemon-reload
表 1. Unit类型

Service unit

系统服务

Target unit

多个 Unit 构成的一个组

Device Unit

硬件设备

Mount Unit

文件系统的挂载点

Automount Unit

自动挂载点

Path Unit

文件或路径

Scope Unit

不是由 Systemd 启动的外部进程

Slice Unit

进程组

Snapshot Unit

Systemd 快照,可以切回某个快照

Socket Unit

进程间通信的 socket

Swap Unit

swap 文件

Timer Unit

定时器

Systemd 默认从目录/etc/systemd/system/读取配置文件,里面存放的大部分文件都是符号链接,指向目录/usr/lib/systemd/system/,这里是真正的配置文件存放目录。

2.1. 配置文件状态

# 列出所有配置文件
$ systemctl list-unit-files

# 列出指定类型的配置文件
$ systemctl list-unit-files --type=service
表 2. 配置文件状态

enabled

已建立启动链接

disabled

没建立启动链接

static

该配置文件没有[Install]部分(无法执行),只能作为其他配置文件的依赖

masked

该配置文件被禁止建立启动链接

2.2. 配置文件格式

格式简要示例
[Unit]
Description=test        # 简单描述服务
After=network.target    # 描述服务类别,表示本服务需要在network服务启动后在启动
Before=xxx.service      # 表示需要在某些服务启动之前启动,After和Before字段只涉及启动顺序,不涉及依赖关系

[Service]
Type=forking            # 设置服务的启动方式
User=USER               # 设置服务运行的用户
Group=USER              # 设置服务运行的用户组
WorkingDirectory=/PATH  # 设置服务运行的路径(cwd)
KillMode=control-group  # 定义systemd如何停止服务
Restart=no              # 定义服务进程退出后,systemd的重启方式,默认是不重启
ExecStart=/start.sh     # 服务启动命令,命令需要绝对路径(采用sh脚本启动其他进程时Type须为forking)

[Install]
WantedBy=multi-user.target  # 多用户
区块 描述

[Unit]

启动顺序与依赖关系

[Service]

启动行为定义

[Install]

服务安装定义

2.2.1. Unit区块

[Unit]区块通常是配置文件的第一个区块,用来定义 Unit 的元数据,以及配置与其他 Unit 的关系。

Description

简短描述

Documentation

文档地址

Requires

强依赖定义,当前 Unit 依赖的其他 Unit,如果它们没有运行,当前 Unit 会启动失败

Wants

弱依赖定义,与当前 Unit 配合的其他 Unit,如果它们没有运行,当前 Unit 不会启动失败

BindsTo

与Requires类似,它指定的 Unit 如果退出,会导致当前 Unit 停止运行

Before

如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之后启动

After

如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之前启动

Conflicts

这里指定的 Unit 不能与当前 Unit 同时运行

Condition…​

当前 Unit 运行必须满足的条件,否则不会运行

Assert…​

当前 Unit 运行必须满足的条件,否则会报启动失败

2.3. Service区块

[Service]区块用来 Service 的配置,只有 Service 类型的 Unit 才有这个区块。

Type

定义启动时的进程行为。值域参考

ExecStart

启动当前服务的命令

ExecStartPre

启动当前服务之前执行的命令

ExecStartPost

启动当前服务之后执行的命令

ExecReload

重启当前服务时执行的命令

ExecStop

停止当前服务时执行的命令

ExecStopPost

停止当其服务之后执行的命令

RestartSec

自动重启当前服务间隔的秒数

Restart

定义何种情况 Systemd 会自动重启当前服务,可能的值包括always(总是重启)、on-success、on-failure、on-abnormal、on-abort、on-watchdog

KillMode

定义systemd如何停止服务。值域参考

TimeoutSec

定义 Systemd 停止当前服务之前等待的秒数

Environment

指定环境变量,如 Environment=DATA_DIR=/dir/data

EnvironmentFile

指定环境参数文件(路径),如 EnviromentFile=-/etc/sysconfig/xxx 连词号表示抑制错误,即发生错误时,不影响其他命令的执行。

User

设置服务运行的用户

Group

设置服务运行的用户组

WorkingDirectory

设置服务运行的路径

RemainAfterExit

可设为"yes"或"no"(默认值),表示当该服务的所有进程全部退出之后,是否依然将此服务视为活动(active)状态。

GuessMainPID

可设为"yes"(默认值)或"no",表示在无法明确定位该服务的主进程的情况下,systemd 是否应该猜测主进程的PID(可能不正确)。 该选项仅在设置了 Type=forking 但未设置 PIDFile= 的情况下有意义。如果PID猜测错误,那么该服务的失败检测与自动重启功能将失效。

PIDFile

守护进程的PID文件,必须是绝对路径。强烈建议在 Type=forking 的情况下明确设置此选项。 systemd 将会在此服务启动后从此文件中读取主守护进程的PID 。systemd 不会写入此文件,但会在此服务停止后删除它(若存在)。

表 3. 启动类型,Service.Type值域

simple

执行ExecStart指定的命令,启动主进程。设置了 ExecStart= 但未设置 BusName= 时的默认值。

forking

以 fork 方式从父进程创建子进程,ExecStart= 所设定的进程将会在启动过程中使用 fork() 系统调用。创建后父进程会立即退出,子进程将成为主进程(例如用 shell 脚本启动服务进程),也就是当所有的通信渠道都已建好、启动亦已成功之后,父进程将会退出,而子进程将作为该服务的主进程继续运行。 对于此种进程,建议同时设置 PIDFile= 选项,以帮助 systemd 准确定位该服务的主进程。

oneshot

类似于 simple,但只执行一次,systemd 会等它执行完,才启动其他服务。未设置 ExecStart= 时的默认值。此种类型通常需要设置 RemainAfterExit= 选项。

dbus

类似于 simple,但会等待 D-Bus 信号后启动。设置了 ExecStart= 与 BusName= 时的默认值。

notify

类似于 simple,启动结束后会发出通知信号,然后 systemd 再启动其他服务。

idle

类似于 simple,但是要等到其他任务都执行完,才会启动该服务。

表 4. 重启行为,Service.KillMode值域

control-group

当前控制组里面的所有子进程,都会被杀掉。默认值

process

只杀主进程。

mixed

主进程将收到 SIGTERM 信号,子进程收到 SIGKILL 信号。

none

没有进程会被杀掉,只是执行服务的 stop 命令。

Restart

定义了服务退出后,Systemd 的重启方式,可以设置的值如下(对于守护进程,推荐设为 on-failure,对于那些允许发生错误退出的服务,可以设为 on-abnormal)

no(default)

退出后不会重启。

on-success

只有正常退出时(退出状态码为0),才会重启。

on-failure

非正常退出时(退出状态码非0),包括被信号终止和超时,才会重启。

on-abnormal

只有被信号终止和超时,才会重启。

on-abort

只有在收到没有捕捉到的信号终止时,才会重启。

on-watchdog

超时退出,才会重启。

always

不管是什么退出原因,总是重启。

2.4. Install区块

[Install]通常是配置文件的最后一个区块,用来定义如何启动,以及是否开机启动。

WantedBy

它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放入/etc/systemd/system目录下面以 Target 名 + .wants后缀构成的子目录中

RequiredBy

它的值是一个或多个 Target,当前 Unit 激活时,符号链接会放入/etc/systemd/system目录下面以 Target 名 + .required后缀构成的子目录中

Alias

当前 Unit 可用于启动的别名

Also

当前 Unit 激活(enable)时,会被同时激活的其他 Unit

3. Target

Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候,Systemd 就会启动里面所有的 Unit。

Target和 init.d 里的 RunLevel 区别::
  1. RunLevel 是互斥的,不可能多个 RunLevel 同时启动,但是多个 Target 可以同时启动。

  2. 默认的 RunLevel(在/etc/inittab文件设置)现在被默认的 Target 取代,位置是/etc/systemd/system/default.target,通常符号链接到graphical.target(图形界面)或者multi-user.target(多用户命令行)

  3. 启动脚本的位置,以前是/etc/init.d目录,符号链接到不同的 RunLevel 目录 (比如/etc/rc3.d、/etc/rc5.d等),现在则存放在/lib/systemd/system和/etc/systemd/system目录

  4. 配置文件的位置,以前init进程的配置文件是/etc/inittab,各种服务的配置文件存放在/etc/sysconfig目录。现在的配置文件主要存放在/lib/systemd目录,在/etc/systemd目录里面的修改可以覆盖原始设置。

表 5. Target和 init.d 里的 RunLevel 关系
RunLevel Target

Runlevel 0

runlevel0.target → poweroff.target

Runlevel 1

runlevel1.target → rescue.target

Runlevel 2

runlevel2.target → multi-user.target

Runlevel 3

runlevel3.target → multi-user.target

Runlevel 4

runlevel4.target → multi-user.target

Runlevel 5

runlevel5.target → graphical.target

Runlevel 6

runlevel6.target → reboot.target