在配置程序开机自启时,常常会用到 systemctl,其是 systemd 的主命令,用于管理系统。systemd 名字来源于 Unix 中的一个惯例:在 Unix 中常以 ‘d’ 作为系统守护进程(daemon,亦称为后台进程)的后缀标识。systemd 是 Linux 系统下的一套中央化系统及设定管理程式(init),包括守护进程、程式库以及应用软体,由 Lennart Poettering 带头开发。目前绝大多数的 Linux 发行版都已采用 systemd 代替原来的 System V,除了 systemctl,systemd 还引入了 localectltimedatectlhostnamectl 等新命令,使得系统配置更方便。本篇以 Ubuntu 为例,所有命令以普通用户运行,部分命令需要 sudo 权限。

常用命令

设置开机自启

支持 systemd 的软件,在安装的时候会自动在 /lib/systemd/system 目录中添加一个配置文件。设置开机自启命令如下

1
2
3
sudo systemctl enable docker
# or
sudo systemctl enable docker.service

执行上面命令之后,会在 /etc/systemd/system 目录或其下的 *.target.wants 下添加一个符号链接,*docker.service 里的配置项 WantedBy 相关。开机时, systemd 只执行 /etc/systemd/system 目录里面的配置文件。当把修改后的 .service 配置文件直接放在 /etc/systemd/system 目录下会覆盖原始配置

获取 systemd 默认启动服务组(即上面的 target)方法如下:

1
systemctl get-default

启动服务

默认安装的软件会自动设置开机自启和立即启动服务。但有时程序停止后,需要启动。常使用如下命令

1
sudo systemctl start docker

查看程序是否启动成功,可以使用如下命令

1
sudo systemctl status docker

正常结果如下:

1
2
3
4
5
6
7
8
9
10
11
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2022-06-17 13:01:12 CST; 7s ago
Docs: https://docs.docker.com
Main PID: 6606 (dockerd)
Tasks: 32
CGroup: /system.slice/docker.service
└─6606 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

6月 17 13:01:12 jinzhongxu-PowerEdge-R740 systemd[1]: Started Docker Application Container Engine.
6月 17 13:01:12 jinzhongxu-PowerEdge-R740 dockerd[6606]: time="2022-06-17T13:01:12.625354075+08:00" level=info msg="API listen on /var/ru

上面输出结果含义:

  • Loaded 表示配置文件的位置,是否设为开机自启;

  • Active 表示运行状态,active 表示正在运行,inactive 表示没有运行;

  • Docs 表示文档说明信息;

  • Main PID 表示主进程;

  • Tasks 表示子进程数;

  • CGroup 表示应用的所有子进程;

  • 日志块 最下面的以日期开头的表示程序运行日志信息

查看实时日志信息,可以使用如下命令:

1
sudo journalctl -u docker -f

停止服务

当需要停止服务时,可使用如下命令:

1
sudo systemctl stop docker

有时候,该命令可能没有相应,服务停不下来。这个时候可以使用 kill 向正在运行的进程发出 “杀进程” 的信号。

1
sudo systemctl kill docker

如果更改了 docker.service 里面的信息,那么需要重新加载,然后重启

1
2
3
sudo systemctl daemon-reload
# 然后重启
sudo systemctl restart docker

配置文件

服务的运行启动完全有配置文件决定。一般 systemd 运行的软件的配置文件主要放在 /usr/lib/systemd/system/etc/systemd/system 目录下。找到配置文件后我们可以使用 vim 打开。或者使用如下命令查看。

1
systemctl cat sshd.service

