linux--systemd、systemctl
- 1 介绍
- 1.1 发展
- sysvinit
- upstart
- 主角 systemd 登场
- 1.2 简介
- 2 优点
- 兼容性
- 启动速度
- systemd 提供按需启动能力
- 采用 linux 的 cgroups 跟踪和管理进程的生命周期
- 启动挂载点和自动挂载的管理
- 实现事务性依赖关系管理
- 日志服务
- systemd journal 的优点如下:
- 3 核心组件和库
- 4 辅助组件
- journald 日志
- libudev 设备管理器
- localed
- logind 管理用户登录和用户数
- homed
- networkd 网络
- resolved
- systemd-boot 系统启动
- timedated 时间设置
- timesyncd 时间同步
- tmpfiles 临时文件清理
- udevd
- 5 systemd 的配置
- .service
- .socket
- .device (automatically initiated by systemd)
- .mount
- .automount
- .swap
- .target
- .path
- .timer (which can be used as a cron-like job scheduler)
- .snapshot
- .slice (used to group and manage processes and resources)
- .scope (used to group worker processes, not intended to be configured via unit files)
- systemd 中的 target 和 sysvinit 中常见的 runlevel 的对应关系
- 参考
1 介绍
1.1 发展
- Linux 操作系统的启动首先从 BIOS 开始,接下来进入 boot loader,由 bootloader 载入内核,进行内核初始化。内核初始化的最后一步就是启动 PID 为 1 的 init 进程。这个进程是系统的第一个进程。它负责产生其他所有的用户进程。init 进程以守护进程(也就是服务)的方式存在,是所有其他进程的祖先。init 进程非常独特,能够完成其他进程无法完成的任务。
- init 系统能够定义、管理和控制 init 进程的行为。它负责组织和运行许多独立的或相关的初始化工作(因此被称为 init 系统),从而让计算机系统进入某种用户预定义的运行模式,比如命令行模式或图形界面模式 。
- 对于一个操作系统而言,仅仅将内核运行起来是毫无实际用途的,必须由 init 系统将操作系统初始化为可操作的状态。比如启动 shell 后,便有了人机交互,这样就可以让计算机执行一些程序完成有实际意义的任务。或者启动 X 图形系统以便提供更佳的人机界面,更加高效的完成任务。这里,字符界面的 shell 或者 X 系统都是一种预设的运行模式。
- 随着计算机系统软硬件的发展,init 系统也在不断的发展变化之中。大体上的演进路线为 sysvinit -> upstart -> systemd。
sysvinit
sysvinit 就是 System V 风格的 init 系统,顾名思义,它源于 System V 系列的 UNIX。最初的 linux 发行版几乎都是采用 sysvinit 作为 init 系统。sysvinit 用术语 runlevel 来定义 “预订的运行模式”。比如 runlevel 3 是命令行模式,runlevel 5 是图形界面模式,runlevel 0 是关机,runlevel 6 是重启。sysvinit 会按照下面的顺序按部就班的初始化系统:
- 激活 udev 和 selinux
- 设置定义在 /etc/sysctl.conf 中的内核参数
- 设置系统时钟
- 加载 keymaps
- 启用交换分区
- 设置主机名(hostname)
- 根分区检查和 remount
- 激活 RAID 和 LVM 设备
- 开启磁盘配额
- 检查并挂载所有文件系统
- 清除过期的 locks 和 PID 文件
- 最后找到指定 runlevel 下的脚本并执行,其实就是启动服务。
除了负责初始化系统,sysvinit 还要负责关闭系统,主要是在系统关闭是为了保证数据的一致性,需要小心地按照顺序进行任务的结束和清理工作。另外,sysvinit 还提供了很多管理和控制系统的命令,比如 halt、init、mesg、shutdown、reboot 等等。
sysvinit 的优点是概念简单。特别是服务(service)的配置,只需要把启动/停止服务的脚本链接接到合适的目录就可以了。
sysvinit 的另一个重要优点是确定的执行顺序,脚本严格按照顺序执行(sysvinit 靠脚本来初始化系统),一个执行完毕再执行下一个,这非常有益于错误排查。
同时,完全顺序执行任务也是 sysvinit 最致命的缺陷。如果 linux 系统只用于服务器系统,那么漫长的启动过程可能并不是什么问题,毕竟我们是不会经常重启服务器的。但是现在 linux 被越来越多的用在了桌面系统中,漫长的启动过程对桌面用户来说是不能接受的。除了启动慢,sysvinit 还有一些其它的缺陷,比如不能很好的处理即插即用的设备,对网络共享磁盘的挂载也存在一定的问题,于是 init 系统开始了它的进化之旅。
upstart
由于 sysvinit 系统的种种弊端,Ubuntu 的开发人员决定重新设计和开发一个全新的 init 系统,即 upstart 。upstart 是第一个被广泛应用的新一代 init 系统。
upstart 基于事件机制,比如 U 盘插入 USB 接口后,udev 得到内核通知,发现该设备,这就是一个新的事件。upstart 在感知到该事件之后触发相应的等待任务,比如处理 /etc/fstab 中存在的挂载点。采用这种事件驱动的模式,upstart 完美地解决了即插即用设备带来的新问题。采用事件驱动机制也带来了一些其它有益的变化,比如加快了系统启动时间。sysvinit 运行时是同步阻塞的。一个脚本运行的时候,后续脚本必须等待。这意味着所有的初始化步骤都是串行执行的,而实际上很多服务彼此并不相关,完全可以并行启动,从而减小系统的启动时间。
upstart 的特点
upstart 解决了之前提到的 sysvinit 的缺点。采用事件驱动模型的 upstart 可以:
- 更快地启动系统
- 当新硬件被发现时动态启动服务
- 硬件被拔除时动态停止服务
这些特点使得 upstart 可以很好地应用在桌面或者便携式系统中,处理这些系统中的动态硬件插拔特性。
主角 systemd 登场
自 2015 年以来,大多数 Linux 发行版都采用了 systemd,取代了SysV init等其他初始化系统。
systemd 是 linux 系统中最新的初始化系统(init),它主要的设计目标是克服 sysvinit 固有的缺点,提高系统的启动速度。systemd 和 ubuntu 的 upstart 是竞争对手,但是时至今日 ubuntu 也采用了 systemd,所以 systemd 在竞争中胜出,大有一统天下的趋势。其实,systemd 的很多概念都来源于苹果 Mac OS 操作系统上的 launchd。
systemd 的优点:
- 功能强大
- 使用方便,
systemd 的缺点:
- 体系庞大
- 非常复杂
下图展示了 systemd 的架构:
1.2 简介
- systemd即为system daemon,是linux下的一种init软件,由Lennart Poettering带头开发,并在LGPL 2.1及其后续版本许可证下开源发布,开发目标是提供更优秀的框架以表示系统服务间的依赖关系,并依此实现系统初始化时服务的并行启动,同时达到降低Shell的系统开销的效果,最终代替常用的System V与BSD风格init程序。
- 与多数发行版使用的System V风格init相比,systemd采用了以下新技术:
(1) 采用Socket激活式与总线激活式服务,以提高相互依赖的各服务的并行运行性能;
(2) 用Cgroups代替PID来追踪进程,因此即使是两次fork之后生成的守护进程也不会脱离systemd的控制。 - 监视和控制systemd的主要命令是systemctl。该命令可用于查看系统状态和管理系统及服务。
2 优点
兼容性
systemd 提供了和 sysvinit 兼容的特性。系统中已经存在的服务和进程无需修改。这降低了系统向 systemd 迁移的成本,使得 systemd 替换现有初始化系统成为可能。
启动速度
systemd 提供了比 upstart 更激进的并行启动能力,采用了 socket / D-Bus activation 等技术启动服务。一个显而易见的结果就是:更快的启动速度。为了减少系统启动时间,systemd 的目标是:
- 尽可能启动更少的进程
- 尽可能将更多进程并行启动
同样地,upstart 也试图实现这两个目标。下图展示了 upstart 相对于 sysvinit 在并发启动这个方面的改进(此图来自互联网):
upstart 增加了系统启动的并行性,从而提高了系统启动速度。但是在 upstart 中,有依赖关系的服务还是必须先后启动。比如任务 A,B,(C,D)因为存在依赖关系,所以在这个局部,还是串行执行。
systemd 能够更进一步提高并发性,即便对于那些 upstart 认为存在相互依赖而必须串行的服务,比如 Avahi 和 D-Bus 也可以并发启动。从而实现如下图所示的并发启动过程(此图来自互联网):
在 systemd 中,所有的任务都同时并发执行,总的启动时间被进一步降低为 T1。可见 systemd 比 upstart 更进一步提高了并行启动能力,极大地加速了系统启动时间。
systemd 提供按需启动能力
当 sysvinit 系统初始化的时候,它会将所有可能用到的后台服务进程全部启动运行。
systemd 可以提供按需启动的能力,只有在某个服务被真正请求的时候才启动它。当该服务结束,systemd 可以关闭它,等待下次需要时再次启动它。
采用 linux 的 cgroups 跟踪和管理进程的生命周期
systemd 利用了 Linux 内核的特性即 cgroups 来完成跟踪的任务。当停止服务时,通过查询 cgroups ,systemd 可以确保找到所有的相关进程,从而干净地停止服务。
cgroups 已经出现了很久,它主要用来实现系统资源配额管理。cgroups 提供了类似文件系统的接口,使用方便。当进程创建子进程时,子进程会继承父进程的 cgroups 。因此无论服务如何启动新的子进程,所有的这些相关进程都会属于同一个 cgroups ,systemd 只需要简单地遍历指定的 cgroups 即可正确地找到所有的相关进程,将它们一一停止即可。
启动挂载点和自动挂载的管理
传统的 linux 系统中,用户可以用 /etc/fstab 文件来维护固定的文件系统挂载点。这些挂载点在系统启动过程中被自动挂载,一旦启动过程结束,这些挂载点就会确保存在。这些挂载点都是对系统运行至关重要的文件系统,比如 HOME 目录。和 sysvinit 一样,Systemd 管理这些挂载点,以便能够在系统启动时自动挂载它们。systemd 还兼容 /etc/fstab 文件,您可以继续使用该文件管理挂载点。
有时候用户还需要动态挂载点,比如打算访问 DVD 或者 NFS 共享的内容时,才临时执行挂载以便访问其中的内容,而不访问光盘时该挂载点被取消(umount),以便节约资源。传统地,人们依赖 autofs 服务来实现这种功能。
systemd 内建了自动挂载服务,无需另外安装 autofs 服务,可以直接使用 systemd 提供的自动挂载管理能力来实现 autofs 的功能。
实现事务性依赖关系管理
系统启动过程是由很多的独立工作共同组成的,这些工作之间可能存在依赖关系,比如挂载一个 NFS 文件系统必须依赖网络能够正常工作。systemd 虽然能够最大限度地并发执行很多有依赖关系的工作,但是类似"挂载 NFS"和"启动网络"这样的工作还是存在天生的先后依赖关系,无法并发执行。对于这些任务,systemd 维护一个"事务一致性"的概念,保证所有相关的服务都可以正常启动而不会出现互相依赖,以至于死锁的情况。
日志服务
systemd 自带日志服务 journald,该日志服务的设计初衷是克服现有的 syslog 服务的缺点。比如:
- syslog 不安全,消息的内容无法验证。每一个本地进程都可以声称自己是 Apache PID 4711,而 syslog 也就相信并保存到磁盘上。
- 数据没有严格的格式,非常随意。自动化的日志分析器需要分析人类语言字符串来识别消息。一方面此类分析困难低效;此外日志格式的变化会导致分析代码需要更新甚至重写。
systemd journal 用二进制格式保存所有日志信息,用户使用 journalctl 命令来查看日志信息。无需自己编写复杂脆弱的字符串分析处理程序。
systemd journal 的优点如下:
- 简单性:代码少,依赖少,抽象开销最小。
- 零维护:日志是除错和监控系统的核心功能,因此它自己不能再产生问题。举例说,自动管理磁盘空间,避免由于日志的不断产生而将磁盘空间耗尽。
- 移植性:日志文件应该在所有类型的 Linux 系统上可用,无论它使用的何种 CPU 或者字节序。
- 性能:添加和浏览日志非常快。
- 最小资源占用:日志数据文件需要较小。
- 统一化:各种不同的日志存储技术应该统一起来,将所有的可记录事件保存在同一个数据存储中。所以日志内容的全局上下文都会被保存并且可供日后查询。例如一条固件记录后通常会跟随一条内核记录,最终还会有一条用户态记录。重要的是当保存到硬盘上时这三者之间的关系不会丢失。syslog 将不同的信息保存到不同的文件中,分析的时候很难确定哪些条目是相关的。
- 扩展性:日志的适用范围很广,从嵌入式设备到超级计算机集群都可以满足需求。
- 安全性:日志文件是可以验证的,让无法检测的修改不再可能。
3 核心组件和库
按照其集成方法,systemd 还提供各种守护进程和实用程序的替代品,包括启动 shell 脚本、pm-utils、inetd、acpid、syslog、watchdog、cron和atd。
systemd 的核心组件包括:
- systemd是 Linux 操作系统的系统和服务管理器。
- systemctl是一个内省和控制 systemd 系统和服务管理器状态的命令。不要与sysctl混淆。
- systemd-analyze可用于确定系统启动性能统计数据,并从系统和服务管理器中检索其他状态和跟踪信息。
systemd使用 Linux 内核的cgroups子系统跟踪进程,而不是使用进程标识符(PID);因此,守护进程无法“逃脱” systemd,即使是通过双分叉。systemd不仅使用 cgroups,还使用systemd-nspawn和machinectl来增强它们,这两个实用程序有助于创建和管理Linux 容器。从 205 版开始,systemd 还提供了 ControlGroupInterface,它是 Linux 内核 cgroups 的 API。Linux 内核 cgroups 经过调整以支持kernfs,并正在修改以支持统一的层次结构。
4 辅助组件
journald 日志
systemd-journald是一个负责事件日志 记录的守护进程,它的日志文件是仅附加的二进制文件。系统管理员可以选择是否使用systemd-journald、syslog-ng或rsyslog记录系统事件。
libudev 设备管理器
libudev是使用udev 的标准库,它允许第三方应用程序查询udev 资源。如实现u盘的自动挂载和卸载。
localed
logind 管理用户登录和用户数
systemd-logind是一个以各种方式管理用户登录和用户数的守护进程。它是一个集成的登录管理器,提供多用户改进并取代不再维护的ConsoleKit 。对于X11 显示管理器,切换到logind需要最少的移植。它集成在 systemd 版本 30 中。
homed
homed是一个守护程序,它提供独立于当前系统配置的可移植人类用户帐户。homed将文件系统中不同位置的各种数据(例如 UID/GID)移动到一个文件中,. homed以多种方式管理用户的主目录,例如普通目录、btrfs子卷、Linux 统一密钥设置卷、fscrypt 目录或从SMB服务器挂载。~/.identity
networkd 网络
networkd是处理网络接口配置的守护进程;在首次集成的 209 版本中,支持仅限于静态分配的地址和对桥接配置的基本支持。2014 年 7 月,systemd 版本 215 发布,添加了新功能,例如用于IPv4主机的DHCP服务器和VXLAN支持。可用于查看 systemd-networkd 所见的网络链接状态。必须在 /lib/systemd/network/ 下添加新接口的配置,作为一个以 .network 扩展名结尾的新文件。
resolved
为本地应用程序提供网络名称解析。
systemd-boot 系统启动
systemd-boot是一个引导管理器,以前称为gummiboot。Kay Sievers 将其合并到版本为 220 的 systemd 中。
timedated 时间设置
systemd-timedated是一个守护进程,可用于控制与时间相关的设置,例如系统时间、系统时区或在UTC和本地时区系统时钟之间进行选择。它可以通过 D-Bus 访问。它集成在 systemd 版本 30 中。
timesyncd 时间同步
是一个已添加的守护进程,用于跨网络同步系统时钟。
tmpfiles 临时文件清理
systemd-tmpfiles是一个实用程序,负责创建和清理临时文件和目录。它通常在启动时运行一次,然后以指定的时间间隔运行。
udevd
udev是Linux 内核的设备管理器,它处理/dev目录和添加/删除设备时的所有用户空间操作,包括固件加载。2012 年 4 月,udev 的源代码树被合并到 systemd 源代码树中。为了匹配 udev 的版本号,systemd 维护人员将版本号直接从 44 提高到 183。2014 年 5 月 29 日,systemd 不再支持通过 udev 加载固件,因为决定由内核负责加载固件。
5 systemd 的配置
- systemd专门通过纯文本文件进行配置。
- systemd在使用声明性语言的配置文件(称为“单元文件”)中记录每个守护进程的初始化指令,取代传统上使用的每个守护进程启动shell 脚本。该语言的语法受到.ini文件的启发。
- 系统初始化需要做的事情非常多。需要启动后台服务,比如启动 ssh 服务;需要做配置工作,比如挂载文件系统。这个过程中的每一步都被 systemd 抽象为一个配置单元,即 unit。可以认为一个服务是一个配置单元,一个挂载点是一个配置单元,一个交换分区的配置是一个配置单元等等。systemd 将配置单元归纳为以下一些不同的类型。然而,systemd 正在快速发展,新功能不断增加。所以配置单元类型可能在不久的将来继续增加。下面是一些常见的 unit 类型(Unit-file types include):
.service
代表一个后台服务进程,比如 MySQLd。这是最常用的一类。
.socket
此类配置单元封装系统和互联网中的一个套接字 。当下,systemd 支持流式、数据报和连续包的 AF_INET、AF_INET6、AF_UNIX socket 。每一个套接字配置单元都有一个相应的服务配置单元 。相应的服务在第一个"连接"进入套接字时就会启动(例如:nscd.socket 在有新连接后便启动 nscd.service)。
.device (automatically initiated by systemd)
此类配置单元封装一个存在于 Linux 设备树中的设备。每一个使用 udev 规则标记的设备都将会在 systemd 中作为一个设备配置单元出现。
.mount
此类配置单元封装文件系统结构层次中的一个挂载点。Systemd 将对这个挂载点进行监控和管理。比如可以在启动时自动将其挂载;可以在某些条件下自动卸载。Systemd 会将 /etc/fstab 中的条目都转换为挂载点,并在开机时处理。
.automount
此类配置单元封装系统结构层次中的一个自挂载点。每一个自挂载配置单元对应一个挂载配置单元 ,当该自动挂载点被访问时,systemd 执行挂载点中定义的挂载行为。
.swap
和挂载配置单元类似,交换配置单元用来管理交换分区。用户可以用交换配置单元来定义系统中的交换分区,可以让这些交换分区在启动时被激活。
.target
此类配置单元为其他配置单元进行逻辑分组。它们本身实际上并不做什么,只是引用其他配置单元而已。这样便可以对配置单元做一个统一的控制。这样就可以实现大家都已经非常熟悉的运行级别概念。比如想让系统进入图形化模式,需要运行许多服务和配置命令,这些操作都由一个个的配置单元表示,将所有这些配置单元组合为一个目标(target),就表示需要将这些配置单元全部执行一遍以便进入目标所代表的系统运行状态。 (例如:multi-user.target 相当于在传统使用 SysV 的系统中运行级别 5)
.path
文件系统中的一个文件或目录。
.timer (which can be used as a cron-like job scheduler)
定时器配置单元用来定时触发用户定义的操作,这类配置单元取代了 atd、crond 等传统的定时服务。
.snapshot
与 target 配置单元相似,快照是一组配置单元。它保存了系统当前的运行状态。
.slice (used to group and manage processes and resources)
用于 cgroups,表示一组按层级排列的单位。slice 并不包含进程,但会组建一个层级,并将 scope 和 service 都放置其中。
.scope (used to group worker processes, not intended to be configured via unit files)
用于 cgroups,表示从 systemd 外部创建的进程。
systemd 中的 target 和 sysvinit 中常见的 runlevel 的对应关系
sysvinit runlevel | systemd target | 描述 |
---|---|---|
0 | poweroff.target | 关闭系统。 |
1,s,single | rescue.target | 单用户模式。 |
2,4 | multi-user.target | 用户定义/域特定运行级别。默认等同于 3。 |
3 | multi-user.target | 多用户,非图形化。用户可以通过多个控制台或网络登录。 |
5 | graphical.target | 多用户,图形化。通常为所有运行级别 3 的服务外加图形化登录。 |
6 | reboot.target | 重启。 |
emergency | emergency.target | 紧急 Shell。 |
参考
1、wiki-systemd
2、百科–systemd
3、关于 systemd 的初步理解
4、systemd详解
5、systemd 介绍
6、Systemd(一)
7、freedesktop–systemd
8、Linux系统时间的设定以及自带的timesync时间同步
9、archlinux–systemd