Linux 系统管理器 Systemd

2018-12-20 0 By admin

systemd是一套Linux系统的基本构建块。它提供了一个系统和服务管理器,它以PID 1运行并启动系统的其余部分。

一、概述

systemd提供积极的并行化功能,使用套接字和D-Bus激活来启动服务,提供按需启动后台程序,使用Linux控制组跟踪进程,维护挂载和自动挂载点,以及实现精心设计的基于事务依赖性的服务控制逻辑。

systemd支持SysV和LSB init脚本,可以替代sysvinit。
其他部分包括日志记录守护程序,用于控制基本系统配置的实用程序,如主机名,日期,区域设置,维护登录用户列表以及运行容器和虚拟机,系统帐户,运行时目录和设置以及用于管理简单网络的守护程序配置,网络时间同步,日志转发和名称解析。

1.1、优点

历史上,Linux 的启动一直采用init进程。这种方法有两个缺点:
一是启动时间长。init进程是串行启动,只有前一个进程启动完,才会启动下一个进程。
二是启动脚本复杂。init进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,这往往使得脚本变得很长。

1.2、运行状态

单元既可以处于活动(active)状态也可以处于停止(inactive)状态, 当然也可以处于启动中(activating)或停止中(deactivating)的状态。 还有一个特殊的失败(failed)状态, 意思是单元以某种方式失败了 (进程崩溃了、或者触碰启动频率限制、或者退出时返回了错误代码、或者遇到了操作超时之类的故障)。 当进入失败(failed)状态时, 导致故障的原因将被记录到日志中以方便日后排查。 需要注意的是,不同的单元可能还会有各自不同的”子状态”, 但它们都被映射到上述五种状态之一。

Systemd 架构图

二、Unit 单元概念

systemd 将各种系统启动和运行相关的对象,表示为各种不同类型的单元(unit),并提供了处理不同单元之间依赖关系的能力。
大部分单元都静态的定义在单元文件中 (参见 systemd.unit(5) 手册),但是有少部分单元则是动态自动生成的:其中一部分来自于其他传统的配置文件(为了兼容性),而另一部分则动态的来自于系统状态或可编程的运行时状态。

2.1、单元类型如下

service 单元
用于封装一个后台服务进程。 参见 systemd.service(5) 手册。
socket 单元
用于封装一个系统套接字(UNIX)或互联网套接字(INET/INET6)或FIFO管道。 相应的服务在第一个”连接”进入套接字时才会被启动。 有关套接字单元的详情,参见 systemd.socket(5) 手册;有关基于套接字或其他方式的启动,参见 daemon(7) 手册。
target 单元
用于将多个单元在逻辑上组合在一起。参见 systemd.target(5) 手册。
device 单元
用于封装一个设备文件,可用于基于设备的启动。 并非每一个设备文件都需要一个 device 单元, 但是每一个被 udev 规则标记的设备都必须作为一个 device 单元出现。参见 systemd.device(5) 手册。
mount 单元
用于封装一个文件系统挂载点(也向后兼容传统的 /etc/fstab 文件)。参见 systemd.mount(5) 手册。
automount 单元
用于封装一个文件系统自动挂载点,也就是仅在挂载点确实被访问的情况下才进行挂载。 它取代了传统的 autofs 服务。参见 systemd.automount(5) 手册。
timer 单元
用于封装一个基于时间触发的动作。它取代了传统的 atd, crond 等任务计划服务。参见 systemd.timer(5) 手册。
swap 单元
用于封装一个交换分区或者交换文件。 它与 mount 单元非常类似。参见 systemd.swap(5) 手册。
path 单元
用于根据文件系统上特定对象的变化来启动其他服务。参见 systemd.path(5) 手册。
slice 单元
用于控制特定 CGroup 内(例如一组 service 与 scope 单元)所有进程的总体资源占用。 参见 systemd.slice(5) 手册。
scope 单元
它与 service 单元类似,但是由 systemd 根据 D-bus 接口接收到的信息自动创建, 可用于管理外部创建的进程。参见 systemd.scope(5) 手册。

单元的名称由单元文件的名称决定, 某些特定的单元名称具有特殊的含义,详情参见 systemd.special(7) 手册。

systemd 能够处理各种类型的依赖关系, 包括依赖与冲突(也就是 Requires= 与 Conflicts= 指令), 以及先后顺序(也就是 After= 与 Before= 指令)。 注意, 上述两种类型的依赖关系(依赖与冲突、先后顺序)之间是相互独立的(无关的)。 举例来说,假定 foo.service 依赖于(Requires) bar.service 但并未指定先后顺序, 那么这两个服务将被同时并行启动。 不过在两个单元之间既存在依赖关系也存在先后顺序的情形也很常见。 另外需要注意的是, 大多数依赖关系都是由 systemd 隐式创建和维护的, 因此没有必要额外手动创建它们。

