systemd 是 Linux 系统工具,用来启动守护进程,已成为大多数发行版的标准配置。
systemd 的优点是功能强大,使用方便,缺点是体系庞大,非常复杂;systemd执行服务是并行的,如果没有人为的干预附加启动依赖,同级服务启动顺序是乱序的,这个在后续会体现出来。
systemd囊括的功能板块很多,内容更倾向运维工作,目前因项目需求,就服务板块进行分析。
systemd不是简单的一个命令,而是非常复杂一组命令,涵盖系统管理的方方面面。
systemctl
是systemd的主要命令,用于整体管理系统各项服务等。
在systemctl眼里,最小的功能单位就是单元,也是单个进程的描述,一个个小的单元互相调用和依赖,组成一个庞大的任务管理系统,这就是 Systemd 的基本思想。
通过systemctl list-unit-files
可以查看当前系统中所有的单元,如下:
每个单元都有一个描述单元的文件,用于规范单元的功能和执行的机制,分别存放在三个不同的目录:
像上述的查看系统中所有的单元文件的命令如下:
/lib/systemd/system
/etc/systemd/system
/usr/lib/systemd/system
明白了单元存在的含义,那么需要管理呀,怎么管理单元的动作,具体如下:
systemctl start [UnitName]
systemctl stop [UnitName]
systemctl restart [UnitName]
systemctl kill [UnitName]
systemctl status [UnitName]
systemctl enable [UnitName]
systemctl disable [UnitName]
顾名思义,通过systemctl控制对单元的开启、停止、重启等操作,这里着重说明的是:
简单分析完systemctl的部分功能之后,systemd还提供了一个可以查看所有启动的总耗时的工具,systemd-analyze
;
systemd-analyze
systemd-analyze blame
systemd-analyze plot > filename.svg
systemd-analyze critical-chain
systemd-analyze critical-chain atd.service
前面介绍这么多都是纸上谈兵而已,需要真正使用上systemd的各种功能,首先要学会怎么读服务文件;
我们找一个.service
文件去读,可以通过systemctl cat
命令查看服务的配置文件,也可以直接到前面说的三个目录下去直接打开,这里打开rc-local.service
来讲解:
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
# This unit gets pulled automatically into multi-user.target by
# systemd-rc-local-generator if /etc/rc.local is executable.
[Unit]
Description=/etc/rc.local Compatibility
ConditionFileIsExecutable=/etc/rc.local
After=network.target
[Service]
Type=forking
ExecStart=/etc/rc.local start
TimeoutSec=0
RemainAfterExit=yes
一个服务怎么启动、什么时候启动、启动什么东西都是由他的配置文件决定的,如上所示,rc-local.service
服务主要是执行/etc/rc.local
的内容,这个关联到linux启动项的内容,这里不展开说明,后续会补充。
rc-local.service
服务的结构分为两个板块,有[Unit]
和[Service]
,其实还有另外一个[Install]
,后续会分别进行说明:
Unit
区块的Description
字段给出当前服务的简单描述,Documentation
字段给出文档位置;After
字段:表示如果network.target
或sshd-keygen.service
需要启动,那么sshd.service
应该在它们之后启动;Before
字段,定义sshd.service
应该在哪些服务之前启动;Wants
字段:表示sshd.service
与sshd-keygen.service
之间存在"弱依赖"关系,即如果"sshd-keygen.service"启动失败或停止运行,不影响sshd.service
继续执行;Requires
字段则表示"强依赖"关系,即如果该服务启动失败或异常退出,那么sshd.service
也必须退出;ConditionFileIsExecutable=/etc/rc.local
指定执行文件;EnvironmentFile
字段:指定当前服务的环境参数文件。该文件内部的key=value
键值对,可以用$key
的形式,在当前配置文件中获取;ExecStart
字段:定义启动进程时执行的命令;ExecReload
字段:重启服务时执行的命令;ExecStop
字段:停止服务时执行的命令;ExecStartPre
字段:启动服务之前执行的命令;ExecStartPost
字段:启动服务之后执行的命令;ExecStopPost
字段:停止服务之后执行的命令;Type
字段定义启动类型。它可以设置的值如下;
ExecStart
字段启动的进程为主进程;ExecStart
字段将以fork()
方式启动,此时父进程将会退出,子进程将成为主进程;simple
,但只执行一次,Systemd 会等它执行完,才启动其他服务;simple
,但会等待 D-Bus 信号后启动;simple
,启动结束后会发出通知信号,然后 Systemd 再启动其他服务;simple
,但是要等到其他任务都执行完,才会启动该服务。一种使用场合是为让该服务的输出,不与其他服务的输出相混合;KillMode
字段:定义Systemd如何停止sshd服务;
Restart
字段:定义了sshd退出后,Systemd的重启方式;
RestartSec
字段:表示 Systemd 重启服务之前,需要等待的秒数。上面的例子设为等待42秒;WantedBy
字段:表示该服务所在的 Target;Target
的含义是服务组,表示一组服务。WantedBy=multi-user.target
指的是,sshd 所在的 Target 是multi-user.target
;这个设置非常重要,因为执行systemctl enable sshd.service
命令时,sshd.service
的一个符号链接,就会放在/etc/systemd/system
目录下面的multi-user.target.wants
子目录之中。
分析完之后,回到[rc-local.service源码]( 3.1 读懂服务文件),我们可以清楚的解析出来,该服务指定的执行文件为/etc/rc.local
,规定该服务在network.target
服务执行完成之后再执行,并且该服务类型为forking
,该服务启动时执行的命令为/etc/rc.local start
在查看/etc/systemd/system
和/lib/systemd/system
下面的服务文件时,仔细的话可以看到分别有.service
和.target
以及.wants
三种不同后缀的文件及文件夹。
像[3.1.3 [Install]]( 3.1.3 [Install]:定义如何安装这个配置文件,即怎样做到开机启动)中描述的WantedBy
字段:表示该服务所在的 target;该target指的就是.target
,每个.target
指的都是一个独立的服务组,表示一组服务。
我们打开ssh.service
可以看到WantedBy=multi-user.target
,指定了ssh.service
所在的服务组为multi-user.target
多用户服务组。
[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
[Install]
WantedBy=multi-user.target
Alias=sshd.service
当我们执行systemctl enable sshd.service
命令时,sshd.service
的一个符号链接,就会放在/etc/systemd/system
目录下面的multi-user.target.wants
子目录之中;这里讲解了(1.2 单元的管理)中的疑点。
我们可以通过执行systemctl list-dependencies multi-user.target
来查看当前multi-user.target
服务组下的服务,
systemd的target
Systemd 目标 | 注释 |
---|---|
runlevel0.target, poweroff.target | 中断系统(halt) |
runlevel1.target, rescue.target | 单用户模式 |
runlevel2.target, runlevel4.target, multi-user.target | 用户自定义启动级别,通常识别为级别3。 |
runlevel3.target, multi-user.target | 多用户,无图形界面。用户可以通过终端或网络登录。 |
runlevel5.target, graphical.target | 多用户,图形界面。继承级别3的服务,并启动图形界面服务。 |
runlevel6.target, reboot.target | 重启 |
emergency.target | 急救模式(Emergency shell) |
Systemd默认的启动Target为multi-user.target,我们也可以通过指令去查看当前启动的target
$systemctl get-default
multi-user.target
一般来说,常用的 Target 有两个:一个是multi-user.target
,表示多用户命令行状态;另一个是graphical.target
,表示图形用户状态,它依赖于multi-user.target
;
打开multi-user.target
文件,如下:
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes
可以看到target 配置文件里面没有启动命令,主要字段如下:
Requires
字段:要求basic.target
一起运行。Conflicts
字段:冲突字段。如果rescue.service
或rescue.target
正在运行,multi-user.target
就不能运行,反之亦然。After
:表示multi-user.target
在basic.target
、 rescue.service
、 rescue.target
之后启动,如果它们有启动的话。AllowIsolate
:允许使用systemctl isolate
命令切换到multi-user.target
。修改配置文件以后,需要重新加载配置文件,然后重新启动相关服务。
# 重新加载配置文件
$ sudo systemctl daemon-reload
# 重启相关服务
$ sudo systemctl restart foobar
参考 > 阮一峰Systemd 入门教程