目录

Linux Systemd

Systemd 是 Linux 系统工具,是用来启动守护进程的,已经成为大多数发行版的标配了。每次用起来我能顺手的也就启动重启停止,其它的都要查,烦死了,还不如干脆记录一下。

Systemd 背景

在操作系统中,init 进程是一个特殊的进程,它是系统启动后运行的第一个进程。init 进程负责启动和管理其他系统进程,并在系统运行期间一直存在。它是操作系统中所有其他进程的祖先。

关于 init 进程的一些信息:

  • 进程标识符init 进程始终具有进程标识符 (PID) 为 1 的属性。这使得其他进程可以轻松地将其子进程传递给 init 进程进行管理,从而避免产生僵尸进程。
  • 启动其他进程init 进程负责启动其他系统进程,例如:守护进程、服务、用户空间应用程序等。通常,init 进程根据系统的初始化脚本或配置文件来启动这些进程。
  • 管理孤儿进程:当一个父进程终止,而其子进程仍在运行时,这些子进程会成为孤儿进程。init 进程会自动采纳这些孤儿进程,并负责回收它们的资源,防止系统出现僵尸进程。
  • 系统关机与重启init 进程在系统关机或重启时负责正确地终止其他进程。它会按照预定顺序发送信号,通知进程执行清理操作并安全退出。
  • 不同的 init 系统:随着时间的推移,有多种 init 系统出现,包括 System V initUpstartsystemd。其中,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 功能紧密集成,允许对进程进行资源限制、隔离和管理。这有助于确保系统资源的公平分配,从而提高系统的稳定性。
  • 集中式日志管理:通过 journaldsystemd 提供了一个集中式日志管理系统。journald 可以收集、存储和管理系统日志,方便管理员分析问题和故障排查。
  • 简化的服务配置systemd 使用名为 Unit 文件的简单配置文件来管理服务。这些文件易于编写和维护,并提供了丰富的选项来定义服务的行为和属性。
  • 命令行工具systemd 提供了一组强大的命令行工具,如 systemctljournalctl,用于管理和查询系统服务和日志。这些工具使管理员能够轻松地控制系统服务和获取相关信息。
  • 向后兼容性:尽管 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表示硬件设备,描述系统设备,通常由 udevsystemd 自动生成。
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 NameDesc
[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 NameDesc
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 NameDesc
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 之间的对应关系:

RunLevelTargetDesc
0runlevel0.target关闭系统
1runlevel1.target单用户模式,用于系统维护
2runlevel2.target多用户模式,不包含网络服务
3runlevel3.target多用户模式,包含网络服务
4runlevel4.target未定义,可由系统管理员自定义用途
5runlevel5.target多用户模式,包含网络服务和图形用户界面(GUI)
6runlevel6.target重新启动系统
-emergency.target紧急模式,提供最小系统功能以进行故障排除
-rescue.target救援模式,类似于单用户模式,用于系统维护和故障排除
-multi-user.target 多用户模式,不包含图形用户界面
-graphical.target多用户模式,包含图形用户界面
-halt.target关闭系统,但不断电