linux systemd - 初始化进程

linux systemd是System V init的替代者,成为RHEL 7、CentOS 7默认的初始化进程。

Linux启动时会先加载操作系统内核,接着,启动初始化进程。

CentOS 7中初始化进程就是systemd,进程id为1。

Red Hat是systemd的主要推动者 ,Red Hat Enterprise Linux、CentOS、Scientific Linux都支持systemd。

分析启动过程

systemd-analyze

查看每个进程启动花费的时间

systemd-analyze blame

设计理念

systemd使用cgroups代替PID跟踪进程,即使fork出的进程也不会脱离systemd的管理。

注:systemd使用cgroups组织和管理进程,cgroups使用分组概念,这些组是分层的,每个组从父级继承属性。一个cgroup以它所属的服务命名,要杀死一个服务,杀死它的cgroup就够了。

服务依赖

systemd是一个服务管理器,能解决服务间的依赖关系,实现服务并行启动。

linux上的服务,启动过程通常要做初始化工作,如:挂载文件系统,过程的每一步都被systemd抽象为一个配置单元,即:unit。

如:服务A启动时服务B必须已启动,systemd使用unit管理和解决服务依赖问题。

systemd unit

systemd将启动和运行相关的对象包装成unit,每个unit对应一个unit配置文件。

Unit文件

[Unit]
Description=Network Time Service

[Service]
ExecStart=/usr/bin/ntpd -n -u ntp:ntp -g

[Install]
WantedBy=multi-user.target

Unit目录

每个unit都有对应的配置文件,systemd根据配置文件启动unit。

systemd默认从/etc/systemd/system/目录中读取配置文件。

定义unit的文件可以放在多个地方,每个地方都有不同的优先级和含义。

系统的unit文件副本通常存放在/lib/systemd/system目录中,安装软件时对应的unit文件默认存放在此目录。

存储在此目录的unit文件可在会话期间按需启动和停止,通常不应编辑这个目录下的文件,如有需要,在另一个位置上创建unit文件覆盖该文件。

这个位置就是/etc/systemd/system/目录,此目录中下unit文件优先级最高。

如果,只想覆盖系统unit文件中的特定指令,可在子目录中创建unit文件中追加指令更改选项。如,为sshd.service添加自定义配置项,创建一个sshd.service.d目录并在custom.conf中插入指令。

另外,也可创建sshd.service.wants和sshd.service.requires目录,这些目录中包含指向unit文件的符号链接,这些unit文件是sshd服务的依赖项。

注:在此目录中,以.conf结尾的文件可用于覆盖或扩展系统unit文件的属性。

还有一个运行时unit文件目录:/run/systemd/system。

此目录下的unit文件优级介于/etc/systemd/system和/lib/systemd/system之间。

权重比前者的轻,比后者重。该目录用于会话期间更改系统的unit行为,服务器reboot后在此目录中所做的更改都将丢失。

Unit配置说明

[Unit]部分

对当前unit进行说明,包含其行为及依赖关系。

Description:提供对unit的描述。使用systemctl命令时,会在systemd状态概述中显示。

[Unit]
Description=The Apache HTTP Server

After:在某些应用启动之后启动当前应用,多个应用以空格分隔。

After=network.target remote-fs.target nss-lookup.target httpd-init.service

Requires:一个unit通常会依赖其他unit,使用Requires表示强依赖。

Requires=avahi-daemon.socket

Wants:声明一种弱依赖关系。

Wants=docker-storage-setup.service

[Service]部分

指定服务启动时要执行的命令,或服务类型。

ExecStart选项声明服务启动时要执行的命令。参数可以是脚本的路径。ExecStartPre和ExecStartPost选项,用于声明服务启动前和启动后执行的命令。

[Service]
ExecStart=/usr/sbin/NetworkManager --no-daemon

ExecStop和ExecReload选项用于指定重新加载或停止服务时要执行的命令。ExecStopPost选项用于指定在一个或多个进程停止后要启动的命令。

服务类型

Systemd将不同行为定义成服务类型,使用type选项指定服务类型:

simple

如果没有定义type和Busname选项,只为ExecStart选项提供了一个指令,那么服务的类型默认为simple。

forking

ExecStart提供的命令将被fork为子进程,启动过程结束,父进程就会死亡,子进程最后会成主进程。

oneshot

如果没有定义Type和ExecStart选项,则使用oneshot作为默认值。它的工作原理很像simple:不同的是,该过程预计在其他units启动前完成。

dbus

使用这种类型的服务,守护进程将从Dbus中获取一个由BusName选项指定的名称。其它部分的工作方式类似于simple。仅在获得DBus名称后才启动后续单元。

notify

与simple相似,区别在于守护进程希望通过sd_notify函数发送通知。只有在发送通知后,才会启动后续的单元。

设置超时

RestartSec选项可以设置systemd重新启动服务前应等待的时间,默认值为100ms。TimeoutStartSec和TimeoutStopSec选项,分别定义服务的启动和停机超时时间,启动超时将被视为启动失败。停机超时会触发一个SIGTERM信号,在等待相同的超时时间后会发送SIGKILL信号。infinity则禁用超时。RuntimeMaxSec选项能够设置服务的可运行时间。服务超出设定时间,将被终止并视为失败。

[Install]部分

服务安装相关的选项。这里的RequiredBy和WantedBy与[Unit]部分的Requires和Wants选项类似,用于建立依赖关系。前者为强依赖,后者为弱依赖。

