linux init系统和系统管理器-Systemd学习

一、Systemd 概述

1.1、init 程序介绍及其发展历程

Linux init程序是系统启动时第一个启动的进程,它负责初始化系统资源,加载操作系统核心模块,启动系统服务和用户进程。init程序是系统启动的重要组成部分,它为后续的系统操作提供了基本的环境。init程序通常是由操作系统内核启动,并且是用户态进程,init 程序,路径为 /sbin/init(为一个软连接,链接到真实的 init 进程),其 PID 为1,它为系统里所有进程的“祖先”,Linux 中所有的进程都由 init 进程直接或间接进行创建并运行,init 进程以守护进程的方式存在,负责组织与运行系统的相关初始化工作,让系统进入定义好的运行模式。在Linux中,init程序有多种实现方式,比如SysV init、Upstart和Systemd等。

init 程序的发展,大体上可分为三个阶段:sysvinit->upstart->systemd,根据 init 进程的发展特性,可以简单理解为如下:

SysV init

最早的Linux发行版使用的是SysV init(System V init),它采用脚本的形式来管理系统服务。在启动过程中,SysV init会按照特定的顺序启动系统服务,并运行对应的启动脚本。SysV init的缺点是启动速度比较慢,因为它需要按照顺序逐个启动服务。

Upstart

Ubuntu从8.04版本开始采用Upstart作为init程序,Upstart是一种事件驱动的init程序,可以并行启动多个服务,提高系统启动速度。Upstart使用配置文件来管理系统服务,它能够自动监测服务的状态,可以在服务崩溃或停止运行时自动重启服务。

Systemd

Systemd是目前最流行的init程序,大多数Linux发行版都采用了Systemd作为默认的init程序。通过套接字激活的机制,让所有无论有无依赖关系的程序全部并行启动,并且仅按照系统启动的需要启动相应的服务,最大化提高开机启动速度。Systemd使用单个配置文件来管理所有服务,并提供了丰富的命令行工具来管理服务。Systemd还支持动态加载和卸载服务,可以在系统运行时添加或删除服务。

1.2、Systemd 架构

在这里插入图片描述

systemd体系架构如下:

  • 最底层:​​systemd 内核层​​面依赖 cgroup、autofs、kdbus
  • 第二层:​​systemd libraries​​ 是 systemd 依赖库
  • 第三层:​​systemd Core​​ 是 systemd 自己的库
  • 第四层:​​systemd daemons​​ 以及 targets 是自带的一些基本 unit、target,类似于 sysvinit 中自带的脚本
  • 最上层就是和 systemd 交互的一些工具,比如systemctl;

在这里插入图片描述

1.3、Systemd 的守护进程

systemd 的守护进程主要分为系统态(system)与用户态(user)

ps -aux | grep systemd
root          1  0.1  0.0  50144  5864 ?        Ss    2022 361:29 /usr/lib/systemd/systemd --system --deserialize 17
root        618  0.0  0.0  44680  3632 ?        Ss    2022   0:00 /usr/lib/systemd/systemd-udevd
dbus        827  0.1  0.0  58228  4228 ?        Ss    2022 315:04 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
root        884  0.0  0.0  27208  3696 ?        Ss    2022 133:08 /usr/lib/systemd/systemd-logind
root      26750  0.0  0.0 112828  2320 pts/2    S+   16:29   0:00 grep --color=auto systemd
root      34868  0.1  0.0 100940 56832 ?        Ss   Mar18 111:11 /usr/lib/systemd/systemd-journald

进程关系如下:

