systemd是Linux下的一种init软件,由Lennart Poettering带头开发,并在LGPL 2.1及其后续版本许可证下开源发布。其开发目标是提供更优秀的框架以表示系统服务间的依赖关系,并依此实现系统初始化时服务的并行启动,同时达到降低Shell的系统开销的效果,最终代替现在常用的System V与BSD风格init程序。
传统的System V是串行启动,即在启动下一个脚本前,上一个脚本必须执行完,这样在启动时间上会有很大的浪费。在这个时间就是金钱的年代,这种启动方式必将被淘汰。 首先是Ubuntu 最先造反,启用了自己的upstart启动方式,upstart基于事件触发,但还是串行启动,但是对于没有必要的服务就不会启动。
这时 systemd出现了,主要优点就是并行启动,节约启动时间,systemd作者曾口出狂言,最快2秒启动
相比以前的System V启动方式有以下优化:
一:传统的启动是内核启动完后,首先执行的第一个进程是/sbin/init。
如果要以systemd方式启动,则首先让内核执行的第一个进程是/lib/systemd/systemd或者/usr/lib/systemd/systemd.
方法是在grub界面输入init=/lib/systemd/systemd
二:systemd启动后,首先会去三个目录下找相应的配置文件,按优先级从高到底为/etc/systemd/,/usr/lib/systemd/
和/lib/systemd/,优先级高的配置文件会覆盖优先级低的配置文件
三:systemd的配置文件又叫unit文件,主要有以下几种
service
:守护进程的启动、停止、重启和重载是此类 unit 中最为明显的几个类型。socket
:此类 unit 封装系统和互联网中的一个 socket 。当下,systemd 支持流式、数据报和连续包的 AF_INET、AF_INET6、AF_UNIX socket 。也支持传统的 FIFOs 传输模式。每一个 socket unit 都有一个相应的服务 unit 。相应的服务在第一个“连接”进入 socket 或 FIFO 时就会启动(例如:nscd.socket 在有新连接后便启动 nscd.service)。device
:此类 unit 封装一个存在于 Linux 设备树中的设备。每一个使用 udev 规则标记的设备都将会在 systemd 中作为一个设备 unit 出现。udev 的属性设置可以作为配置设备 unit 依赖关系的配置源。mount
:此类 unit 封装系统结构层次中的一个挂载点。automount
:此类 unit 封装系统结构层次中的一个自挂载点。每一个自挂载 unit 对应一个已挂载的挂载 unit (需要在自挂载目录可以存取的情况下尽早挂载)。target
:此类 unit 为其他 unit 进行逻辑分组。它们本身实际上并不做什么,只是引用其他 unit 而已。这样便可以对 unit 做一个统一的控制。(例如:multi-user.target 相当于在传统使用 SysV 的系统中运行级别5);bluetooth.target 只有在蓝牙适配器可用的情况下才调用与蓝牙相关的服务,如:bluetooth 守护进程、obex 守护进程等)snapshot
:与 target unit 相似,快照本身不做什么,唯一的目的就是引用其他 unit 。
四:systemd启动的第一个unit文件为/lib/systemd/system/下的default.target文件(这里的default.target一般为链接文
件,这样default.target指向不同的文件,可达到不同的启动等级)
例:
可以看到,default.target指向graphical.target这个文件,graphical.target表示图形界面这个等级
graphical.target其内容如下:
Description= :一些描述,显示给用户界面看的,可以是任何字符串,一般是关于服务的说明。
Documentation= :指定参考文档的列表。
Requires= :指定graphical.target依赖于multi-user.target这个服务,如果graphical.target被激活,那么 Requires 后面
的multi-user.target服务也会被激活,反之,如果 Requires 后面的multi-user.target服务被停止或无法启动,则graphical.target
服务也会停止。这个选项可以指定多次,那么就要求所有指定的服务都被激活。
After= :表示启动完multi-user.target后,再启动graphical.target。同时还有Before= :表示启动完本服务后,再启动Before后面
的服务。
Conflicts= :配置一个依赖冲突,当rescue.target服务启动时,graphical.target服务停止,反过来,graphical.target服务启动,
那么rescue.targe就会停止。
Wants= :相对弱化的 Requires= ,display-manager.target会被启动,但如果无法启动或无法添加到事务处理,并不影
响graphical.target服务做为一个整体的启动。
AllowIsolate= :布尔值。如果是真值,则此服务可以使用 systemctl isolate 命令进行操作。否则会拒绝此操作。默认值是假。
Alias= :在安装使用应该使用的别名。名字必须和服务本身有同样的后缀(即同样的类型)。这个选项可以指定多次,所有的
名字都起作用,当执行 systemctl enable 命令时,会建立相当的链接
五:常用的命令
Description= :一些描述,显示给用户界面看的,可以是任何字符串,一般是关于服务的说明。
Documentation= :指定参考文档的列表,以空格分开的 URI 形式,如http://, https://, file:, info:, man:,这是有顺序的,最好是先解释这个服务的目的是什么,然后是它是如何配置的,再然后是其它文件,这个选项可以多次指定,会将多行的合并,如果指定了一个空的,那么会重置此项,前的配置不在起作用。
Requires= :指定此服务依赖的其它服务,如果本服务被激活,那么 Requires 后面的服务也会被激活,反之,如果 Requires 后面的服务被停止或无法启动,则本服务也会停止。这个选项可以指定多次,那么就要求所有指定的服务都被激活。需要注意的是这个选项不影响启动或停止的顺序,启动顺序使用单句的 After= 和 Before= 来配置。例如,如果 foo.service 依赖 bar.serivce,但是只配置了 Requires= 而没有 After= 或 Before=,那么 foo.service 启动时会同时激活 foo.service 和 bar.service。通常使用 Wants= 代替 Requires= 是更好的选择,因为系统会更好的处理服务失败的情况。注意,这种依赖关系,也可以在文件之外来处理,即使用 .requires/ 目录,可以参看上面的说明。
RequiresOverridable= :类似上面的 Requires= ,不过这种情况下,只要用户明确要求它启动,才会影响到被依赖的服务,不然服务出错什么的,不会影响被依赖服务的启动。
Requisite=
, RequisiteOverridable= :分别类似上面的两个,不过如果是这个指定服务没有启动,被依赖的服务会不启动,立即失败。
Wants= :相对弱化的 Requires= ,这里列出的服务会被启动,但如果无法启动或无法添加到事务处理,并不影响本服务做为一个整体的启动。这是推荐的两个服务关联的方式。这种依赖也可以配置文件外,通过 .wants/ 目录添加,具体可以看上面的说明。
BindsTo= :和 Requires= 很像,但是这种情况,如果他后面列出的服务停止运行或崩溃之类的,本服务也会同时停止。
PartOf= :又一个类似 Requires= 的选项,但是限制在停止或重启动服务,如果这里列出的服务被停止或重启动,那么本服务也会停止或重启动,注意这个依赖是意向,即本服务停止或重启动,不会影响到这里列出服务的运行状态。
Conflicts= :配置一个依赖冲突,如果配置了些项,那么,当一个服务启动时,或停止此处列出的服务,反过来,如果这里列出的服务启动,那么本服务就会停止,即后启动的才起作用。注意,此设置和 After= 和 Before= 是互相独立的。如果服务 A 和 B 冲突,且在 B 启动的时候同时启动,那么有可能会启动失败(两都都是必需的)或修改以修复它(两者之一或两都都不是必需的),后一种情况,会将不需要的依赖删除,或停止冲突。
Before=
, After= :配置服务间的启动顺序,比如一个 foo.service 包含了一行 Before=bar.service,那么当他们同时启动时,bar.service 会等待 foo.service 启动完成后才启动。注意这个设置和 Requires= 的相互独立的,同时包含 After= 和 Requires= 也是常见的。此选项可以指定一次以上,这时是按顺序全部启动。
OnFailure= :列出一个或更多的服务,当本服务启动状态是 failed 的时候,激活这些服务。
PropagatesReloadTo=
, ReloadPropagatedFrom= :这两个是列出一些服务,当其它服务 reload 时同时 reload 这个服务,或者反之。
RequiresMountsFor= :用空格分开的绝对路径列表,是 Requires= 和 After= 添加的依赖中的 mount 文件需要访问的指定的路径。
OnFailureIsolate= :是一个布尔值,如果是真,那么 OnFailure= 后面的服务会进入隔离模式,即所有不是它依赖的服务都会停止。如果只设置一个服务,可以放在 OnFailure= 后,默认值是假。
IgnoreOnIsolate= :一个布尔值.如果是真则当隔离其它服务时本服务不会停止(不明白隔离是什么意思,大概在后面)。默认是假。
IgnoreOnSnapshot= :一个布尔值.如果是真则本服务不包含快照(snapshots)。对 device 和 snapshot 服务默认为真,其它服务默认为假。
StopWhenUnneeded= :一个布尔值。如果是真则当本服务不使用时会停止。 注意,为了尽量减少 systemd 的工作,默认情况下是不会停止不使用的服务的,除非和其它服务冲突,或用户明确要求停止。如果设置了这个选项,那么如果没有其它活动的服务需要此服务,它会自动停止。默认值是假。
RefuseManualStart=
, RefuseManualStop= :布尔值。如果设为真值,则此服务只能间接的激活或停止。这种情况下,用户直接启动或停止此服务会被拒绝,只有做为其它的服务依赖关系,由其它服务进行启动或停止才可以。这主要是为了停止用户误操作。默认值是假。
AllowIsolate= :布尔值。如果是真值,则此服务可以使用 systemctl isolate 命令进行操作。否则会拒绝此操作。最好的办法是不要动这处选项,除非目标服务的行为类似于 SysV 启动系统中的 runlevels。只是一种预防措施,避免系统无法使用的状态。默认值是假。
DefaultDependencies= :布尔值。如果是真(默认值),一些本服务默认的依赖会隐式的建立,具体是哪些依赖,则于服务的类型决定。比如,对于普通的服务(.service类型),它会确保在系统基本服务启动后才启动本服务,会在系统关机前确保本服务已关闭。一般来说,只有早期开机服务和后期的关机服务,才需要把这个设成假。强烈对大多数普通服务,让这个选项启用即可。如果设成假,也不会禁用所有的隐式依赖,只是禁用那些非必要的。
JobTimeoutSec= :当一个客户端等待本服务的某个 Job 完成时,所指定的超时时间。如果达到了限制的时间,此 Job 会取消运行,但服务不会更改状态,包括进入“failed”状态。除了设备服务(即.device类型),其它的默认值是0(即没有超时设置)。注意,这个是独立于特定服务所设置的超时设置的(比如对 .service 类型所设置的 Timeout=),它对服务本身没有影响,但特定服务的设置是有影响的(能用来更改服务状态)。
ConditionPathExists=
, ConditionPathExistsGlob=
, ConditionPathIsDirectory=
, ConditionPathIsSymbolicLink=
, ConditionPathIsMountPoint=
, ConditionPathIsReadWrite=
, ConditionDirectoryNotEmpty=
,ConditionFileNotEmpty=
, ConditionFileIsExecutable=
, ConditionKernelCommandLine=
, ConditionVirtualization=
, ConditionSecurity=
, ConditionCapability=
, ConditionHost=
, ConditionACPower=
,ConditionNull= :这是一组类似的东西。检测特定的条件是不是真值,如果不是真值,服务会略过启动,但是它依赖的服务还是会正常运行的。这个条件测试失败不会让服务进入失败状态。条件是在服务开始运行时检查的。
ConditionPathExists=
是指定在服务启动时检查指定文件的存在状态。如果指定的绝对路径名不存在,这个条件的结果就是失败。如果绝对路径的带有!前缀,则条件反转,即只有路径不存在时服务才启动。
ConditionPathExistsGlob= 类似上面的选项,但支持通配符。
ConditionPathIsDirectory= 判断指定路径是不是目录。
ConditionPathIsSymbolicLink= 判断指定路径是不是链接。
ConditionPathIsMountPoint= 判断指定路径是不是一个挂载点。
ConditionPathIsReadWrite= 多年指定路径是否可读写(即不是做为只读系统挂载的)
ConditionDirectoryNotEmpty= 判断指定目录是否存在且不为空。
ConditionFileNotEmpty= 判断指定文件是否是常规文件且不为空(即大小不是0)。
ConditionFileIsExecutable= 判断指定文件是否是常规文件且可执行。
类似的,ConditionKernelCommandLine=是判断有没有指定的内核命令行启动参数(或带有!反之),这个参数必须是一个单词或用=分开的两个单词,前一种情况下,会寻找内核参数是否有此单词或是赋值的左边。后一种情况则必须是赋值的左右同时符合。
ConditionVirtualization= 是判断是不是在虚拟化环境下执行的服务。这可以是个布尔值以判断是不是任意的虚拟化环境,或者下列的字符串之一: qemu, kvm, vmware, microsoft, oracle, xen, bochs, chroot, openvz, lxc, lxc-libvirt, systemd-nspawn,以判断是不是特定的虚拟化环境,多重嵌套的虚拟化环境,只判断最后一层。可以使用!进行反转判断。
ConditionSecurity= 是判断系统是否启用了安全环境,当前仅能识别selinux
, apparmor
, 和 smack。可以使用!进行反转判断。
ConditionCapability= 是判断服务管理器绑定的 capability 是否存在。(可以查看其它部分的详细信息。)设置为 capability 的名字,比如 CAP_MKNOD。可以通过在前面加!反转判断。
ConditionHost= 是判断主机名 (hostname)或机器ID(machine ID)是否匹配。可以加!反转。
ConditionACPower= 是判断机器是否在使用交流电源。如果设成 true,而只有至少连接一个交流电源时结果才为真,反过来,设成 false,则不连接所有交流电源时才为真。
最后,ConditionNull= 是一个常量性质的判断条件,它应该是布尔值,如果设成 false ,则条件永远失败,反过来则永远成立。
如果指定多个条件,则所有条件都需要成立(即条件之间是 AND 的关系)。条件前面可以加上 | 符号,这时条件变成一个触发条件,服务定义了触发条件,那么在满足其它非触发条件和这个触发条件的情况下,服务会至少执行一次。同时指定|和!前缀时,先处理|,后处理!。除了ConditionPathIsSymbolicLink=,其它条件均跟随链接。如果这些条件指定为空,则相当于重置,前面的任何设置都不再起作用。
SourcePath= :这个服务生成的配置文件所在的路径,这主要是用在生成工具从外部配置文件的格式转换到本地服务的配置格式中。因此,对一般的服务不要使用此选项。
服务文件还可能包含一个 [Install] 段,这个段的内容服务的安装信息。它不在 systemd 的运行期间使用。只在使用 systemctl enable 和 systemctl disable 命令启用/禁用服务时有用。
Alias= :在安装使用应该使用的额外名字(即别名)。名字必须和服务本身有同样的后缀(即同样的类型)。这个选项可以指定多次,所有的名字都起作用,当执行 systemctl enable 命令时,会建立相当的链接。
WantedBy=
, RequiredBy= :在
.wants/
或 .requires/
子目录中为服务建立相应的链接。这样做的效果是当列表中的服务启动,本服务也会启动。 在 bar.service 中的 WantedBy=foo.service 和 Alias=foo.service.wants/bar.service 基本是一个意思。
Also= :当此服务安装时同时需要安装的附加服务。
如果用户请求安装的服务中配置了此项,则 systemctl enable 命令执行时会自动安装本项所指定的服务。
在 [Install] 段使用这些字符串有特定含义: %n, %N, %p, %i, %U, %u, %m, %H, %b. 详细信息看下一段。、
特殊字符串
许多设置支持使用特殊的字符串,可以在运行或加载时替换成特定的内容。下表是支持的字符串。
字符串 | 简介 | 详细信息 |
---|---|---|
%n |
完整的服务名称 | |
%N |
不转义的完整服务名称 | |
%p |
前缀名 | 对于实例化的服务,这是前@前面的部分,对于其它的服务,是指去掉后缀(即类型)的部分。 |
%P |
不转义的前缀名 | |
%i |
实例名称 | 对于实例化的服务,这是指 @和后缀之间的部分。 |
%I |
不转义的实例名。 | |
%f |
不转义的文件名。 | 这可以不转义的实例名(如果可用)或前缀名,带有/前缀。 |
%c |
服务的控制组路径。? | |
%r |
systemd 的根控制组路径。? | |
%R |
systemd 的根控制组路径的父目录。 | |
%t |
运行时 Socket 目录。 | 这可以是 /run (系统管理器) 或 $XDG_RUNTIME_DIR (用户管理器). |
%u |
用户名 | 这是服务配置的用户或systemd运行实例的用户(如果没有配置的话)。 |
%U |
用户 UID | 这是服务配置的用户UID或systemd运行实例的用户UID(如果没有配置的话) |
%h |
用户家目录 | 这是服务配置的用户家目录或systemd运行实例的用户家目录(如果没有配置的话) |
%s |
用户Shell | 这是服务配置的用户shell或systemd运行实例的用户shell(如果没有配置的话) |
%m |
机器 ID | 运行系统的机器 ID ,格式是一个字符串。 |
%b |
启动 ID | 运行系统的启动 ID ,格式是一个字符串。. |
%H |
主机名 | 运行系统的主机名。 |
%% |
转义 % | 一个单百分号. |
systemd 的手册页:http://www.freedesktop.org/software/systemd/man
fedora 的 systemd 说明页面:http://fedoraproject.org/wiki/Packaging:Systemd,中文:https://fedoraproject.org/wiki/Systemd/zh-cn
unbuntu 的 systemd 说明页面:https://wiki.edubuntu.org/systemd
arch 的 systemd 说明页面:https://wiki.archlinux.org/index.php/Systemd/,中文:https://wiki.archlinux.org/index.php/Systemd_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)