注:可选项WantedBy、、RequiredBy、ConflictedBy。

示例:

[Unit]
Description=Force ens5f5 ethernet interface to 100Mbps
Requires=Network.target
After=Network.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/ethtool -s ens5f5 wol d
ExecStop=/usr/sbin/ethtool -s ens5f5 wol g

[Install]
WantedBy=multi-user.target

示例说明

在服务启动时,使用ethtool命令禁用以太网接口(ens5f5)上的“wake-on-lan”特性,并在服务停止时重新启用“wake-on-lan”特性。

更多鲜活的例子查看Redis自启动配置Spring Boot应用开机自启动

注:以上配置项为关键选项而非全集。

依赖关系

unit B依赖unit A ,systemd会先启动A再启动B。

systemd事务

为保证unit之间的依赖不会产生环形引用,systemd会尝试解决这类问题。

systemd中的依赖分为强弱两种:required依赖和want依赖。存在循环依赖的时,systemd会解除want依赖,尝试打破循环,如果失败则报错。

systemd target

在systemd中target用于对unit进行分组和排序。一个分组代表了所能够启动的服务项,同时暗含着系统的运行级别。

如:大多数守护进程都分在multi-user.target这个组下面,而multi-user.target同时依赖basic.target,这意味着basic.target分组下的服务,将比multi-user.target下的服务先启动,multi-user.target拥有的服务可能比basic.target多。

查看系统所支持的运行级别。

systemctl list-units --type target

查看当前的运行级别

systemctl get-default
cat /etc/systemd/system/default.target

查看target依赖的服务

systemctl show -p "Wants" multi-user.target

更改默认target

systemctl set-default name.target

systemctl set-default multi-user.target
rm '/etc/systemd/system/default.target'
ln -s '/usr/lib/systemd/system/multi-user.target' '/etc/systemd/system/default.target'

修改当前会话的target

systemctl isolate name.target

systemctl isolate multi-user.target

Unit分类

systemd根据服务/资源将unit分为12种类型。

Service unit:系统服务

Target unit:Unit组(group of units)

Device Unit:硬件设备

Mount Unit:文件系统的挂载点

Automount Unit:自动挂载点

Path Unit:文件/路径

Scope Unit:非Systemd启动的进程

Slice Unit:进程组

Snapshot Unit:Systemd快照

Socket Unit:socket

Swap Unit:swap

Timer Unit:定时器

一般将对应类型后缀附加到资源名称的末尾,如:sshd.socket,nginx.service。

.service:描述如何管理服务器上的服务或应用。

.socket:描述基于socket激活的网络、IPC套接字或FIFO缓冲区。这些文件总是有一个关联的.service文件,当socket上有活动时,将启动该文件。

device:需要systemd管理的设备,并不是所有的设备都有.device文件。

.mount:在系统上定义了一个挂载点,由systemd管理,以挂载路径命名。

.automount:配置一个自动安装的挂载点。须以它们引用的挂载点命名,且必须有一个匹配的.mount unit配置定义挂载细节。

.swap:描述系统上的交换空间。unit的名称须反映空间的设备或文件路径。

.target:在启动或更改状态时为其他unit提供同步点。可以将系统带到一个新的状态。

.path:定义一个路径,可基于路径激活。当路径达到指定的状态时,将启动相同名称的.service unit。使用inotify监视路径的变更。

.timer:定义一个由systemd管理的计时器,类似于cron作业。当定时任务到达时,启动一个匹配的unit。

snapshot:由systemctl snapshot命令自动创建。快照不能跨会话保存。

.slice:与Linux Control Group节点关联,名称反映了它在cgroup树中的层级结构。

scope:由systemd从总线接口接收的信息创建。用于管理外部创建的系统进程。

查看Unit

systemctl list-unit-files --type=service

正在运行的service unit

systemctl list-units

正在运行的unit

systemctl list-units --all --state=inactive

未运行的unit

systemctl list-units --failed

加载失败的unit

注:运行systemctl时.service扩展名可省略,systemd会默认unit为service类型。

Unit状态

systemctl status [name.service]

systemctl start [name.service]
systemctl stop [name.service]
systemctl restart [name.service]
systemctl reload [name.service]
systemctl is-active [name.service]

Unit依赖

查看unit依赖项

systemctl list-dependencies

查看指定服务的依赖:

systemctl list-dependencies nginx

配置文件状态

启用(enabled)、禁用(disabled)、静态(static)。

启用意味着在.wants目录中有一个符号链接。禁用则没有。

静态意味着服务在init脚本中缺少[Install]部分,因此,不能启用或禁用它。静态服务通常是其他服务的依赖项。

Unit文件命名格式

unit_name.type_extension

查看Unit属性

systemctl show sshd.service

显示服务的单个属性,

systemctl show sshd.service -p Conflicts

Conflicts=shutdown.target

屏蔽服务

手动方式启动

sudo systemctl mask nginx.service
systemctl list-unit-files

systemd说明

systemd使用一组命令管理系统资源:

systemctl:控制systemd系统和服务。

loginctl:管理systemd的日志系统。

systemd-cgls:显示cgroup内容。

timedatectl:设置日期和时区。

hostnamectl:设置hostname。

localectl:设置地区和键盘布局。

systemadm:systemctl命令的前端。