pstree -p | grep systemd
systemd(1)-+-xxx(17036)-+-{
    
    xxx}(17037)
           |                   |-containerd-shim(88298)-+-systemd(88315)
           |-systemd-journal(34868)
           |-systemd-logind(884)
           `-systemd-udevd(618)

PID 为1的进程/sbin/init 即是 system 态的 systemd,它为一个软链接,指向真实的 systemd 路径,在操作系统中一般放在/usr/lib/systemd/目录:

ll /usr/sbin/init
lrwxrwxrwx. 1 root root 22 Mar  4  2022 /usr/sbin/init -> ../lib/systemd/systemd

ll /usr/lib/systemd/systemd
-rwxr-xr-x. 1 root root 1632800 Mar  4  2022 /usr/lib/systemd/systemd

systemd 为进程服务集合的总称,它包含许多的进程,负责控制、管理系统的资源,其中包括 systemd-login,负责用户登录相关信息的创建、修改与删除;systemd-sleep 控制系统的休眠、睡眠状态切换等等。在优麒麟操作系统下,它们主要集中在/usr/lib/systemd/文件目录:

ls /usr/lib/systemd/
catalog                 rhel-loadmodules   systemd-cgroups-agent     systemd-localed            systemd-remount-fs      systemd-timedated       system-sleep
import-pubring.gpg      rhel-readonly      systemd-coredump          systemd-logind             systemd-reply-password  systemd-udevd           user
ntp-units.d             system             systemd-cryptsetup        systemd-machined           systemd-rfkill          systemd-update-done     user-generators
rhel-autorelabel        systemd            systemd-fsck              systemd-machine-id-commit  systemd-shutdown        systemd-update-utmp     user-preset
rhel-configure          systemd-ac-power   systemd-hibernate-resume  systemd-modules-load       systemd-shutdownd       systemd-user-sessions
rhel-dmesg              systemd-activate   systemd-hostnamed         systemd-pull               systemd-sleep           systemd-vconsole-setup
rhel-dmraid-activation  systemd-backlight  systemd-importd           systemd-quotacheck         systemd-socket-proxyd   system-generators
rhel-domainname         systemd-binfmt     systemd-initctl           systemd-random-seed        systemd-sysctl          system-preset
rhel-import-state       systemd-bootchart  systemd-journald          systemd-readahead          systemd-sysv-install    system-shutdown

二、Systemd 特点

Systemd是一个用于Linux系统的init系统和系统管理器,它是目前最流行的init系统之一,也是许多主流Linux发行版(如Fedora、Red Hat Enterprise Linux、Debian等)的默认init系统。Systemd在Linux系统的启动、服务管理、日志记录等方面提供了很多改进和优化。

2.1、兼容性

systemd 提供了和 SysV init 兼容的特性。比如可以通过 SysV 兼容性模式来支持 SysV init 的脚本,还可以通过 systemd-sysv-generator 工具来将 SysV init 脚本转换为 Systemd 的服务单元,从而实现对 SysV 进程的支持。系统中已经存在的服务和进程无需修改。这降低了系统向 systemd 迁移的成本,使得 systemd 替换现有初始化系统成为可能。

2.2、启动速度

Systemd 是一个并行启动的 init 系统,相比于传统的 SysV init,它可以并行启动多个服务,从而提高系统的启动速度。
Systemd 启动速度的快慢取决于系统中启动的服务数量和服务启动顺序。

在启动过程中,Systemd 会根据服务之间的依赖关系并行启动服务,从而尽量减少服务之间的等待时间,提高启动速度。同时,Systemd 还会对服务进行优先级排序,将优先级高的服务优先启动,加快系统启动的时间。

除了并行启动之外,Systemd 还提供了一些优化措施来提高启动速度。例如,它使用二进制日志格式来记录系统日志,相比于传统的文本日志格式,可以更快地进行解析和搜索。此外,Systemd 还支持动态加载和卸载服务,可以在系统运行时添加或删除服务,而无需重启系统,从而减少了系统的停机时间。

总的来说,Systemd 启动速度相对较快,可以在大部分系统上实现快速启动,同时还提供了一些优化措施来进一步提高启动速度。

2.3、systemd 提供按需启动能力

当 sysvinit 系统初始化的时候,它会将所有可能用到的后台服务进程全部启动运行。并且系统必须等待所有的服务都启动就绪之后,才允许用户登录。这种做法有两个缺点:首先是启动时间过长,其次是系统资源浪费。

某些服务很可能在很长一段时间内,甚至整个服务器运行期间都没有被使用过。比如 CUPS,打印服务在多数服务器上很少被真正使用到。您可能没有想到,在很多服务器上 SSHD 也是很少被真正访问到的。花费在启动这些服务上的时间是不必要的;同样,花费在这些服务上的系统资源也是一种浪费。

systemd 可以提供按需启动的能力,只有在某个服务被真正请求的时候才启动它。当该服务结束,systemd 可以关闭它,等待下次需要时再次启动它。
这有点类似于以前系统中的 inetd,并且有很多文章介绍如何把过去 inetd 管理的服务迁移到 systemd。

Systemd 提供了按需启动服务的能力,这个功能通常称为“启动时懒加载”(Lazy Loading)。按需启动的含义是,在系统启动时不立即启动所有服务或服务单元,而是在需要时再进行启动。这种方式可以减少系统启动时间和资源占用,并且可以避免不必要的服务启动。

Systemd 的按需启动功能是通过“启动时懒加载”机制来实现的。在这种机制下,Systemd 只会在需要特定服务时才会启动它。例如,当用户首次尝试访问某个服务时,Systemd 会自动启动该服务。这种方式可以使得系统中只有正在使用的服务或服务单元才会被启动,从而减少了系统启动时间和资源占用。

需要注意的是,按需启动服务的功能需要服务单元支持。如果一个服务单元不支持按需启动,那么无论什么时候启动系统,该服务单元都会被立即启动。因此,在配置 Systemd 服务时,需要特别注意按需启动机制的设置。

2.4、采用 linux 的 cgroups 跟踪和管理进程的生命周期

systemd 利用了 Linux 内核的特性即 cgroups 来完成跟踪的任务。cgroups 是 Linux 内核提供的一种机制,用于对进程进行资源隔离和限制。通过 cgroups,可以限制进程的 CPU、内存、磁盘、网络等资源的使用,并且可以对进程进行管理和监控。当停止服务时,通过查询 cgroups ,systemd 可以确保找到所有的相关进程,从而干净地停止服务。
cgroups 已经出现了很久,它主要用来实现系统资源配额管理。cgroups 提供了类似文件系统的接口,使用方便。当进程创建子进程时,子进程会继承父进程的 cgroups 。因此无论服务如何启动新的子进程,所有的这些相关进程都会属于同一个 cgroups ,systemd 只需要简单地遍历指定的 cgroups 即可正确地找到所有的相关进程,将它们一一停止即可。

Systemd 使用 cgroups 来进行进程的管理和跟踪,通过创建 cgroups,将进程分组并进行隔离和限制。在 Systemd 中,每个服务单元都被分配到一个 cgroup 中,该 cgroup 中包含了该服务单元的所有进程,从而实现对所有进程的资源隔离和限制。

通过使用 cgroups,Systemd 可以实现对进程的生命周期进行跟踪和管理。例如,可以在 cgroups 中设置进程的 CPU 使用时间、内存限制、IO 限制等,从而实现对进程的资源限制。此外,Systemd 还可以使用 cgroups 来进行进程的监控和日志记录,从而提供更好的系统管理功能。

2.5、启动挂载点和自动挂载的管理

传统的 linux 系统中,用户可以用 /etc/fstab 文件来维护固定的文件系统挂载点。这些挂载点在系统启动过程中被自动挂载,一旦启动过程结束,这些挂载点就会确保存在。这些挂载点都是对系统运行至关重要的文件系统,比如 HOME 目录。和 sysvinit 一样,Systemd 管理这些挂载点,以便能够在系统启动时自动挂载它们。systemd 还兼容 /etc/fstab 文件,您可以继续使用该文件管理挂载点。

Systemd 使用“挂载单元”(mount units)来管理挂载点,每个挂载单元对应着一个挂载点。挂载单元是 Systemd 中的一个服务单元,它包含了挂载点的配置信息,包括文件系统类型、挂载选项、挂载点所在的设备、挂载点路径等等。

在 Systemd 中,可以使用 systemd-mount 命令来管理挂载单元,包括创建、修改、删除挂载单元等操作。Systemd 还支持启动时挂载和自动挂载,可以通过如下方式实现:

  • 启动时挂载:在挂载单元中设置“Wants”“Requires”依赖项,使得相关的设备或挂载点在系统启动时自动挂载。

  • 自动挂载:在挂载单元中设置“AutoMount”“yes”,这样当相关设备或挂载点被访问时,Systemd 会自动挂载该设备或挂载点。

存在循环依赖,那么 systemd 将无法启动任意一个服务。此时 systemd 将会尝试解决这个问题,因为配置单元之间的依赖关系有两种:required 是强依赖;want 则是弱依赖,systemd 将去掉 wants 关键字指定的依赖看看是否能打破循环。如果无法修复,systemd 会报错。systemd 能够自动检测和修复这类配置错误,从而极大地减轻了管理员的排错负担。

需要注意的是,在使用 Systemd 进行挂载点管理时,需要特别关注挂载点的依赖关系和挂载顺序。例如,如果挂载点 A 依赖于挂载点 B,则需要先挂载 B,然后才能挂载 A。因此,在配置挂载单元时,需要特别注意挂载点的依赖关系和挂载顺序,以保证文件系统正确地挂载和使用。

有时候用户还需要动态挂载点,比如打算访问 DVD 或者 NFS 共享的内容时,才临时执行挂载以便访问其中的内容,而不访问光盘时该挂载点被取消(umount),以便节约资源。传统地,人们依赖 autofs 服务来实现这种功能。
systemd 内建了自动挂载服务,无需另外安装 autofs 服务,可以直接使用 systemd 提供的自动挂载管理能力来实现 autofs 的功能。

2.6、实现事务性依赖关系管理

系统启动过程是由很多的独立工作共同组成的,这些工作之间可能存在依赖关系,比如挂载一个 NFS 文件系统必须依赖网络能够正常工作。systemd 虽然能够最大限度地并发执行很多有依赖关系的工作,但是类似"挂载 NFS"和"启动网络"这样的工作还是存在天生的先后依赖关系,无法并发执行。对于这些任务,systemd 维护一个"事务一致性"的概念,保证所有相关的服务都可以正常启动而不会出现互相依赖,以至于死锁的情况。

在 Systemd 中,每个服务单元都可以指定一组依赖项,这些依赖项可以是其他服务单元、套接字、挂载点等。Systemd 通过事务性依赖关系管理来确保依赖项按正确的顺序启动,并且在依赖项未满足时暂停或者终止服务单元。

事务性依赖关系管理的核心思想是事务(transaction),即将所有依赖项按正确的顺序组合成一个事务,并且在该事务中启动、停止或重新启动服务单元。当一个服务单元的依赖项未满足时,Systemd 会暂停或终止该服务单元,并且等待依赖项满足后再重新启动。

在 Systemd 中,事务性依赖关系管理的实现主要包括以下几个方面:

  • 依赖图分析:Systemd 使用依赖图来描述服务单元之间的依赖关系,并且通过分析依赖图来确定正确的启动顺序。

  • 事务管理器:Systemd 使用事务管理器来管理依赖项的启动、停止或重新启动,并且在依赖项未满足时暂停或终止服务单元。

  • 依赖项状态追踪:Systemd 会追踪每个依赖项的状态,并且在依赖项状态发生变化时重新计算依赖关系。

通过事务性依赖关系管理,Systemd 可以确保服务单元按正确的顺序启动,并且在依赖项未满足时暂停或终止服务单元,从而提高了系统的稳定性和可靠性。

2.7、日志服务

systemd 自带日志服务 journald,journald 负责收集、存储和管理系统日志,它可以记录系统启动时的所有日志信息,包括内核日志、应用程序日志和服务日志等。在 journald 中,每条日志都被称为一个“日志条目”(log entry),它包含了日志文本、时间戳、优先级、来源等信息。该日志服务的设计初衷是克服现有的 syslog 服务的缺点。比如:

syslog 不安全,消息的内容无法验证。每一个本地进程都可以声称自己是 Apache PID 4711,而 syslog 也就相信并保存到磁盘上。
数据没有严格的格式,非常随意。自动化的日志分析器需要分析人类语言字符串来识别消息。一方面此类分析困难低效;此外日志格式的变化会导致分析代码需要更新甚至重写。
systemd journal 用二进制格式保存所有日志信息,用户使用 journalctl 命令来查看日志信息。无需自己编写复杂脆弱的字符串分析处理程序。

systemd journal 的优点如下:

简单性:代码少,依赖少,抽象开销最小。
零维护:日志是除错和监控系统的核心功能,因此它自己不能再产生问题。举例说,自动管理磁盘空间,避免由于日志的不断产生而将磁盘空间耗尽。
移植性:日志文件应该在所有类型的 Linux 系统上可用,无论它使用的何种 CPU 或者字节序。
性能:添加和浏览日志非常快。
最小资源占用:日志数据文件需要较小。
统一化:各种不同的日志存储技术应该统一起来,将所有的可记录事件保存在同一个数据存储中。所以日志内容的全局上下文都会被保存并且可供日后查询。例如一条固件记录后通常会跟随一条内核记录,最终还会有一条用户态记录。重要的是当保存到硬盘上时这三者之间的关系不会丢失。syslog 将不同的信息保存到不同的文件中,分析的时候很难确定哪些条目是相关的。
扩展性:日志的适用范围很广,从嵌入式设备到超级计算机集群都可以满足需求。
安全性:日志文件是可以验证的,让无法检测的修改不再可能。

Systemd 日志服务的主要功能包括:

  • 自动旋转:journald 可以自动旋转日志文件,防止日志文件过大,而且可以限制日志文件的大小和数量。

  • 消息过滤:journald 可以根据优先级、来源、进程 ID 等条件对日志进行过滤,从而更方便地查看关注的日志信息。

  • 日志转发:journald 可以将日志转发到远程服务器或者其他日志收集系统,方便集中管理和监控。

  • 可靠性保障:journald 可以通过加密、完整性校验等方式保证日志的安全性和可靠性。

在使用 Systemd 日志服务时,可以使用 journalctl 工具来查看和管理系统日志。journalctl 工具提供了丰富的查询选项,可以根据时间、关键字、优先级等条件查询日志信息,从而方便问题排查和故障诊断。

总的来说,Systemd 日志服务提供了强大的系统日志管理功能,通过 journald 守护进程来收集、存储和管理系统日志,从而方便开发人员和系统管理员查看和分析系统日志,提高了系统的可靠性和可管理性。

三、Systemd unit

Systemd unit 是 Systemd 中管理和控制系统资源、服务或任务的基本单元,每个 unit 都有独有的名称、类型和配置文件,并且通过依赖关系来控制 unit 的启动和停止顺序,从而实现了对系统资源和服务的高效管理和控制。

3.1、常见unit

Unit 一共分成12种。

  • Service unit(.service):用于封装一个后台服务进程
  • Target unit(.target):此类配置单元为其他配置单元进行逻辑分组。它们本身实际上并不做什么,只是引用其他配置单元而已。这样便可以对配置单元做一个统一的控制。这样就可以实现大家都已经非常熟悉的运行级别概念。比如想让系统进入图形化模式,需要运行许多服务和配置命令,这些操作都由一个个的配置单元表示,将所有这些配置单元组合为一个目标(target),就表示需要将这些配置单元全部执行一遍以便进入目标所代表的系统运行状态。 (例如:multi-user.target 相当于在传统使用 SysV 的系统中运行级别 5)
  • Device Unit(.device):此类配置单元封装一个存在于 Linux 设备树中的设备。每一个使用 udev 规则标记的设备都将会在 systemd 中作为一个设备配置单元出现。对于/dev 目录下的设备
  • Mount Unit(.mount):此类配置单元封装文件系统结构层次中的一个挂载点。Systemd 将对这个挂载点进行监控和管理。比如可以在启动时自动将其挂载;可以在某些条件下自动卸载。Systemd 会将 /etc/fstab 中的条目都转换为挂载点,并在开机时处理。
  • Automount Unit(.automount):此类配置单元封装系统结构层次中的一个自挂载点。每一个自挂载配置单元对应一个挂载配置单元 ,当该自动挂载点被访问时,systemd 执行挂载点中定义的挂载行为。
  • Path Unit(.path):文件系统中的一个文件或目录。用于监控指定目录或文件的变化,并触发其它 Unit 运行
  • Scope Unit():用于 cgroups,表示从 systemd 外部创建的进程。这种 Unit 文件不是用户创建的,而是 Systemd 运行时产生的,描述一些系统服务的分组信息
  • Slice Unit(*.slice):进程组,用于 cgroups,表示一组按层级排列的单位。slice 并不包含进程,但会组建一个层级,并将 scope 和 service 都放置其中。
  • Snapshot Unit(.snapshot):用于表示一个由 systemctl snapshot 命令创建的 Systemd Units 运行状态快照,与 target 配置单元相似,快照是一组配置单元。它保存了系统当前的运行状态。
  • Socket Unit(.socket):此类配置单元封装系统和互联网中的一个套接字 。当下,systemd 支持流式、数据报和 连续包的 AF_INET、AF_INET6、AF_UNIX socket 。每一个套接字配置单元都有一个相应的服务配置单元 。相应的服务在第一个"连接"进入套接字时就会启动(例如:nscd.socket 在有新连接后便启动 nscd.service)
  • Swap Unit(.swap):和挂载配置单元类似,交换配置单元用来管理交换分区。用户可以用交换配置单元来定义系统中的交换分区,可以让这些交换分区在启动时被激活。
  • Timer Unit(.timer):定时器配置单元用来定时触发用户定义的操作,这类配置单元取代了 atd、crontab 等传统的定时服务。
# 列出正在运行的 Unit
$ systemctl list-units
systemctl list-units
  UNIT                                                                  LOAD      ACTIVE SUB       DESCRIPTION
  proc-sys-fs-binfmt_misc.automount                                     loaded    active running   Arbitrary Executable File Formats File System Automount Point
  sys-devices-pci0000:00-0000:00:03.0-virtio0-virtio\x2dports-vport0p1.device loaded    active plugged   /sys/devices/pci0000:00/0000:00:03.0/virtio0/virtio-ports/vpo
  sys-devices-pci0000:00-0000:00:04.0-virtio1-block-vda-vda1.device     loaded    active plugged   /sys/devices/pci0000:00/0000:00:04.0/virtio1/block/vda/vda1
  sys-devices-platform-serial8250-tty-ttyS1.device                      loaded    active plugged   /
......

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

# 列出所有没有运行的 Unit
$ systemctl list-units --all --state=inactive
 UNIT                                                  LOAD      ACTIVE   SUB  DESCRIPTION
  sys-fs-fuse-connections.mount                         loaded    inactive dead FUSE Control File System
  tmp.mount                                             loaded    inactive dead Temporary Directory
  systemd-ask-password-console.path                     loaded    inactive dead Dispatch Password Requests to Console Directory Watch
● display-manager.service                               not-found inactive dead display-manager.service
  ....
# 列出所有加载失败的 Unit
$ systemctl list-units --failed
  UNIT                         LOAD      ACTIVE SUB    DESCRIPTION
● disable_printk_relax.service loaded    failed failed (null)
● httpd.service                loaded    failed failed The Apache HTTP Server
● mariadb.service              loaded    failed failed MariaDB database server
● postfix.service              loaded    failed failed Postfix Mail Transport Agent
● rc-local.service             loaded    failed failed /etc/rc.d/rc.local Compatibility
● walle.service                not-found failed failed walle.service

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

3.2、Systemd 目录

  • /etc/systemd/system/:该目录包含了所有本地系统服务单元文件的配置文件,包括启动时运行的系统服务和用户服务。
ls /etc/systemd/system
aegis.service       cpupower.service  default.target.wants  graphical.target.wants  multi-user.target.wants  sysinit.target.wants
basic.target.wants  default.target    getty.target.wants    local-fs.target.wants   sockets.target.wants     system-update.target.wants
  • /usr/lib/systemd/system/:该目录包含了所有已安装软件的服务单元文件,包括系统服务和第三方软件服务。
ls /usr/lib/systemd/system
arp-ethers.service                      halt.target.wants                  poweroff.target.wants                          systemd-ask-password-console.path
atd.service                             hibernate.target                   printer.target                                 systemd-ask-password-console.service
auditd.service                          htcacheclean.service               proc-sys-fs-binfmt_misc.

...
  • /run/systemd/system/:该目录包含了所有正在运行的服务单元文件,这些服务单元文件是基于 /etc/systemd/system/ 和 /usr/lib/systemd/system/ 目录中的文件生成的。
ls /run/systemd/system
session-215677.scope    session-401915.scope.d  session-402358.scope    session-c4042067.scope.d  session-c6917125.scope    user-0.slice.d
session-215677.scope.d  session-401918.scope    session-402358.scope.d  session-c5481555.scope    session-c6917125.scope.d  user-1367771.slice
session-285125.scope    session-401918.scope.d  session-c16.scope       session-c5481555.scope.d  session-c92156.scope      user-1367771.slice.d
session-285125.scope.d  session-401919.scope    session-c16.scope.d     session-c56.scope         session-c92156.scope.d
session-401915.scope    session-401919.scope.d  session-c4042067.scope  session-c56.scope.d       user-0.slice
  • /etc/systemd/system.conf:该文件包含了 Systemd 的全局配置。

  • /etc/systemd/user/:该目录包含了用户定义的服务单元文件,这些服务单元文件会在用户登录时自动启动。

  • /etc/systemd/logind.conf:该文件包含了 login 管理器的配置,用于管理用户登录时的会话。

  • /etc/systemd/systemd-journald.conf`:该文件包含了 journal 日志的配置,用于管理系统日志。

  • /etc/systemd/timesyncd.conf:该文件包含了 timesyncd 时间同步服务的配置。

  • /usr/lib/systemd/systemd-sleep:该目录包含了睡眠模式相关的服务脚本。