结果大概是这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# /lib/systemd/system/ssh.service
[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
User=jinzhongxu
Group=jinzhongxu
WorkingDirectory=/home/jinzhongxu/
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755

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

配置文件分成 Unit, Service, Install 三个块。下面分别对其进行介绍。

Unit:启动顺序与依赖关系

1
2
3
4
[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
  •  Description 表示当前服务的简单描述;

  • 有时还会有 Documentation 字段,给出文档位置;

  • After 表示如果 network.target, auditd.service 如果需要启动,那么 sshd 应在它们之后启动;

  • 有时会有 Before 字段,表示在哪些服务之前启动;

  • AfterBefore 只涉及启动顺序,不涉及依赖关系;

  • 有时会有 Wants 字段,表示该程序与其有”弱依赖“关系;

  • 有时会有 Requires 字段,表示该程序与其有“强依赖”关系;

Service:启动行为

1
2
3
4
5
6
7
8
9
10
11
12
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755

Service 区块定义了如何启动当前服务。

  • EnvironmentFile 指定当前服务的环境参数文件。该文件内部是 key=value 键值对,可以用 $key 获取参数文件中的值;上面配置文件中有时会有 -,表示“抑制错误”,即发生错误时,不影响其他命令执行;

  • ExecReload字段:重启服务时执行的命令

  • ExecStop字段:停止服务时执行的命令

  • ExecStartPre字段:启动服务之前执行的命令

  • ExecStartPost字段:启动服务之后执行的命令

  • ExecStopPost字段:停止服务之后执行的命令

  • KillMode字段:定义 systemd 如何停止服务,上面的 process 表示只停止主进程,不停止任何 sshd 子进程,即子进程打开的 SSH session 仍然保持连接。这对于 SSH 很重要,不会连自己打开的 SSH session 一起杀掉;除了 process,还有 control-group (默认值),当前控制组里面的所有子进程都会被杀掉;mixed 主进程将收到 SIGTERM 信号,子进程收到 SIGKILL 信号;none 没有进程会被杀掉,只是执行服务的 stop 命令;

  • Restart 字段:定义了 sshd 退出后,systemd 的重启方式,默认为 no,表示退出后不会重启;on-success 表示只有正常退出时(退出状态码为 0)才会重启;on-failure 表示非正常退出时(退出状态码非 0),包括被信号终止和超时,才会重启;on-abnormal 表示只有被信号终止和超时,才会重启;on-abort 表示只有在收到没有博捉到的信号终止时,才会重启;on-watchdog 表示超时退出,才会重启;always 表示不管是什么原因退出,总是重启;

  • Type 字段:定义启动类型。simple(默认值):ExecStart 字段启动的进程为主进程;forking:ExecStart 字段将以 fork() 方式启动,此时父进程将会退出,子进程将成为主进程;oneshot:类似于 simple,但只执行一次,systemd 会等它执行完,才启动其他服务;dbus:类似于 simple,但会等待 D-Bus 信号后启动;notify:类似于 simple,启动结束后会发出通知信号,然后 systemd 再启动其他服务;idle:类似于 simple,但是要等到其他任务都执行完,才会启动该服务。一种使用场合是为让该服务的输出,不与其他服务的输出相混合。

Install 区块

Install 区块定义如何按照这个配置文件,即怎样做到开机自启。

1
2
3
[Install]
WantedBy=multi-user.target
Alias=sshd.service
  • WantedBy字段:表示该服务所在的 Target,Target 的含义是服务组,表示一组服务。 WantedBy=multi-user.target 指的是, sshd 所在的 Target 是 multi-user.target 。这个设置非常重要,因为在执行 systemctl enable sshd 命令时,sshd.service 的一个符号链接,就会放在 /etc/systemd/system目录下面的 multi-user.target.wants 子目录之中。获取 systemd 默认的启动 target 命令是 systemctl get-default.

关于 target 有如下两个命令

1
2
3
4
5
6
# 查看 multi-user.target 包含的所有服务
systemctl list-dependencies multi-user.target

# 切换到另一个 target
# shutdown.target 就是关机状态
sudo systemctl isolate shutdown.target

一般来说,常用的 Target 有两个:一个是multi-user.target,表示多用户命令行状态;另一个是graphical.target,表示图形用户状态,它依赖于multi-user.target.

查看 target 的配置文件

1
systemctl cat multi-user.target

结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# /lib/systemd/system/multi-user.target
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.

[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes

注意,Target 配置文件里面没有启动命令。

上面输出结果中,主要字段含义如下。

Requires字段:要求basic.target一起运行。

Conflicts字段:冲突字段。如果rescue.servicerescue.target正在运行,multi-user.target就不能运行,反之亦然。

After:表示multi-user.targetbasic.target 、 rescue.service、 rescue.target之后启动,如果它们有启动的话。

AllowIsolate:允许使用systemctl isolate命令切换到multi-user.target

参考文献

  1. Systemd 入门教程:实战篇 - 阮一峰的网络日志