Systemd 是 Linux 系统工具,是用来启动守护进程的,已经成为大多数发行版的标配了。每次用起来我能顺手的也就启动重启停止,其它的都要查,烦死了,还不如干脆记录一下。
Systemd 背景
在操作系统中,init
进程是一个特殊的进程,它是系统启动后运行的第一个进程。init
进程负责启动和管理其他系统进程,并在系统运行期间一直存在。它是操作系统中所有其他进程的祖先。
关于 init
进程的一些信息:
- 进程标识符:
init
进程始终具有进程标识符 (PID) 为 1 的属性。这使得其他进程可以轻松地将其子进程传递给 init
进程进行管理,从而避免产生僵尸进程。 - 启动其他进程:
init
进程负责启动其他系统进程,例如:守护进程、服务、用户空间应用程序等。通常,init
进程根据系统的初始化脚本或配置文件来启动这些进程。 - 管理孤儿进程:当一个父进程终止,而其子进程仍在运行时,这些子进程会成为孤儿进程。
init
进程会自动采纳这些孤儿进程,并负责回收它们的资源,防止系统出现僵尸进程。 - 系统关机与重启:
init
进程在系统关机或重启时负责正确地终止其他进程。它会按照预定顺序发送信号,通知进程执行清理操作并安全退出。 - 不同的
init
系统:随着时间的推移,有多种 init
系统出现,包括 System V init
、Upstart
和 systemd
。其中,System V init
是最早的 init
系统,而 systemd
目前是许多 Linux 发行版中的默认 init
系统,因为它提供了许多先进功能,如并行启动、进程监控和日志管理。
System V init
的缺点:
- 启动速度:
System V init
使用串行启动过程,即一个进程启动完成后,才能启动下一个进程。这导致了系统启动速度较慢。现代的 init
系统,如 systemd
,采用并行启动策略,可以大大提高系统启动速度。 - 依赖管理:
System V init
对进程间的依赖关系管理不足。如果一个服务依赖于另一个服务,System V init
无法确保依赖项已启动。这可能导致启动失败或错误。相比之下,systemd
等现代 init
系统具有更好的依赖管理。 - 进程监控:
System V init
在进程崩溃时无法自动重启进程。这可能导致系统不稳定,需要手动干预。systemd
等替代方案提供了自动进程监控和重启功能,以提高系统的可靠性。 - 日志管理:
System V init
缺乏统一的日志管理。每个进程可能有自己的日志记录方式,这使得日志分析和故障排查变得困难。systemd
引入了 journald
,提供了统一的日志管理,方便管理员分析问题。 - 配置复杂:
System V init
使用启动脚本来管理服务,这些脚本可能难以编写和维护。systemd
使用更简单的配置文件来管理服务,降低了维护成本。
Systemd 概述
systemd
是一种现代化的 init
系统,用于启动、监视和管理 Linux 操作系统中的进程。它在许多主流 Linux 发行版中替代了传统的 System V init
系统,提供了许多改进和新功能。
systemd
的特点:
- 并行启动:
systemd
支持并行启动服务,这意味着它可以同时启动多个服务和进程,从而加快系统启动速度。 - 依赖管理:
systemd
可以自动处理服务和进程之间的依赖关系,确保按照正确的顺序启动它们。这有助于减少启动错误和服务启动失败的可能性。 - 进程监控与自动重启:
systemd
可以监控进程的运行状态,并在它们意外崩溃时自动重启它们。这有助于提高系统的可靠性和稳定性。 - 资源管理:
systemd
与 Linux 的 CGroups 功能紧密集成,允许对进程进行资源限制、隔离和管理。这有助于确保系统资源的公平分配,从而提高系统的稳定性。 - 集中式日志管理:通过
journald
,systemd
提供了一个集中式日志管理系统。journald
可以收集、存储和管理系统日志,方便管理员分析问题和故障排查。 - 简化的服务配置:
systemd
使用名为 Unit 文件的简单配置文件来管理服务。这些文件易于编写和维护,并提供了丰富的选项来定义服务的行为和属性。 - 命令行工具:
systemd
提供了一组强大的命令行工具,如 systemctl
和 journalctl
,用于管理和查询系统服务和日志。这些工具使管理员能够轻松地控制系统服务和获取相关信息。 - 向后兼容性:尽管
systemd
引入了许多新功能和改进,但它仍然保持了对传统 System V init
脚本的支持。这使得在过渡到 systemd
的过程中,现有的服务仍可以继续运行。
简单来说,systemd
是一个工具集,涉及到系统管理的方方面面。
Systemd 工具
systemctl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| // 重启系统
$ sudo systemctl reboot
// 关闭系统,切断电源
$ sudo systemctl poweroff
// CPU 停止工作
$ sudo systemctl halt
// 暂停系统
$ sudo systemctl suspend
// 系统进入冬眠状态
$ sudo systemctl hibernate
// 系统进入交互式休眠状态
$ sudo systemctl hybrid-sleep
// 启动进入救援模式(单用户状态)
$ sudo systemctl rescue
|
systemd-analyze
1
2
3
4
5
6
7
8
9
10
11
| // 查看启动耗时
$ systemd-analyze
// 查看每个服务的启动耗时
$ systemd-analyze blame
// 显示瀑布状的启动过程流
$ systemd-analyze critical-chain
// 显示指定服务的启动流
$ systemd-analyze critical-chain nginx.service
|
hostnamectl
1
2
3
4
5
| // 显示当前主机的信息
$ hostnamectl
// 设置主机名称
$ sudo hostnamectl set-hostname ecs-ubuntu
|
localectl
1
2
3
4
5
6
| // 查看本地化设置
$ localectl
// 设置本地化参数
$ sudo localectl set-locale LANG=en_GB.utf8
$ sudo localectl set-keymap en_GB
|
timedatectl
1
2
3
4
5
6
7
8
9
10
| // 查看当前时区设置
$ timedatectl
// 显示所有可用的时区
$ timedatectl list-timezones
// 设置当前时区
$ sudo timedatectl set-timezone Asia/Shanghai
$ sudo timedatectl set-time YYYY-MM-DD
$ sudo timedatectl set-time HH:MM:SS
|
loginctl
1
2
3
4
5
6
7
8
| // 列表当前 Session
$ loginctl list-sessions
// 列出当前登录用户
$ loginctl list-users
// 列出显示指定用户的信息
$ loginctl show-user ubuntu
|
journalctl
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
| // 查看所有日志(默认情况下,仅保存本次启动的日志)
$ sudo journalctl
// 查看内核日志
$ sudo journalctl -k
// 查看系统本次启动的日志
$ sudo journalctl -b -0
// 查看上一次启动的日志
$ sudo journalctl -b -1
// 查看指定时间的日志
$ sudo journalctl --since="2023-04-18 12:13:14"
$ sudo journalctl --since "30 min ago"
$ sudo journalctl --since yesterday
$ sudo journalctl --since "2017-12-31" --until "2019-12-20"
$ sudo journalctl --since 5:30 --until "3 hour ago"
// 显示结尾的最近 10 行日志
$ sudo journalctl -n
// 显示结尾的指定行数的日志
$ sudo journalctl -n 50
// 显示最新实时滚动的日志
$ sudo journalctl -f
// 查看指定服务的日志
$ sudo journalctl /usr/sbin/nginx
// 查看指定进程的日志
$ sudo journalctl _PID=1
// 查看某个路径的脚本的日志
$ sudo journalctl /usr/bin/bash
// 查看指定用户的日志
$ sudo journalctl _UID=104 --since today
// 查看某个 Unit 的日志
$ sudo journalctl -u nginx.service
$ sudo journalctl -u nginx.service --since today
// 显示某个 Unit 的实时滚动最新日志
$ sudo journalctl -u nginx.service -f
// 合并显示多个 Unit 的日志
$ sudo journalctl -u sshd.service -u nginx.service --since today
// 查看指定优先级的日志(0:emerg 1:alert 2:crit 3:err 4:warning 5:notice 6:info 7:debug)
$ sudo journalctl -p err -b
// 日志默认分页输出
$ sudo journalctl --no-pager
// 日志以 JSON 单行格式输出
$ sudo journalctl -b -u nginx.service -o json
// 日志以 JSON 多行格式输出
$ sudo journalctl -b -u nginx.service -o json-pretty
// 显示日志占据的磁盘空间
$ sudo journalctl --disk-usage
// 显示指定日志文件占据的最大空间
$ sudo journalctl --vacuum-size=1G
// 指定日志文件保存多久
$ sudo journalctl --vacuum-time=1years
|
Unit
systemd.unit — Unit configuration
Unit 类型
类型 | 扩展名 | 说明 |
---|
Service | .service | 表示系统服务,用于管理系统服务,如启动、停止、重启等操作。 |
Socket | .socket | 表示套接字,描述 IPC(进程间通信)或网络套接字,使服务按需启动。 |
Device | .device | 表示硬件设备,描述系统设备,通常由 udev 或 systemd 自动生成。 |
Mount | .mount | 表示文件系统挂载点。描述文件系统挂载点,用于挂载、卸载、管理文件系统。 |
Automount | .automount | 表示自动挂载点,描述文件系统自动挂载点,用于按需挂载文件系统。 |
Timer | .timer | 表示定时器,描述定时任务,基于时间或日历事件触发相关 Unit 启动。 |
Swap | .swap | 表示交换分区或交换文件。描述交换分区或交换文件,用于激活、停用交换空间。 |
Path | .path | 表示文件系统路径。描述文件系统路径的监控,用于触发服务启动。 |
Slice | .slice | 表示一组 Unit 的层次结构,用于对资源进行分组和管理。描述分层资源分配,用于 systemd 进程资源控制。 |
Scope | .scope | 表示运行时创建的一组相关进程。描述动态创建的外部进程,用于将一组相关进程归为一组资源管理。 |
Target | .target | 表示同步点或系统状态。定义系统状态节点,用于对一组相关的 Unit 进行分组和同步。 |
Unit 状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // 列出正在运行的 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
|
Unit 操作
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
| // 显示系统状态
$ systemctl status
// 显示单个 Unit 的状态
$ systemctl status bluetooth.service
// 显示远程主机的某个 Unit 的状态
$ systemctl -H root@ip status httpd.service
// 显示某个 Unit 是否正在运行
$ systemctl is-active application.service
// 显示某个 Unit 是否处于启动失败状态
$ systemctl is-failed application.service
// 显示某个 Unit 服务是否建立了启动链接
$ systemctl is-enabled applicaation.service
// 启动一个服务
$ sudo systemctl start nginx.service
// 停止一个服务
$ sudo systemctl stop nginx.service
// 重启一个服务
$ sudo systemctl restart nginx.service
// 杀死一个服务的所有子进程
$ sudo systemctl kill nginx.service
// 重新加载一个服务的配置文件
$ sudo systemctl reload nginx.service
// 重载所有修改过的配置文件
$ sudo systemctl daemon-reload
// 显示某个 Unit 所有的底层参数
$ sudo show nginx.service
// 显示某个 Unit 指定的属性域值
$ sudo show -p CPUShares nginx.service
// 设置某个 Unit 指定的属性
$ sudo systemctl set-property nginx.service CPUShares=500
// 列出某个 Unit 的所有依赖
$ systemctl list-dependencies nginx.service
// 列出某个 Unit 的所有依赖(显示所有)
$ systemctl list-dependencies --all nginx.service
// 开启某个 Unit 开机启动
$ sudo systemctl enable name.service
// 禁止某个 Unit 开机启动
$ sudo systemctl disable name.service
|
Unit 配置
Systemd Unit 文件由多个配置区块组成,每个区块包含有关该 Systemd Unit 的特定信息。以下是一些常见的 Systemd Unit 配置区块:
Block Name | Desc |
---|
[Unit] | 包含 Unit 的通用选项,如描述、依赖关系等 |
[Service] | 仅适用于 .service 文件,包含与服务相关的选项,如启动类型、命令等 |
[Socket] | 仅适用于 .socket 文件,包含与套接字相关的选项,如监听地址等 |
[Device] | 仅适用于 .device 文件,包含与设备相关的选项,如设备匹配规则等 |
[Mount] | 仅适用于 .mount 文件,包含与挂载点相关的选项,如文件系统类型等 |
[Automount] | 仅适用于 .automount 文件,包含与自动挂载点相关的选项,如超时等 |
[Swap] | 仅适用于 .swap 文件,包含与交换空间相关的选项,如优先级等 |
[Target] | 仅适用于 .target 文件,包含与系统状态节点相关的选项 |
[Path] | 仅适用于 .path 文件,包含与文件系统路径监控相关的选项,如路径等 |
[Timer] | 仅适用于 .timer 文件,包含与定时任务相关的选项,如触发时间等 |
[Slice] | 仅适用于 .slice 文件,包含与分层资源分配相关的选项,如内存限制等 |
[Scope] | 仅适用于 .scope 文件,包含与动态创建的外部进程相关的选项 |
[Install] | 包含有关 Unit 安装和启用的选项,如所需的目标等 |
Systemd Unit 文件中 [Unit]
配置区块的一些常见配置键名及其含义:
Key Name | Desc |
---|
Description | 对 Unit 的简短描述 |
Documentation | 提供 Unit 文档的 URL 链接 |
Requires | 定义必须在此 Unit 之前启动的其他 Unit,如果它们失败,此 Unit 也将失败 |
Wants | 类似于 Requires,但失败的依赖不会导致本 Unit 失败 |
BindsTo | 当依赖的 Unit 启动/停止时,同步启动/停止本 Unit |
PartOf | 当依赖的 Unit 启动/停止/重新加载时,同步启动/停止/重新加载本 Unit |
Conflicts | 指定与此 Unit 冲突的其他 Unit,当冲突的 Unit 启动时,本 Unit 将停止 |
Before | 确保本 Unit 在指定的其他 Unit 之前启动 |
After | 确保本 Unit 在指定的其他 Unit 之后启动 |
OnFailure | 当本 Unit 失败时启动的其他 Unit |
OnSuccess | 当本 Unit 成功时启动的其他 Unit |
ConditionPathExists | 如果指定的文件路径存在,则启动此 Unit |
ConditionPathIsDirectory | 如果指定的文件路径是目录,则启动此 Unit |
ConditionKernelCommandLine | 如果内核命令行参数包含指定的选项,则启动此 Unit |
ConditionArchitecture | 如果系统架构匹配指定的架构,则启动此 Unit |
AssertPathExists | 如果指定的文件路径存在,则启动此 Unit,否则将失败 |
AssertPathIsDirectory | 如果指定的文件路径是目录,则启动此 Unit,否则将失败 |
AssertKernelCommandLine | 如果内核命令行参数包含指定的选项,则启动此 Unit,否则将失败 |
AssertArchitecture | 如果系统架构匹配指定的架构,则启动此 Unit,否则将失败 |
Systemd Unit 文件中 [Service]
配置区块的一些常见配置键名及其含义:
Key Name | Desc |
---|
Type | 定义服务的启动类型,如 simple、forking、oneshot、dbus、notify 等 |
ExecStart | 定义启动服务时执行的命令 |
ExecStartPre | 在 ExecStart 命令执行之前运行的命令 |
ExecStartPost | 在 ExecStart 命令执行之后运行的命令 |
ExecReload | 定义重新加载服务配置时执行的命令 |
ExecStop | 定义停止服务时执行的命令 |
ExecStopPost | 在 ExecStop 命令执行之后运行的命令 |
Restart | 定义何时自动重启服务,如 always、on-success、on-failure、on-abnormal 等 |
RestartSec | 自动重启服务之间的时间间隔 |
TimeoutStartSec | 服务启动超时时间 |
TimeoutStopSec | 服务停止超时时间 |
RuntimeMaxSec | 服务的最长运行时间,超过该时间将被终止 |
WatchdogSec | 服务的看门狗超时时间,超过该时间未收到任何信号将被视为不正常 |
User | 以指定用户身份运行服务 |
Group | 以指定组身份运行服务 |
Environment | 定义服务运行时的环境变量 |
EnvironmentFile | 从指定文件中导入环境变量 |
WorkingDirectory | 定义服务运行时的工作目录 |
LimitNOFILE | 定义服务允许打开的最大文件描述符数量 |
LimitNPROC | 定义服务允许创建的最大进程数量 |
Nice | 定义服务的优先级 |
OOMScoreAdjust | 调整服务在内存不足时被杀死的优先级 |
KillMode | 定义服务终止时的进程杀死模式,如 control-group、process、mixed、none 等 |
StandardInput | 定义服务的标准输入来源,如 null、tty、socket 等 |
StandardOutput | 定义服务的标准输出目的地,如 null、journal、tty、socket 等 |
StandardError | 定义服务的标准错误输出目的地,如 null、journal、tty、socket 等 |
1
2
3
4
5
6
7
8
9
10
11
12
| // 查看某个服务的配置文件
$ systemctl cat nginx.service
// 列出所有配置文件
$ systemctl list-unit-files
// 列出指定类型的配置文件
$ systemctl list-unit-files --type=service
// 一旦修改配置文件,需要重新加载配置并重启启动
$ sudo systemctl daemon-reload
$ sudo systemctl restart nginx.service
|
为 systemd
创建和配置 unit
文件,需要遵循以下步骤:
- 创建
unit
文件:在 /etc/systemd/system
目录下创建一个新的 unit
文件。文件名应该包含服务名称和适当的扩展名,例如 my-custom-service.service
:
1
| $ sudo touch /etc/systemd/system/my-custom-service.service
|
- 编辑
unit
文件:使用文本编辑器(如 nano、vim 或 gedit)打开新创建的 unit
文件,并添加相应的配置:
1
| $ sudo vim /etc/systemd/system/my-custom-service.service
|
- 编写
unit
文件内容:根据服务的需求,在 unit
文件中添加相应的配置。以下是一个简单的 service unit
示例:
1
2
3
4
5
6
7
8
9
10
11
12
| [Unit]
Description=My Custom Service
After=network.target
[Service]
ExecStart=/usr/bin/my-custom-service --option1
Restart=always
User=myuser
Group=mygroup
[Install]
WantedBy=multi-user.target
|
- 保存并关闭
unit
文件:在编辑器中保存更改并关闭 unit
文件。 - 重新加载
systemd
配置:运行以下命令,让 systemd
重新加载配置:
1
| $ sudo systemctl daemon-reload
|
- 启动新创建的
unit
:使用以下命令启动新创建的 unit
:
1
| $ sudo systemctl start my-custom-service
|
- 设置
unit
开机启动(可选):如有必要,可以使用以下命令使 unit
随系统启动:
1
| $ sudo systemctl enable my-custom-service
|
- 检查
unit
状态:要检查 unit
的状态,可以使用以下命令:
1
| $ sudo systemctl status my-custom-service
|
Service unit (.service)
Service unit
文件用于描述系统服务的启动、停止、重启等行为。一个简单的 service unit
示例:
1
2
3
4
5
6
7
8
9
10
11
12
| [Unit]
Description=My Custom Service
After=network.target
[Service]
ExecStart=/usr/bin/my-custom-service --option1
Restart=always
User=myuser
Group=mygroup
[Install]
WantedBy=multi-user.target
|
Socket unit (.socket)
Socket unit
文件用于描述进程间通信的 socket
。一个简单的 socket unit
示例:
1
2
3
4
5
6
7
8
9
| [Unit]
Description=My Custom Service Socket
[Socket]
ListenStream=/run/my-custom-service/socket
Accept=yes
[Install]
WantedBy=sockets.target
|
Timer unit (.timer)
Timer unit
文件用于描述定时触发的任务。一个简单的 timer unit
示例:
1
2
3
4
5
6
7
8
9
| [Unit]
Description=Run my custom service every hour
[Timer]
OnCalendar=*-*-* *:00:00
Persistent=true
[Install]
WantedBy=timers.target
|
Target
在 Systemd 中,Target(目标)的作用是将一组相关的 Unit(单元)组织到一起,为它们提供一个统一的同步点。Target 本身并不执行任何操作,但它们定义了系统中不同服务和组件之间的关系,提供了一个有序的启动和停止方式。这有点类似于 System V init 系统中的运行级别(runlevels),但比运行级别更灵活。
Target可以帮助管理系统的不同状态和功能,例如:
- 将系统从单用户模式切换到多用户模式。
- 在系统启动过程中,确保基本系统服务(如日志记录、网络配置等)已启动,然后再启动其他服务。
- 根据需要启动和停止一组相关服务,而不是逐个启动和停止它们。
通过使用 Target,系统管理员可以轻松地按需启动、停止和管理服务,以及在不同的系统状态之间进行切换。一些常见的 Target 示例包括无图形界面多用户模式(multi-user.target
)、图形模式(graphical.target
)和引导系统重启的目标(reboot.target
)等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // 查看当前系统的所有 Target
$ systemctl list-unit-files --type=target
// 查看一个 Target 包含的所有 Unit
$ systemctl list-dependencies multi-user.target
// 查看启动时的默认 Target
$ systemctl get-default
// 设置启动时的默认 Target
$ sudo systemctl set-default multi-user.target
// 关闭前一个 Target 里面所有不属于后一个 Target 的进程
$ sudo systemctl isolate multi-user.target
|
Target 与 System V init 系统中的 RunLevel 有一定的对应关系,但请注意,Target 提供了更灵活的方式来管理系统状态。以下是一些常见的 Target 与 RunLevel 之间的对应关系:
RunLevel | Target | Desc |
---|
0 | runlevel0.target | 关闭系统 |
1 | runlevel1.target | 单用户模式,用于系统维护 |
2 | runlevel2.target | 多用户模式,不包含网络服务 |
3 | runlevel3.target | 多用户模式,包含网络服务 |
4 | runlevel4.target | 未定义,可由系统管理员自定义用途 |
5 | runlevel5.target | 多用户模式,包含网络服务和图形用户界面(GUI) |
6 | runlevel6.target | 重新启动系统 |
- | emergency.target | 紧急模式,提供最小系统功能以进行故障排除 |
- | rescue.target | 救援模式,类似于单用户模式,用于系统维护和故障排除 |
- | multi-user | .target 多用户模式,不包含图形用户界面 |
- | graphical.target | 多用户模式,包含图形用户界面 |
- | halt.target | 关闭系统,但不断电 |