3.3、Unit 和 Target

Unit: Unit 是 Systemd 的基本构建块,用于定义系统服务和其他资源,包括服务的启动顺序、依赖关系、部署状态等。每个 Unit 都有一个唯一的名字和类型,例如 service、socket、mount 等。

在 Unit 文件中,可以定义以下信息:

Unit 的类型、名称和描述
Unit 之间的依赖关系和启动顺序
Unit 的执行程序、启动参数和环境变量
Unit 的状态和执行结果
Unit 的启动、停止、重启和状态查询等操作

Target: Target 是一组相关的 Unit 的集合,用于定义系统运行的目标状态。每个 Target 都有一个唯一的名字和一组依赖的 Unit,当系统启动时,Systemd 会尝试启动指定的 Target,从而满足系统运行的需求。

在 Target 文件中,可以定义以下信息:

Target 的名称和描述
Target 所包含的 Unit 和依赖关系
Target 的启动、停止、重启和状态查询等操作

Target 的类型和 Unit 的类型类似,例如 multi-user、graphical、network 等。其中,multi-user.target 用于启动多用户命令行界面,graphical.target 用于启动图形化界面,network.target 用于启动网络服务等。

总之,Unit 和 Target 是 Systemd 的核心概念,通过定义 Unit 和 Target,可以对系统服务和状态进行管理和控制。

