systemd 基本概念
systemd 是 PID 为1的一个程序,负责初始化系统。所有的程序不是systemd直接启动就是由systemd的子系统启动。systemd是内核直接启动,所以信号9(KILL)对systemd也无效。
systemd 使用Linux控制组跟踪进程,维护安装和自动挂载点,并实现基于事务性依赖关系的详尽服务控制逻辑。其他部分包括日志记录守护程序,用于控制基本系统配置的实用程序,例如主机名,日期,区域设置,维护已登录用户和正在运行的容器和虚拟机的列表,系统帐户,运行时目录和设置,以及用于管理简单网络的守护程序配置,网络时间同步,日志转发和名称解析。
简介
对比 systemV
从CentOS 7.x 以后,Red Hat 系列的 distribution 放弃沿用多年的System V 开机启动服务的流程. systemd 也是当年我从6.x 到 7.x 过度时感觉到最大的变化了,直到今天,MySQL的启动脚本还是可以通过 service mysqld start
启动的,但是升级到 CentOS 7.x 之后,就变成了 systemd start mysqld
了。当然还有经典的init 0
的关机指令。
相比于 initd,systemd有以下几个大的进步。
- 并行启动:旧的 init 启动脚本是一项一项任务依序启动的模式,因此不相依的服务也是得要一个一个的等待。systemd可以让所有的服务同时启动,因此你会发现到,系统启动的速度变快了!
- 一经要求就回应的on-demand启动方式:systemd全部就是仅有一只systemd服务搭配systemctl指令来处理,无须其他额外的指令来支援。不像systemV还要init, chkconfig, service…等等指令。此外, systemd由于常驻记忆体,因此任何要求(on-demand)都可以立即处理后续的daemon启动的任务。
- 服务相依性的自我检查:由于systemd可以自订服务相依性的检查,因此如果B服务是架构在A服务上面启动的,那当你在没有启动A服务的情况下仅手动启动B服务时, systemd会自动帮你启动A服务。
- 依daemon功能分类:systemd下管理的服务非常多,为了厘清所有服务的功能,因此,首先systemd先定义所有的服务为一个服务单位(unit),并将该unit归类到不同的服务类型(type)去。旧的init仅分为stand alone与super daemon,systemd将服务单位(unit)区分为service, socket, target, path, snapshot, timer等多种不同的类型(type),方便管理员的分类与记忆。
- 将多个daemons集合成为一个群组:如同systemV的init里头有个runlevel的特色,systemd亦将许多的功能集合成为一个所谓的target项目,这个项目主要在设计操作环境的建置,所以是集合了许多的daemons,亦即是执行某个target就是执行好多个daemon的意思!
- 向下相容旧有的init服务脚本:基本上, systemd是可以相容于init的启动脚本的,因此,旧的init启动脚本也能够透过systemd来管理,这也是为什么到现在还可以使用
serivce mysqld start
这样命令的原因。
综上可知,systemd 已经足够强大,可以管理一个进程的生命周期,如果是自己写的一套代码完全可以交给systemd 来维护呀,以前公司使用 god(进程监控守护工具) 来管理服务,god 提供了服务启动、服务宕机自动拉起、环境变量和chroot、服务资源限制、定时任务等,但是systemd 的出现已经足够替代 god 这样的第三方服务,systemd 已经足够实现服务托管。
systemd 的配置文件
基本上, systemd 将过去所谓的daemon 执行脚本通通称为一个服务单位(unit),而每种服务单位依据功能来区分时,就分类为不同的类型(type)。在 Systemd 的生态圈中,Unit 文件统一了过去各种不同系统资源配置格式,例如服务的启/停、定时任务、设备自动挂载、网络配置、虚拟内存配置等。而 Systemd 通过不同的文件后缀来区分这些配置文件。
- automount:用于控制自动挂载文件系统,相当于 SysV-init 的 autofs 服务
- device:对于 /dev 目录下的设备,主要用于定义设备之间的依赖关系
- mount:定义系统结构层次中的一个挂载点,可以替代过去的 /etc/fstab 配置文件
- path:用于监控指定目录或文件的变化,并触发其它 Unit 运行
- scope:这种 Unit 文件不是用户创建的,而是 Systemd 运行时产生的,描述一些系统服务的分组信息
- service:封装守护进程的启动、停止、重启和重载操作,是最常见的一种 Unit 文件
- slice:用于表示一个 CGroup 的树,通常用户不会自己创建这样的 Unit 文件
- snapshot:用于表示一个由 systemctl snapshot 命令创建的 Systemd Units 运行状态快照
- socket:监控来自于系统或网络的数据消息,用于实现基于数据自动触发服务启动
- swap:定义一个用户做虚拟内存的交换分区
- target:用于对 Unit 文件进行逻辑分组,引导其它 Unit 的执行。它替代了 SysV-init 运行级别的作用,并提供更灵活的基于特定设备事件的启动方式。其实是一群unit 的集合,例如上面表格中谈到的multi-user.target 其实就是一堆服务的集合~也就是说, 选择执行multi-user.target 就是执行一堆其他.service 或/及.socket 之类的服务就是了!
- timer:用于配置在特定时间触发的任务,替代了 Crontab 的功能
文件目录 Unit 文件按照 Systemd 约定,应该被放置指定的三个系统目录之一中。这三个目录是有优先级的,如下所示,越靠上的优先级越高。因此,在三个目录中有同名文件的时候,只有优先级最高的目录里的那个文件会被使用。
- /etc/systemd/system/:管理员依据主机系统的需求所建立的执行脚本,其实这个目录有点像以前/etc/rc.d/rc5.d/Sxx之类的功能。
- /run/systemd/system/:系统执行过程中所产生的服务脚本,这些脚本的优先序要比/usr/lib/systemd/system/高!
- /usr/lib/systemd/system/:每个服务最主要的启动脚本设定,有点类似以前的/etc/init.d底下的档案;
Systemd 默认从目录 /etc/systemd/system/ 读取配置文件。但是,里面存放的大部分文件都是符号链接,指向目录 /usr/lib/systemd/system/,真正的配置文件存放在那个目录。
Systemd Service Unit
Unit 文件结构
一般可以使用 systemctl cat networking 查看 Unit 文件。
|
|
[Unit]
区块通常是配置文件的第一个区块,用来定义 Unit 的元数据,以及配置与其他 Unit 的关系。它的主要字段如下。
Description
:简短描述Documentation
:文档地址Requires
:当前 Unit 依赖的其他 Unit,如果它们没有运行,当前 Unit 会启动失败Wants
:与当前 Unit 配合的其他 Unit,如果它们没有运行,当前 Unit 不会启动失败BindsTo
:与Requires类似,它指定的 Unit 如果退出,会导致当前 Unit 停止运行Before
:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之后启动After
:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之前启动Conflicts
:这里指定的 Unit 不能与当前 Unit 同时运行Condition
:当前 Unit 运行必须满足的条件,否则不会运行Assert
:当前 Unit 运行必须满足的条件,否则会报启动失败
[Service]
区块用来 Service 的配置,只有 Service 类型的 Unit 才有这个区块。它的主要字段如下。
Type
:定义启动时的进程行为。它有以下几种值。Type=simple
:默认值,执行ExecStart指定的命令,启动主进程Type=forking
:以 fork 方式从父进程创建子进程,创建后父进程会立即退出Type=oneshot
:一次性进程,Systemd 会等当前服务退出,再继续往下执行Type=dbus
:当前服务通过D-Bus启动Type=notify
:当前服务启动完毕,会通知Systemd,再继续往下执行Type=idle
:若有其他任务执行完毕,当前服务才会运行ExecStart
:启动当前服务的命令ExecStartPre
:启动当前服务之前执行的命令ExecStartPost
:启动当前服务之后执行的命令ExecReload
:重启当前服务时执行的命令ExecStop
:停止当前服务时执行的命令ExecStopPost
:停止当其服务之后执行的命令RestartSec
:自动重启当前服务间隔的秒数Restart
:定义何种情况 Systemd 会自动重启当前服务,可能的值包括always(总是重启)、on-success、on-failure、on-abnormal、on-abort、on-watchdogTimeoutSec
:定义 Systemd 停止当前服务之前等待的秒数Environment
:指定环境变量EnvironmentFile
:指定加载一个包含服务所需的环境变量的列表的文件,文件中的每一行都是一个环境变量的定义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、程序堆栈、文件句柄数量、子进程数量等
[Install]
通常是配置文件的最后一个区块,用来定义如何启动,以及是否开机启动。它的主要字段如下。
WantedBy
:它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放入/etc/systemd/system目录下面以 Target 名 + .wants后缀构成的子目录中RequiredBy
:它的值是一个或多个 Target,当前 Unit 激活时,符号链接会放入/etc/systemd/system目录下面以 Target 名 + .required后缀构成的子目录中Alias
:当前 Unit 可用于启动的别名Also
:当前 Unit 激活(enable)时,会被同时激活的其他 Unit
Unit 配置文件的完整字段清单,请参考 官方文档。
Unit 管理
systemctl list-units 命令可以查看当前系统的所有 Unit 。
|
|
Systemd Target
启动计算机的时候,需要启动大量的 Unit。如果每一次启动,都要一一写明本次启动需要哪些 Unit,显然非常不方便。Systemd 的解决方案就是 Target。
简单说,Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候,Systemd 就会启动里面所有的 Unit。
传统的init启动模式里面,有 RunLevel 的概念,跟 Target 的作用很类似。不同的是,RunLevel 是互斥的,不可能多个 RunLevel 同时启动,但是多个 Target 可以同时启动。
|
|
Target 与 传统 RunLevel 的对应关系如下。
|
|
它与init进程的主要差别如下。
(1)默认的 RunLevel(在/etc/inittab
文件设置)现在被默认的 Target 取代,位置是/etc/systemd/system/default.target
,通常符号链接到graphical.target(图形界面)或者multi-user.target(多用户命令行)。
(2)启动脚本的位置,以前是/etc/init.d
目录,符号链接到不同的 RunLevel 目录 (比如/etc/rc3.d
、/etc/rc5.d
等),现在则存放在/lib/systemd/system
和/etc/systemd/system
目录。
(3)配置文件的位置,以前init进程的配置文件是/etc/inittab
,各种服务的配置文件存放在/etc/sysconfig
目录。现在的配置文件主要存放在/lib/systemd
目录,在/etc/systemd
目录里面的修改可以覆盖原始设置。
Systemd 管理
Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。
systemctl
systemctl 是 Systemd 的主命令,用于管理系统。
|
|
systemd-analyze
systemd-analyze 命令用于查看启动耗时。
|
|
hostnamectl
hostnamectl 命令用于查看当前主机的信息。
|
|
localectl
localectl 命令用于查看本地化设置。
|
|
timedatectl
timedatectl 命令用于查看当前时区设置。
|
|
loginctl
loginctl 命令用于查看当前登录的用户。
|
|
日志管理
Systemd 统一管理所有 Unit 的启动日志。带来的好处就是,可以只用journalctl
一个命令,查看所有日志(内核日志和应用日志)。日志的配置文件是/etc/systemd/journald.conf
。
|
|
参考: