systemd基础知识简介
1. 简介
什么是 systemd?
它是一个服务管理的工具。systemd将任务组织成称为单元(units )的组件,并将单元组组织成目标(targets)。
想象一下,您的 Linux 操作系统是一个大公司,而 systemd 就是这个公司的“大管家”。它不仅管理公司里的各个部门(也就是系统和服务),还负责确保公司每天都能顺利开业并运行(也就是系统的初始化和维护)。
systemd 是 Linux 操作系统的一个“大管家”,它负责管理整个系统的运行和各种服务。对于大多数 Linux 发行版来说,systemd 都是默认的启动(初始化)系统。
这个“大管家”不是由用户直接请来的,而是在系统安装时就已经安排好了。它通过一个叫 /sbin/init 的“邀请函”被系统内核直接请来,并在系统开机早期就开始工作。
当systemd作为开机后第一个运行的程序(PID 1,也叫init)时,它就开始扮演“大管家”的角色,负责启动和维持用户空间的服务。这个“大管家”会一直工作,直到系统关机。
除了是“大管家”外,systemd还拥有 PID 1 的身份,并且是由系统内核直接启动的。系统里的其他程序都是由 systemd 或其子程序直接启动的。systemd 还负责挂载主机的文件系统和管理临时文件。而且,它还能兼容以前那种老式的SysV启动脚本。
在 systemd 里,有一个叫“单元”(unit)的东西,它是系统能够操作和管理的一种资源。这是 systemd 工具主要使用的对象。这些资源都是通过叫“单元文件”(unit files)的配置文件来定义的。
systemctl 是控制这个“大管家”的中心管理工具,可以用来查看和控制 systemd 系统和服务管理器的状态。
在 systemd 里,还有一些叫“目标”(targets)的东西,它们是一组相关的单元,在系统启动时作为同步点。目标单元文件有 .target 的文件扩展名。目标单元通过一系列的依赖关系将各种 systemd 单元组合在一起。
如果遇到问题,你可以使用 journalctl 来查询和显示 systemd 日志中的消息,帮助进行故障排除。
想了解更多关于 systemd 的信息,你可以访问 https://systemd.io 网站或查看 systemd 的手册页(man 1 systemd)。
2. 关于 systemd 启动
开机启动的第一步是加载 Linux 内核,这是 Linux 操作系统的核心部分。内核加载完成后,它会初始化硬件,并启动 systemd 进程,这是系统上运行的第一个进程。
2.1. linux 启动过程
Linux 启动流程是操作系统启动的初始阶段。这是操作系统加载内存、初始化组件并准备执行用户应用程序的过程。
Linux 启动流程主要分为四个阶段:
阶段一:BIOS
当你打开电脑时,电脑会启动 BIOS(基本输入输出系统)并进行 POST(开机自检)。这是一个完整性检查,用于检测硬盘、SSD、键盘、RAM、USB 端口等组件的硬件功能。如果硬件工作正常,启动流程就会进入下一阶段。
阶段二:引导加载程序
POST 完成后,BIOS 会搜索并加载存储在 MBR(主引导记录)中的引导加载程序。MBR 是一段 512 字节的代码,通常根据你的硬盘架构位于 /dev/sda 或 /dev/hda。MBR 也可以位于 Linux 的 U 盘或 DVD 安装介质上。BIOS 会加载并执行这段 MBR 代码。
Linux 中有三种主要的引导加载程序:LILO、GRUB 和 GRUB2。GRUB2(第二代统一引导加载程序)是现代 Linux 发行版中最新的也是主要的引导加载程序。GRUB2 的配置文件位于 /boot/grub2/grub2.cfg。一旦 BIOS 找到 GRUB2 引导加载程序,它就会执行并将其加载到主内存(RAM)中。
阶段三:Linux 内核初始化
Linux 内核是操作系统的核心。在你的 Linux 系统中,内核与硬件进行交互,控制内存管理并管理进程。引导加载程序会加载你选择的 Linux 内核。内核会从压缩版本中自行解压并挂载根文件系统。然后,它会运行 /sbin/init 程序。
阶段四:systemd
内核加载 systemd,这是 Linux 操作系统的系统和服务管理器。然后,systemd 会运行所有其他的初始化进程。
2.2. 使用 systemd 的启动流程
一旦内核加载了 systemd,systemd 就会接管并启动其他使系统启动并运行所需的系统服务。这包括网络服务、登录管理器等服务。
启动流程是按照特定目标单元的执行顺序并行进行的。systemd 使用 /etc/systemd/system/default.target 文件来确定 Linux 系统应该启动到的目标。这个文件是一个指向 graphical.target 的链接,graphical.target 会启动图形登录管理器。systemd 会激活 default.target 的所有依赖目标单元,以及这些依赖项的递归依赖项。一旦所有服务都启动完毕,你的系统就可以使用了,登录管理器也会显示出来。现在,你可以登录并开始使用系统了。
2.3. 使用 systemd-analyze 命令分析系统启动流程性能
使用 systemd-analyze
命令来分析系统启动流程的性能。该命令还可以用于从系统和服务管理器中检索其他状态和跟踪信息。它用于检查单元文件是否正确,还可以访问对高级系统管理器调试有用的特殊功能。
一些示例包括:
2.3.1. 查看系统启动所需的时间
systemd-analyze time
Startup finished in 3.404s (kernel) + 2.415s (initrd) + 13.125s (userspace) = 18.945s
graphical.target reached after 13.117s in userspace
2.3.2. 获取启动过程的高级概述,其中包括启动的服务以及每个服务启动所需的时间
systemd-analyze critical-chain
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.
graphical.target @13.117s
└─multi-user.target @13.117s
└─getty.target @13.117s
└─getty@tty1.service @13.116s
└─plymouth-quit-wait.service @10.775s +2.338s
└─systemd-user-sessions.service @10.769s +3ms
└─remote-fs.target @10.764s
└─iscsi.service @10.747s +16ms
└─network-online.target @10.744s
└─NetworkManager-wait-online.service @1.547s +9.197s
└─NetworkManager.service @1.507s +37ms
└─network-pre.target @1.504s
└─wpa_supplicant.service @2.341s +5ms
└─dbus.service @1.042s
└─basic.target @1.036s
└─sockets.target @1.036s
└─snapd.socket @1.035s +590us
└─sysinit.target @1.030s
└─systemd-update-utmp.service @1.025s +5ms
└─auditd.service @976ms +47ms
└─systemd-tmpfiles-setup.service @964ms +9ms
└─local-fs.target @962ms
└─snapd.mounts.target @961ms
└─snap-core18-2796.mount @417ms +543ms
└─dev-loop9.device @961ms +628us
此命令会为每个指定的单元或默认目标打印一个时间关键单元的树状结构。服务的初始化可能依赖于套接字激活和单元的并行执行。与 blame
命令类似,它会显示一个单元激活所需的时间,但对于像设备单元这样直接过渡到活动状态的单元,其激活时间是没有定义的。
2.3.3. 查看启动过程中启动的服务列表,并根据每个服务所花费的时间显示
systemd-analyze blame
9.197s NetworkManager-wait-online.service
4.002s fwupd.service
2.338s plymouth-quit-wait.service
1.282s dracut-pre-udev.service
1.062s sys-devices-platform-serial8250-tty-ttyS0.device
1.062s dev-ttyS0.device
1.061s dev-ttyS1.device
1.061s sys-devices-platform-serial8250-tty-ttyS1.device
1.060s dev-ttyS11.device
1.060s sys-devices-platform-serial8250-tty-ttyS11.device
1.059s sys-devices-platform-serial8250-tty-ttyS13.device
1.059s dev-ttyS13.device
1.059s sys-devices-platform-serial8250-tty-ttyS10.device
1.059s dev-ttyS10.device
1.058s sys-devices-platform-serial8250-tty-ttyS14.device
1.058s dev-ttyS14.device
1.058s dev-ttyS12.device
1.058s sys-devices-platform-serial8250-tty-ttyS12.device
1.056s sys-devices-platform-serial8250-tty-ttyS17.device
一个服务的初始化可能会很慢,因为它在等待另一个服务的初始化完成。此命令会显示一个单元激活所需的时间,但对于像设备单元这样直接过渡到活动状态的单元,其激活时间是没有定义的。此命令不会显示 Type=simple 类型服务的结果,因为 systemd 认为这些服务会立即启动,因此无法分析它们的初始化延迟。
2.3.4. 生成一个矢量图形文件,显示启动过程中发生的事件
systemd-analyze plot > /temp/sample.svg
此命令会在临时目录中创建一个 SVG 文件。SVG 文件是一个文本文件,它定义了一组图形向量,LibreOffice Draw 等应用程序可以使用这些向量来生成图形。
3. 单元文件的结构
在 systemd 中,单元(unit)指的是系统知道如何操作和管理的任何资源。这是 systemd 工具使用的主要对象。这些资源通过称为单元文件的配置文件进行定义。当你使用 systemd 时,如果了解单元文件,管理起来会更方便。单元文件使用简单的声明式语法,让你能够轻松了解单元激活后的目的和效果。单元文件包含带有指令的节(section),例如:
[Section]
Directive1=value
Directive2=value
. . .
单元文件类型包括以下部分:
[Unit]
大多数单元文件中的第一个部分是 [Unit] 节。此部分用于定义单元文件的元数据,并配置单元文件与其他单元文件的关系。此部分通常放在顶部,因为它提供了单元文件的概述。
[Automount] / [Mount] / [Path] / [Service] / [Slice] / [Socket] /[Swap] / [Timer]
包含特定于相应类型的指令的部分。有关可用类型的列表,请参阅下面的“单元文件类型”。请注意,device、target、snapshot 和 scope 类型没有特定类型的部分。
[Install]
这通常是单元文件中的最后一个部分,并且是可选的。此部分用于定义当单元文件被启用或禁用时的行为。当你启用一个单元文件时,它会在启动时自动启动。根据具体的单元,可能需要依赖其他相关单元才能正常工作。例如,chrony 需要 After、Wants 和 Before 指令,这些都是 chrony 正常工作所需的依赖项。
示例 1:systemd 服务文件
[Unit]
Description=usbguard
[Service]
ExecStart=/usr/sbin/usb-daemon
[Install]
WantedBy=multi-user.target
[Unit]
一段简短而有意义的描述,解释服务文件的目的。
[Service]
指定服务启动时要执行的程序。
[Install]
启动带有网络功能的多用户系统,但不包含图形环境。此指令允许您指定依赖关系。
4. 单元文件类型
您可以通过文件扩展名来确定单元的类型。systemd 根据它们描述的资源类型对单元进行分类。
systemd 可用的单元文件类型:
.service
描述如何管理一个服务或应用程序。这包括如何启动或停止服务,重新加载其配置文件(如果适用),在什么条件下服务会自动启动,以及相关单元文件的依赖或层级信息。
.scope
这个单元文件是由 systemd 根据从 D-Bus 接口接收到的信息自动创建的,用于管理由外部创建的系统进程集合。
.path
定义基于路径的激活路径。默认情况下,会激活同名基本名称的 .service 单元文件。inotify 是一个内核 API,被想要接收文件变化通知的程序使用。
.snapshot
systemctl snapshot 命令自动创建一个 .snapshot 单元文件。这个命令创建当前系统状态的临时快照。您可以在做出更改后修改当前系统状态。快照用于回滚临时状态。
.timer
定义由 systemd 管理的计时器。这类似于用于延迟或计划激活的 cron 作业。当计时器到达时,会启动同名但文件扩展名为 .service 的单元文件。
.slice
关联 Linux 控制组节点,这些节点允许将资源分配或限制给与切片关联的任何进程。名称指示控制组树中的层级。单元默认根据其类型放置在切片中。
.target
在启动或状态变化期间为其他单元提供同步,或将系统带到新状态。其他单元指定它们与目标的关系,以便与目标的操作同步。
.socket
描述 systemd 用于基于套接字激活的网络、IPC 套接字或 FIFO 缓冲区。有一个相关的 .service 文件,当在该单元定义的套接字上看到活动时启动。
.device
定义由 udev 或 sysfs 文件系统指定给 systemd 管理的设备。并非所有设备都有 .device 文件。当排序、挂载或访问设备时需要这个单元文件。
.swap
定义系统上的交换空间。单元文件的名称必须反映空间的设备或文件路径。
.mount
定义由 systemd 管理的系统上的挂载点。此文件以挂载路径命名,斜杠替换为短划线。/etc/fstab 中的条目可以自动创建单元。
.automount
定义自动挂载的挂载点。根据它所指的挂载点命名文件。需要一个匹配的 .mount 单元文件来定义挂载的具体细节。
5. 单元依赖性和执行顺序
systemd 有两种类型的依赖关系:需求依赖和顺序依赖。需求依赖指定在激活一个单元时,必须启动或停止哪些其他单元。顺序依赖指定单元必须启动的顺序。
5.1. 单元依赖
单元文件具有依赖功能。一个单元可能在运行前需要一个或多个其他单元。这些依赖关系通过单元文件中的 Wants 和 Requires 指令设置。
Wants
例如,如果单元 A 有 Wants=单元 B,当运行单元 A 时,单元 B 也会运行。但如果单元 B 是否成功启动,不影响单元 A 成功运行。
Requires
如果单元 A 有 Requires=单元 B,两个单元都会运行,但如果单元 B 没有成功运行,单元 A 将被停用。即使单元 A 的进程本可以成功运行也无关紧要。
5.2. 顺序依赖
如果没有适当的指令,systemd 可以同时运行一组单元。以正确的顺序启动服务对于 Linux 系统的良好运行非常重要。您可以使用单元文件指令 Before 和 After 来安排顺序。
Before
例如,如果单元 A 有 Before=单元 B,当两个单元都运行时,单元 A 会在单元 B 之前完全执行。
After
如果单元 A 有 After=单元 B,当两个单元都运行时,单元 B 会在单元 A 之前完全执行。
6. 日志记录
日志文件和日志记录对于系统管理非常重要。它们提供了系统的详细信息,对于故障排除和审计至关重要。日志文件包含了由内核、应用程序以及登录系统的用户生成的事件和消息。您可以使用 journalctl 命令来查询日志记录。这个命令查看由 systemd 收集的日志。systemd-journald
服务处理 systemd 的日志收集。systemd-journald 以二进制格式保存事件和消息。
7. systemd targets
systemd 使用单元(units)和目标(targets)。一个 systemd 单元定义了系统上的一个服务或动作,它由名称、类型和配置文件组成。一个 systemd 目标结合了几个单元,并定义了为了达到目标必须启动哪些服务。例如,在服务器上,这可能是网络正在运行且多个用户可以登录的状态。这些文件通过后缀 .target 来识别。
类似于单元文件,不同的目标可以通过依赖关系进行嵌套。例如,multi-user.target 需要(除其他外)设置登录和用户会话服务的目标。
常见的 systemd 目标:
default.target
默认启动。default.target 文件是一个符号链接,指向真正的目标文件,例如桌面工作站的 graphical.target。对于服务器,通常是 graphical.target。
poweroff.target
关闭并关闭系统电源。
rescue.target
目标单元,它拉起基础系统并启动一个救援 shell 会话。
multi-user.target
设置一个非图形化(控制台)的多用户系统。
graphical.target
使用带有网络服务的图形化多用户系统。
reboot.target
关闭并重启系统。
有关 systemd 目标的更多信息,请参考 man 5 systemd.target 和 man 7 systemd.special。
8. 以普通用户身份使用systemd
您可以使用 systemd 作为普通用户,以提高安全性或在您没有 root 用户权限时使用。通过创建用户服务,可以运行非特权服务。
在创建和使用用户服务时,请考虑以下几点:
- 用户服务会在用户会话结束时被终止。这可以通过使用
loginctl enable-linger USERNAME
命令来覆盖。 - 用户服务文件位于
/etc/systemd/user
或$HOME/.config/systemd/user/
。 - 您可以使用
systemctl --user
命令来控制用户服务。
9. systemctl命令概述
systemctl
命令用于检查和控制 systemd 和服务管理器的状态。
您可以使用以下常见的 systemctl
命令,并参考 man systemctl
页面。
9.1. 查看 systemd 信息
要查看关于 systemd 组件的信息,您可以使用以下命令:
systemctl list-units
列出 systemd 单元。您可以使用可选参数:--state=running
显示活动单元,--type=service
显示已退出和活动单元。
systemctl list-unit-files
列出 systemd 单元及其状态,例如静态、生成、禁用、别名、屏蔽和启用。
systemctl list-dependencies
列出依赖树。
systemctl list-dependencies UNIT_FILE
列出单元文件的依赖关系。
9.2. 管理 systemd 服务
systemctl
命令使您能够执行以下与服务相关的任务。
systemctl status SERVICE
检查特定服务的状态。
systemctl show SERVICE
显示服务信息。
systemctl start SERVICE
代替手动启动服务,使用 start 命令。当配置文件发生变化时,必须重新启动相关服务。
systemctl stop SERVICE
停止特定正在运行的服务。
systemctl restart SERVICE
代替手动重启服务,使用 restart 命令。当配置文件发生变化时,必须重新启动相关服务。
systemctl enable SERVICE
在启动时启用服务。
systemctl disable SERVICE
在启动时禁用服务。
systemctl reload-or-restart SERVICE
如果服务支持重新加载,则重新加载服务,否则重启服务。如果服务未运行,则会重启。
systemctl mask SERVICE
当服务被屏蔽时,这意味着单元文件被符号链接到 /dev/null。屏蔽服务的符号链接从 /etc/systemd/system 指向 /dev/null 创建。即使另一个启用的服务需要它,这也会使得加载服务变得不可能。它必须手动停止,或者它会继续在后台运行。您可以使用 --runtime
选项仅在系统下一次重启之前临时屏蔽。
Created symlink /etc/systemd/system/FOSSLinux.service → /dev/null.
systemctl unmask SERVICE
取消屏蔽服务。当系统启动或手动重启时生效。
9.3. 管理系统状态
systemctl
命令使您能够执行电源管理过程,如重启、关闭等,如下所述。
systemctl reboot
重启系统 reboot.target。
systemctl poweroff
关闭系统 poweroff.target。
systemctl emergency
进入紧急模式 emergency.target。
systemctl default
返回默认目标 multi-user.target。
10. systemd故障排除
您可以使用以下故障排除提示来识别和解决 systemd 服务的问题,并确保系统运行顺畅。
检查 systemd 单元文件的语法
在启动或启用 systemd 服务之前,检查单元文件的语法以确保没有错误。例如:
sudo systemd-analyze verify /etc/systemd/system/my-custom-service.service
该命令分析单元文件并报告任何语法错误、缺失文件或其他问题。在启用和启动服务之前,您必须修复任何报告的问题。
检查服务的日志
如果您遇到任何 systemd 服务的问题,请检查服务的日志。例如:
sudo journalctl -u my-custom-service.service
该命令显示指定服务的日志,包括任何错误消息、警告或其他相关信息。您可以使用这些日志来识别和修复服务的问题。
使用 systemd-analyze plot 命令可视化启动过程
如果服务在启动过程中引起问题,您可以使用 systemd-analyze plot 命令来可视化启动过程并识别问题。例如:
sudo systemd-analyze plot > boot-plot.svg
该命令创建一个名为 boot-plot.svg 的 SVG 文件,其中包含启动过程和潜在问题的图形表示。这包括每个服务的启动和停止时间。您可以在 SVG 兼容的图像查看器或 Web 浏览器中打开此文件,以分析在启动过程中引起问题的服务。
故障排除失败的服务
要找出哪些服务失败并检查日志输出:
sudo systemctl --state=failed
检查服务的运行时状态
要了解服务的当前运行时状态:
sudo systemctl status SERVICE
关机或重启耗时过长
如果关机或重启耗时过长,可能是因为某个服务没有退出。systemd 会等待每个服务退出一段时间,然后尝试终止它。一个常见问题是服务挂起或关闭操作停滞。要找出原因,请使用以下命令:
sudo systemctl poweroff
Failed to power off system via logind: There's already a shutdown or sleep operation in progress
sudo systemctl list-jobs
您可以取消正在运行和等待的任务,然后再次关闭或重启:
sudo systemctl cancel
sudo systemctl stop systemd-suspend.service
11. systemd最佳实践
您可以遵循一些最佳实践,以确保 systemd 服务高效且能够处理不同情况。
检查服务的运行时状态
要了解服务的当前运行时状态:
sudo systemctl status SERVICE
在 systemd 单元文件中使用绝对路径
在 systemd 单元文件中,对于可执行文件和所需的文件(如配置文件或脚本),请使用绝对路径。systemd 不依赖于用户的环境变量(如 $PATH
)来定位文件。
使用 ExecReload 指令
当您想要定义在重新加载服务时(使用 systemctl reload
命令)应执行的特定命令时,在 [SERVICE]
部分使用 ExecReload
指令。这对于可以动态重新加载配置而无需重启的服务很有用。
[Service]
ExecStart=PATH_TO_EXECUTABLE
ExecReload=PATH_TO_RELOAD_SCRIPT
使用 RestartSec 指令
当您想要定义服务在失败后重启前的延迟时间(以秒为单位)时,在 [SERVICE]
部分使用 RestartSec
指令。这对于需要指定时间来释放资源或防止可能导致高系统负载的快速重启循环的服务很有用。
[Service]
ExecStart=PATH_TO_EXECUTABLE
Restart=on-failure
RestartSec=5
在远程机器上禁用紧急模式
您可以在远程机器上禁用紧急模式,例如托管在 Google Cloud 上的虚拟机。如果启用了此模式,机器将被阻止连接到网络。例如:
sudo systemctl mask emergency.service
sudo systemctl mask emergency.target
12. 引用
https://documentation.suse.com/en-us/sle-micro/6.0/html/Micro-systemd-basics/index.html