# 查看target类型的unit
$ systemctl list-unit-files --type=target

# 查看指定target下面有哪些unit
$ systemctl list-dependencies multi-user.target

# 查看系统默认的target
$ systemctl get-default
multi-user.target

sudo systemctl set-default multi-user.target
# 切换 Target 时,默认不关闭前一个 Target 启动的进程,systemctl isolate 命令改变这种行为,关闭前一个 Target 里面所有不属于后一个 Target 的进程
sudo systemctl isolate multi-user.target
# 查看配置文件
systemctl cat multi-user.target

# 修改配置文件以后,需要重新加载配置文件,然后重新启动相关服务
# 重新加载配置文件
sudo systemctl daemon-reload
# 重启相关服务
sudo systemctl restart foobar

cat /usr/lib/systemd/system/sshd.service //查看一个服务属于哪个target,只需要看[install]部分就可以看出属于哪个target

$ cat /usr/lib/systemd/system/sshd.service
[Unit]
Description=OpenSSH server daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target sshd-keygen.service
Wants=sshd-keygen.service

[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/sshd
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target

Target 与 SysV-init 进程的主要区别:

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

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

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

3.4、Unit 的状态

在 Systemd 中,Unit 的状态有以下几种:

  • active (running):Unit 正在运行。
  • active (exited):Unit 已经完成运行并退出。
  • inactive (dead):Unit 已经停止运行。
  • activating (start):Unit 正在启动。
  • activating (auto-restart):Unit 正在自动重启。
  • deactivating (stop):Unit 正在停止。
  • deactivating (restart):Unit 正在重启。
  • failed:Unit 启动失败,或者在运行过程中突然停止。

常用命令

# 显示系统状态
$ systemctl status

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

# 显示远程主机的某个 Unit 的状态
$ systemctl -H [email protected] status httpd.service

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

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

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

3.5、常见unit 管理命令

# 立即启动一个服务
$ 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

3.6、unit 依赖关系

在 Systemd 中,Unit 之间可以建立依赖关系,以确保它们按照正确的顺序启动和停止。以下是 Unit 之间依赖关系的几种类型:

  • Requires:表示 Unit A 依赖于 Unit B,如果 Unit B 无法启动,则 Unit A 也无法启动。

  • Wants:表示 Unit A 希望依赖于 Unit B,但是如果 Unit B 无法启动,Unit A 仍然可以启动。

  • RequiresOverridable:与 Requires 类似,但是允许在启动时覆盖依赖的 Unit,例如在容器中运行时。

  • BindsTo:表示 Unit A 依赖于 Unit B,如果 Unit B 停止运行,则 Unit A 也会被停止。

  • PartOf:表示 Unit A 是 Unit B 的一部分,如果 Unit B 停止运行,则 Unit A 也会被停止。

  • Conflicts:表示 Unit A 与 Unit B 冲突,如果 Unit B 正在运行,则 Unit A 无法启动。

在 Unit 文件中,可以使用以下语法定义依赖关系:

[Unit]
Requires=unit1.service
Wants=unit2.service
BindsTo=unit3.socket
PartOf=unit4.target
Conflicts=unit5.service

其中,unit1.service、unit2.service 等都是 Unit 的名称。通过建立正确的依赖关系,可以确保系统服务按照正确的顺序启动和停止,从而避免由于依赖关系不正确而导致的问题。
常用命令:

# 列出一个 Unit 的所有依赖
$ systemctl list-dependencies nginx.Service

# 上述命令默认不会显示target 类型依赖,需要展示,使用如下命令
$ systemctl list-dependencies --all nginx.service

3.7、unit 文件

/usr/lib/systemd/system/docker.service为例,来学习一下unit文件的书写:

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
BindsTo=containerd.service
After=network-online.target firewalld.service containerd.service
Wants=network-online.target
Requires=docker.socket

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always

# Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
# Both the old, and new location are accepted by systemd 229 and up, so using the old location
# to make them work for either version of systemd.
StartLimitBurst=3

# Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.
# Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
# this option work for either version of systemd.
StartLimitInterval=60s

# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity

# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this option.
TasksMax=infinity

# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes

# kill only the docker process, not all processes in the cgroup
KillMode=process

[Install]
WantedBy=multi-user.target
  • Unit 段:此部分所有 Unit 文件通用,用来定义 Unit 的元数据、配置以及与其他 Unit 的关系,Description 描述 Unit 文件信息,Documentation 表示指定服务的文档,Condition 表示服务启动的条件,有些 Unit 还包含 wants、before、after、require 字段,这些表示服务的一个依赖关系。
  • Install 段:此部分所有 Unit 文件通用,通常指定运行目标的 target,使得服务在系统启动时自动运行。Wantedby、RequiredBy 与 Unit 段 Wants 字段类似,表示依赖关系,Alias 字段表示启动运行时使用的别名。
  • service 段:服务(Service)类型的 Unit 文件特有的字段,用于定义服务的具体管理和执行动作。其中包括 Type 字段,定义进程的行为,例如使用 fork()启动,使用 dbus 启动等等;ExecStart、ExecStartPre、ExecStartPos、ExecReload、ExecStop 分别表示启动当前服务执行的命令、启动当前服务之前执行的命令、启动当前服务之后启动的命令、重启当前服务时执行的命令、停止当前服务时执行的命令。

3.7.1、Unit 段参数

  • Description:描述这个 Unit 文件的信息

  • Documentation:指定服务的文档,可以是一个或多个文档的 URL 路径

  • Requires:依赖的其它 Unit 列表,列在其中的 Unit 模板会在这个服务启动时的同时被启动。并且,如果其中任意一个服务启动失败,这个服务也会被终止

  • Wants:与 Requires 相似,但只是在被配置的这个 Unit 启动时,触发启动列出的每个 Unit 模块,而不去考虑这些模板启动是否成功

  • After:与 Requires 相似,但是在后面列出的所有模块全部启动完成以后,才会启动当前的服务

  • Before:与 After 相反,在启动指定的任务一个模块之间,都会首先确证当前服务已经运行

  • Binds To:与 Requires 相似,失败时失败,成功时成功,但是在这些模板中有任意一个出现意外结束或重启时,这个服务也会跟着终止或重启

  • Part Of:一个 Bind To 作用的子集,仅在列出的任务模块失败或重启时,终止或重启当前服务,而不会随列出模板的启动而启动

  • OnFailure:当这个模板启动失败时,就会自动启动列出的每个模块

  • Conflicts:与这个模块有冲突的模块,如果列出的模块中有已经在运行的,这个服务就不能启动,反之亦然

3.7.2、Install 段参数

这部分配置的目标模块通常是特定运行目标的 .target 文件,用来使得服务在系统启动时自动运行。这个区段可以包含三种启动约束:

  • WantedBy:和 Unit 段的 Wants 作用相似,只有后面列出的不是服务所依赖的模块,而是依赖当前服务的模块。它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放入 /etc/systemd/system 目录下面以 <Target 名> + .wants 后缀构成的子目录中,如 /etc/systemd/system/multi-user.target.wants/

  • RequiredBy:和 Unit 段的 Wants 作用相似,只有后面列出的不是服务所依赖的模块,而是依赖当前服务的模块。它的值是一个或多个 Target,当前 Unit 激活时,符号链接会放入 /etc/systemd/system 目录下面以 <Target 名> + .required 后缀构成的子目录中

  • Also:当前 Unit enable/disable 时,同时 enable/disable 的其他 Unit

  • Alias:当前 Unit 可用于启动的别名

3.7.3、Service 段参数

用来 Service 的配置,只有 Service 类型的 Unit 才有这个区块。它的主要字段分为服务生命周期和服务上下文配置两个方面

服务生命周期控制相关
  • Type:定义启动时的进程行为,它有以下几种值:

    • Type=simple:默认值,执行ExecStart指定的命令,启动主进程

    • Type=forking:以 fork 方式从父进程创建子进程,创建后父进程会立即退出

    • Type=oneshot:一次性进程,Systemd 会等当前服务退出,再继续往下执行

    • Type=dbus:当前服务通过D-Bus启动

    • Type=notify:当前服务启动完毕,会通知Systemd,再继续往下执行

    • Type=idle:若有其他任务执行完毕,当前服务才会运行

  • RemainAfterExit:值为 true 或 false(默认)。当配置为 true 时,Systemd 只会负责启动服务进程,之后即便服务进程退出了,Systemd 也仍然会认为这个服务还在运行中。这个配置主要是提供给一些并非常驻内存,而是启动注册后立即退出,然后等待消息按需启动的特殊类型服务使用的。

  • ExecStart:启动当前服务的命令

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

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

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

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

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

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

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

  • TimeoutStartSec:启动服务时等待的秒数,这一配置对于使用 Docker 容器而言显得尤为重要,因其第一次运行时可能需要下载镜像,严重延时会容易被 Systemd 误判为启动失败杀死。通常,对于这种服务,将此值指定为 0,从而关闭超时检测

  • TimeoutStopSec:停止服务时的等待秒数,如果超过这个时间仍然没有停止,Systemd 会使用 SIGKILL 信号强行杀死服务的进程

  • KillMode:定义 Systemd 如何停止 sshd 服务。

    • control-group(默认值):当前控制组里面的所有子进程,都会被杀掉

    • process:只杀主进程

    • mixed:主进程将收到 SIGTERM 信号,子进程收到 SIGKILL 信号

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

服务上下文配置相关
  • Environment:为服务指定环境变量

  • EnvironmentFile:指定加载一个包含服务所需的环境变量的列表的文件,文件中的每一行都是一个环境变量的定义,该文件内部的key=value键值对,可以用$key的形式,在当前配置文件中获取

  • Nice:服务的进程优先级,值越小优先级越高,默认为 0。其中 -20 为最高优先级,19 为最低优先级

  • WorkingDirectory:指定服务的工作目录

  • RootDirectory:指定服务进程的根目录(/ 目录)。如果配置了这个参数,服务将无法访问指定目录以外的任何文件

  • User:指定运行服务的用户

  • Group:指定运行服务的用户组

  • MountFlags:服务的 Mount Namespace 配置,会影响进程上下文中挂载点的信息,即服务是否会继承主机上已有挂载点,以及如果服务运行执行了挂载或卸载设备的操作,是否会真实地在主机上产生效果。可选值为 shared、slaved 或 private

    • shared:服务与主机共用一个 Mount Namespace,继承主机挂载点,且服务挂载或卸载设备会真实地反映到主机上

    • slave:服务使用独立的 Mount Namespace,它会继承主机挂载点,但服务对挂载点的操作只有在自己的 Namespace 内生效,不会反映到主机上

    • private:服务使用独立的 Mount Namespace,它在启动时没有任何任何挂载点,服务对挂载点的操作也不会反映到主机上

  • LimitCPU / LimitSTACK / LimitNOFILE / LimitNPROC 等:限制特定服务的系统资源量,例如 CPU、程序堆栈、文件句柄数量、子进程数量等

  • 日志相关类,这里输出到journal,否则默认syslog

StandardError=journal

StandardOutput=journal

StandardInput=null

注意:如果在 ExecStart、ExecStop 等属性中使用了 Linux 命令,则必须要写出完整的绝对路径。对于 ExecStartPre 和 ExecStartPost 辅助命令,若前面有个 “-” 符号,表示忽略这些命令的出错。因为有些 “辅助” 命令本来就不一定成功,比如尝试清空一个文件,但文件可能不存在。

3.7.4、Unit 文件占位符

在 Unit 文件中,有时会需要使用到一些与运行环境有关的信息,例如节点 ID、运行服务的用户等。这些信息可以使用占位符来表示,然后在实际运行被动态地替换实际的值。

  • %n:完整的 Unit 文件名字,包括 .service 后缀名

  • %p:Unit 模板文件名中 @ 符号之前的部分,不包括 @ 符号

  • %i:Unit 模板文件名中 @ 符号之后的部分,不包括 @ 符号和 .service 后缀名

  • %t:存放系统运行文件的目录,通常是 “run”

  • %u:运行服务的用户,如果 Unit 文件中没有指定,则默认为 root

  • %U:运行服务的用户 ID

  • %h:运行服务的用户 Home 目录,即 %{HOME} 环境变量的值

  • %s:运行服务的用户默认 Shell 类型,即 %{SHELL} 环境变量的值

  • %m:实际运行节点的 Machine ID,对于运行位置每个的服务比较有用

  • %b:Boot ID,这是一个随机数,每个节点各不相同,并且每次节点重启时都会改变

  • %H:实际运行节点的主机名

  • %v:内核版本,即 “uname -r” 命令输出的内容

  • %%:在 Unit 模板文件中表示一个普通的百分号

3.7.5、Unit 模板

在 Systemd 中,Unit 模板是一种特殊的 Unit 文件,用于定义多个类似的 Unit。模板文件本身并不启动任何服务,而是用于生成实际的 Unit 文件。这种机制可以让用户通过模板生成多个相似的 Unit 文件,从而简化配置过程。

Unit 模板的文件名以 @ 符号开头,例如 [email protected]。在模板文件中,可以使用 %i 占位符来代表实际的实例名称。当 Systemd 启动具体的 Unit 实例时,%i 将会被替换为实例名称。

以下是一个简单的 Unit 模板示例:

[Unit]
Description=My Service Template

[Service]
ExecStart=/usr/bin/myservice --name=%i

[Install]
WantedBy=multi-user.target

在这个示例中,模板文件定义了一个名为 [email protected] 的模板,包含了一个 ExecStart 指令,其中 %i 用于表示实例名称。这个模板可以用于生成多个实际的 Unit 文件,例如 [email protected][email protected]

使用 Systemd 的模板机制可以方便地生成多个类似的 Unit 文件,从而简化配置过程,提高效率。

3.8、服务的生命周期

当一个新的 Unit 文件被放入 /etc/systemd/system/ 或 /usr/lib/systemd/system/ 目录中时,它是不会被自识识别的。
在 Systemd 中,一个服务的生命周期包括以下几个阶段:

  • 加载阶段:Systemd 加载服务的 Unit 文件,并根据配置启动或禁止服务。

  • 准备阶段:Systemd 准备服务的启动环境,包括设置环境变量、创建所需目录、检查依赖关系等操作。

  • 启动阶段:Systemd 启动服务,执行服务的启动命令或程序,并记录服务的 PID。

  • 运行阶段:服务正常运行期间,Systemd 监视服务的状态,并记录日志、处理信号等操作。

  • 停止阶段:当服务需要停止时,Systemd 发送 stop 信号给服务进程,并等待服务进程退出。

  • 停止后处理阶段:当服务进程退出后,Systemd 执行服务的停止后处理命令或程序,并记录服务的退出状态。

  • 卸载阶段:当服务不再需要时,Systemd 卸载服务的 Unit 文件,并清理相关的运行时文件和日志。

除了以上阶段,Systemd 还提供了其他的功能,例如自动重启、服务状态查询、依赖关系管理等。通过 Systemd 的管理,可以更方便地管理和监控系统服务的运行状态。

3.8.1、 服务的激活

  • systemctl enable:在 /etc/systemd/system/ 建立服务的符号链接,指向 /usr/lib/systemd/system/ 中

  • systemctl start:依次启动定义在 Unit 文件中的 ExecStartPre、**ExecStart **和 **ExecStartPost **命令

3.8.2、 服务的启动和停止

  • systemctl start:依次启动定义在 Unit 文件中的 ExecStartPre、ExecStart 和 ExecStartPost 命令

  • systemctl stop:依次停止定义在 Unit 文件中的 ExecStopPre、ExecStop 和 ExecStopPost 命令

  • systemctl restart:重启服务

  • systemctl kill:立即杀死服务

3.8.3、 服务的开机启动和取消

  • systemctl enable:除了激活服务以外,也可以置服务为开机启动

  • systemctl disable:取消服务的开机启动

3.8.4、 服务的修改和移除

  • systemctl daemon-reload:Systemd 会将 Unit 文件的内容写到缓存中,因此当 Unit 文件被更新时,需要告诉 Systemd 重新读取所有的 Unit 文件

  • systemctl reset-failed:移除标记为丢失的 Unit 文件。在删除 Unit 文件后,由于缓存的关系,即使通过 daemon-reload 更新了缓存,在 list-units 中依然会显示标记为 not-found 的 Unit。

3.9、日志管理

在 Systemd 中,所有的系统服务都会产生日志记录,包括服务启动、停止、错误信息等。Systemd 采用 Journal 日志系统来管理和存储这些日志。Journal 日志系统提供了以下优点:

  • 支持多种日志格式:Journal 日志系统支持多种日志格式,包括文本格式、二进制格式、JSON 格式等。

  • 支持高效的日志压缩:Journal 日志系统可以自动压缩日志,并支持快速查询压缩后的日志。

  • 支持高效的日志过滤:Journal 日志系统支持高效的日志过滤,可以根据服务名称、事件类型、时间范围等条件来查询日志。

  • 支持高效的日志旋转:Journal 日志系统支持高效的日志旋转,可以自动删除过期的日志,并将日志文件大小限制在一定范围内。

在 Systemd 中,可以使用以下命令来查询和管理日志:

  • journalctl:该命令可以查询系统日志,包括服务启动、停止、错误信息等。可以根据服务名称、事件类型、时间范围等条件来查询日志。

  • journalctl --follow:该命令可以实时跟踪日志的变化,类似于 tail -f 命令。

  • journalctl --vacuum-size=100M:该命令可以限制日志文件大小,当文件大小超过指定值时,会自动删除过期的日志。

  • journalctl --vacuum-time=1week:该命令可以限制日志文件保存时间,当日志文件的保存时间超过指定时间时,会自动删除过期的日志。

总之,通过 Systemd 的 Journal 日志系统,可以方便地管理和查询系统日志,加快排查故障的速度。

其他常见命令:

# 查看所有日志(默认情况下 ,只保存本次启动的日志)
sudo journalctl

# 查看内核日志(不显示应用日志):--dmesg 或 -k
sudo journalctl -k

# 查看系统本次启动的日志(其中包括了内核日志和各类系统服务的控制台输出):--system 或 -b
sudo journalctl -b
sudo journalctl -b -0

# 查看上一次启动的日志(需更改设置)
sudo journalctl -b -1

# 查看指定服务的日志:--unit 或 -u
sudo journalctl -u docker.servcie

# 查看指定服务的日志
sudo journalctl /usr/lib/systemd/systemd

# 实时滚动显示最新日志
sudo journalctl -f

# 查看指定时间的日志
sudo journalctl --since="2021-10-30 18:17:16"
sudo journalctl --since "20 min ago"
sudo journalctl --since yesterday
sudo journalctl --since "2022-01-10" --until "2022-01-11 03:00"
sudo journalctl --since 09:00 --until "1 hour ago"

# 显示尾部的最新 10 行日志:--lines 或 -n
sudo journalctl -n

# 显示尾部指定行数的日志
sudo journalctl -n 20

# 将最新的日志显示在前面
sudo journalctl -r -u docker.service

# 改变输出的格式:--output 或 -o
sudo journalctl -r -u docker.service -o json-pretty

# 查看指定进程的日志
sudo journalctl _PID=1

# 查看某个路径的脚本的日志
sudo journalctl /usr/bin/bash

# 查看指定用户的日志
sudo journalctl _UID=33 --since today

# 查看某个 Unit 的日志
sudo journalctl -u nginx.service
sudo journalctl -u nginx.service --since today

# 实时滚动显示某个 Unit 的最新日志
sudo journalctl -u nginx.service -f

# 合并显示多个 Unit 的日志
journalctl -u nginx.service -u php-fpm.service --since today

# 查看指定优先级(及其以上级别)的日志,共有 8 级
# 0: emerg
# 1: alert
# 2: crit
# 3: err
# 4: warning
# 5: notice
# 6: info
# 7: debug
sudo journalctl -p err -b

# 日志默认分页输出,--no-pager 改为正常的标准输出
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

四、systemd.timer定时任务

在 Systemd 中,除了服务(Unit),还可以使用 timer(定时器)来管理和控制定时任务。与传统的 crontab 相比,使用 Systemd 的 timer 可以提供更高的灵活性和可靠性。

Timer 本质上也是一个 Unit,它可以定义定时任务的执行时间和执行命令。Timer 可以设置为启动一次、每天、每周、每月等不同的时间间隔。

4.1、systemd.timer优点

  • 自动生成日志,配合 Systemd 的日志工具,很方便除错

  • 可以设置内存和 CPU 的使用额度,比如最多使用50%的 CPU

  • 任务可以拆分,依赖其他 Systemd 单元,完成非常复杂的任务

4.2、示例详解

在/usr/lib/systemd/system里创建test.timer(一般建议同名)文件

[Unit]
Description=My test Timer

[Timer]
OnBootSec=2m
OnUnitActiveSec=10s
OnCalendar=*-*-* 00:00:00
Unit=myjob.service

[Install]
WantedBy=timers.target
定时器单元文件中必须包含一个 [Timer]

通过同时使用 OnBootSec=OnUnitActiveSec= 指令, 就可以实现在系统启动后的某个时间点启动匹配单元, 并且之后每隔一段时间周期性的反复启动匹配单元

时间单位后缀:us(微秒), ms(毫秒), s(), m(), h(), d(), w()。 如果省略了时间单位,那么表示使用默认单位"秒"

Unit= 该定时器单元的匹配单元, 也就是要被该定时器启动的单元。默认值是与此定时器单元同名的服务单元

当 Timer 启动时,Systemd 会根据 OnCalendar 参数来计算下一次执行的时间,并在该时间到达时启动对应的服务或命令。Timer 的执行日志将被记录在 Systemd 的 Journal 日志中,可以使用 journalctl 命令来查看。

在启动 Timer 之前,需要使用 systemctl enable 命令将 Timer 加入到自启动列表中。

systemctl enable mytimer.timer

常用命令:

# 启动刚刚新建的这个定时器
sudo systemctl start test.timer

# 查看这个定时器的状态
systemctl status test.timer

# 查看所有正在运行的定时器
systemctl list-timers

# 关闭这个定时器
sudo systemctl stop myscript.timer

# 下次开机,自动运行这个定时器
sudo systemctl enable myscript.timer

# 关闭定时器的开机自启动
sudo systemctl disable myscript.timer

# 查看整个日志
sudo journalctl

# 查看 test.timer 的日志
sudo journalctl -u test.timer

# 查看 test.timer 和 test.service 的日志
sudo journalctl -u test

# 从结尾开始查看最新日志
sudo journalctl -f

# 从结尾开始查看 test.timer 的日志
journalctl -f -u test.timer

4.3、Timer参数详解

4.3.1、Timer 单元文件分成几个部分

[Unit]部分定义元数据。

[Timer]部分定制定时器。Systemd 提供以下一些字段

  • OnActiveSec:定时器生效后,多少时间开始执行任务

  • OnBootSec:系统启动后,多少时间开始执行任务

  • OnStartupSec:Systemd 进程启动后,多少时间开始执行任务

  • OnUnitActiveSec:该单元上次执行后,等多少时间再次执行

  • OnUnitInactiveSec: 定时器上次关闭后多少时间,再次执行

  • OnCalendar:基于绝对时间,而不是相对时间执行

  • AccuracySec:如果因为各种原因,任务必须推迟执行,推迟的最大秒数,默认是60秒

  • Unit:真正要执行的任务,默认是同名的带有.service后缀的单元

  • Persistent:如果设置了该字段,即使定时器到时没有启动,也会自动执行相应的单元

  • WakeSystem:如果系统休眠,是否自动唤醒系统

举例脚本里面,OnUnitActiveSec=1h表示一小时执行一次任务。其他的写法还有OnUnitActiveSec=*-*-* 02:00:00表示每天凌晨两点执行,OnUnitActiveSec=Mon *-*-* 02:00:00表示每周一凌晨两点执行,具体请参考官方文档

4.3.2、[Install] 和 target

  • test.timer文件里面,还有一个[Install]部分,定义开机自启动(systemctl enable)和关闭开机自启动(systemctl disable)这个单元时,所要执行的命令。上面脚本中,[Install]部分只写了一个字段,即WantedBy=multi-user.target。它的意思是,如果执行了systemctl enable test.timer(只要开机,定时器自动生效),那么该定时器归属于multi-user.target。

  • 所谓 Target 指的是一组相关进程,有点像 init 进程模式下面的启动级别。启动某个Target 的时候,属于这个 Target 的所有进程都会全部启动。multi-user.target是一个最常用的 Target,意为多用户模式。也就是说,当系统以多用户模式启动时,就会一起启动test.timer。它背后的操作其实很简单,执行systemctl enable test.timer命令时,就会在multi-user.target.wants目录里面创建一个符号链接,指向test.timer

参考文档:

1、https://blog.51cto.com/weiyigeek/5666902

2、https://blog.csdn.net/lemon_TT/article/details/127090001

3、https://blog.csdn.net/qq_35995514/article/details/125582824

4、https://www.cnblogs.com/aaronLinux/p/6861425.html

猜你喜欢

转载自blog.csdn.net/yuelai_217/article/details/130949299