应用程序和单元(透过依赖关系)可能会查询其他单元的状态变化。 在 systemd 中, 这种查询被包装为”任务”(job)并被作为”任务队列”进行管理。 任务的执行结果可能成功也可能失败, 但是任务的执行顺序是依照任务所属单元之间的先后顺序确定的。

在系统启动时,systemd 默认启动 default.target 单元, 该单元中应该包含所有你想在开机时默认启动的单元。 但实际上,它通常只是一个指向 graphical.target (图形界面) 或 multi-user.target (命令行界面,常用于嵌入式或服务器环境, 一般是 graphical.target 的一个子集)的符号连接。 详见 systemd.special(7) 手册。

systemd 依赖于内核提供的 cgroups 特性控制进程的派生, 从而确保可以追踪到所有子进程。 cgroups 信息由内核负责维护, 并且可以通过 /sys/fs/cgroup/systemd/ 接口进行访问。此外,还可以通过 systemd-cgls(1) 或 ps(1) 之类的工具进行查看 (ps xawf -eo pid,user,cgroup,args)

systemd 几乎完全兼容传统的 SysV init 系统: SysV init 脚本可以作为另一种配置文件格式被识别; 提供与 SysV 兼容的 /dev/initctl 接口; 提供各种 SysV 工具的兼容实现; 依然兼容例如 /etc/fstab 或者 utmp 之类传统的 Unix 特性。

systemd 还有一个小型的事务系统: 如果要启动或关闭一个单元, 那么该单元所依赖的 所有其他单元都会被一起加入到同一个临时事务中。 这样,就可以校验整个事务的一致性, 也就是检查是否存在循环依赖。 如果存在循环依赖, 那么 systemd 将会尝试通过 去掉弱依赖(want)来解决这个问题, 如果最终实在无法解决循环依赖的问题, 那么 systemd 将会报错。

systemd 内置了许多系统启动过程中必需的操作, 例如,设置 hostname 以及配置 loopback 网络设备, 以及挂载 /sys 和 /proc 文件系统。

三、目录

3.1、系统单元目录

systemd 会从多个优先级不同的系统单元目录中读取系统单元, 软件包应该将系统单元文件安装在 pkg-config systemd --variable=systemdsystemunitdir命令所返回的系统单元目录中(通常是/usr/lib/systemd/system)。
此外,systemd 还会读取优先级较高的/usr/local/lib/systemd/system/目录以及优先级较低的 /usr/lib/systemd/system 目录中的系统单元文件。
优先级最高的系统单元目录是pkg-config systemd --variable=systemdsystemconfdir命令所返回的目录(通常是 /etc/systemd/system)。
注意,软件包应该仅使用 systemctl(1) 的 enable 与 disable 命令修改上述目录中的内容。 完整的目录列表参见 systemd.unit(5) 手册。

3.2、用户单元目录

用户单元目录所遵守的规则与系统单元目录类似, 软件包应该将用户单元文件安装在 pkg-config systemd --variable=systemduserunitdir 命令所返回的用户单元目录中(通常是/usr/lib/systemd/user)。
此外,因为用户单元目录还遵守 XDG Base Directory specification 规范, 所以 systemd 还会读取 $XDG_DATA_HOME/systemd/user(仅在已设置 $XDG_DATA_HOME 的情况下) 或 ~/.local/share/systemd/user(仅在未设置 $XDG_DATA_HOME 的情况下) 目录中的用户单元。
全局用户单元目录(针对所有用户)是 pkg-config systemd --variable=systemduserconfdir 命令所返回的目录(通常是/etc/systemd/user)。
注意,软件包应该仅使用 systemctl(1) 的 enable 与 disable 命令修改上述目录中的内容。 无论这种修改是全局的(针对所有用户)、还是私有的(针对单个用户)。 完整的目录列表参见 systemd.unit(5) 手册。

3.3、SysV启动脚本目录(不同发行版之间差别可能很大)

如果 systemd 找不到指定服务所对应的单元文件, 那么就会到SysV启动脚本目录中 去寻找同名脚本(去掉 .service 后缀)。

3.4、SysV运行级目录(不同发行版之间差别可能很大)

systemd 在决定是否启用一个服务的时候, 会参照SysV运行级目录对该服务的设置。 注意, 这个规则不适用于那些已经拥有原生单元文件的服务。