systemd 的配置文件的编写(一[Unit]和[Install]、通用)
上一篇文章简单的说了下怎么写 .service 文件,从这篇开始,详细的介绍下 systemd 的配置文件如何编写。
一、基本情况
systemd 其实除了常用的 .service 文件,还有以下几种配置文件,分别实现不同的功能:.socket
, .device
, .mount
, .automount
, .swap
, .target
, .path
, .timer
, .snapshot,基本上看扩展名就知道什么意思了。所有这此文件,都和 .service 一样,使用 .desktop 文件的语法(即 windows 下 ini 文件的语法),其具体内容可以参考这里。
所有的这些文件都有共同的两个 group ,或者说 section,即 [Unit] 和 [Install](注意,这些文件的内容都是区分大小写的),不同文件可能其它不同的段,比如[Service]/[Mount]等。下面就具体介绍下这些文件。
这些文件在启动时按一定的顺序载入,一般情况下是这样的:
表1. 以系统模式运行时的载入顺序 (--system
).
路径 | 描述 |
---|---|
/run/systemd/generator.early |
Generated units (early) |
/etc/systemd/system |
本地配置 |
/run/systemd/systemd |
Volatile units |
/run/systemd/generator |
Generated units (middle) |
/usr/local/lib/systemd/system |
local 包中的文件 |
/usr/lib/systemd/system |
安装包中的文件 |
/run/systemd/generator.late |
Generated units (late) |
--user
).
路径 | 描述 |
---|---|
/tmp/systemd-generator.early. |
Generated units (early) |
/etc/systemd/user |
Local configuration |
/run/systemd/user |
Volatile units |
/tmp/systemd-generator. |
Generated units (middle) |
/usr/local/lib/systemd/user |
Units for local packages |
/usr/lib/systemd/user |
Units for installed packages |
/tmp/systemd-generator.late. |
Generated units (late) |
按顺序从高到低,先载入的会覆盖后载入的。从而,一般来讲,如果自己定义的 .service ,要放在/etc/systemd/system里,如果是打包,要放在/usr/lib/systemd/system里,在Magic上,这个路径在rpm打包的时候可以用%{_unitdir}来代替。
在用户模式运行时 (–user),可以用变量 $SYSTEMD_UNIT_PATH 指定路径。
也可能使用 systemctl 的 link 指令来指定不在上面这些目录中的配置(很少见)。
这些文件里可能含有不能支持的选项,systemd在这种情况下,会给出警告然后继续运行。如果一个选项以X-开头,systemd会完全忽略它。不过应用程序可以使用这些文件包含的附加信息。
关于文件中的数据类型。布尔类型可以写成多种格式,真值可以写成 1,yes,true,on,假值可以写成0,no,false,off。
时间类型也支持多种格式,一个单独的数字,指多少秒;也可以带有时间后缀,如果多个后缀在一起,会相加。例如:“50”指的是50秒,“2min 200ms”指的是2分钟200毫秒,即120200毫秒。文件中可以支持这样的时间后缀:s, min, h, d, w, ms, us。具体的内容在讨论.time文件的那段还会再说。
空行和以#和;开始的行会被忽略,所以这可以用来写注释。以反斜杠(\)连接在一起的行,处理时会将反斜杠替换成空格,所以可以用这个来把太长的行分成多行。
和一个 foo.service 文件在一起存在的可能有一个 foo.service.wants/ 目录,所有这个目录里的链接的这些文件都隐含的增加在 Wants= 键的后面,这样可以在不修改原文件的情况下,为其增加依赖关系。关于 Wants= 的详细信息可以看下面。建立这些链接的办法是在 systemctl enable 命令时通过读取文件中的 [Install] 段来建立。类似的还有 .requires/ 目录,对应的就是Requires= 。
和一个 foo.service 文件一起存在的还可能有一个 foo.service.d/ 目录,所有在这个目录中带有.conf后缀的文件会在 foo.service 本身解析后进行解析,这对不编辑 foo.service 文件而给它增加一些配置是很有用的。注意确保解析的指令有相应的节头。
如果一行以.include 开头,后面跟上文件名,这样会把指定的文件解析,注意确保解析的指令有相应的节头。和其它语言的包含文件差不多。
注意,虽然 systemd 提供了这样一个灵活的依赖系统,但是建议不是必要的情况,不使用此功能,而是通过基于总线(bus)或套接字(socket)的激活让 systemd 来自己处理这些依赖关系,这样可以实现更简单、灵活的系统。(吐个槽,这个其实没那么容易)
有些文件的名称反映了现有系统的路径,比如 dev-sda.device 是指 /dev/sda 设备,这种情况下,需要使用一些替换,比如 / 被换成 -,所有不可打印字符和-换成\x20,root目录/换成-,而其它的前后的/都被删除。
有时,systemd 可以在运行时从一个模板文件产生一个实例,这样可以让 systemd 从一个单一文件产生多个单元文件,systemd首先会在文件系统中查找文件,如果没有找到,而文件名中包含@字符,那它会去找模板文件,其名称是保留@前面和后缀。例如:如果找getty@tty3.serivce没有找到,那么systemd会找getty@.service,并将它从配置文件中实例化。配置文件中用于实例化的字符串,可以用特殊字符 i% 来指定,详细描述请参看后面。
如果文件是空的,或链接到/dev/null,它将不被加载,这样可以用来禁用服务,让它即使手工也无法启动。
这些文件的格式基本是稳定的(从systemd 26,即 fedora15以后),具体的可以参看这里,就是说在将来的版本中,这些配置仍然完全可用。
二、选项 [Unit] 段
Requisite=
, RequisiteOverridable= :分别类似上面的两个,不过如果是这个指定服务没有启动,被依赖的服务会不启动,立即失败。
Before=
, After= :配置服务间的启动顺序,比如一个 foo.service 包含了一行 Before=bar.service,那么当他们同时启动时,bar.service 会等待 foo.service 启动完成后才启动。注意这个设置和 Requires= 的相互独立的,同时包含 After= 和 Requires= 也是常见的。此选项可以指定一次以上,这时是按顺序全部启动。
PropagatesReloadTo=
, ReloadPropagatedFrom= :这两个是列出一些服务,当其它服务 reload 时同时 reload 这个服务,或者反之。
IgnoreOnIsolate= :一个布尔值.如果是真则当隔离其它服务时本服务不会停止(不明白隔离是什么意思,大概在后面)。默认是假。
IgnoreOnSnapshot= :一个布尔值.如果是真则本服务不包含快照(snapshots)。对 device 和 snapshot 服务默认为真,其它服务默认为假。
StopWhenUnneeded= :一个布尔值。如果是真则当本服务不使用时会停止。 注意,为了尽量减少 systemd 的工作,默认情况下是不会停止不使用的服务的,除非和其它服务冲突,或用户明确要求停止。如果设置了这个选项,那么如果没有其它活动的服务需要此服务,它会自动停止。默认值是假。
RefuseManualStart=
, RefuseManualStop= :布尔值。如果设为真值,则此服务只能间接的激活或停止。这种情况下,用户直接启动或停止此服务会被拒绝,只有做为其它的服务依赖关系,由其它服务进行启动或停止才可以。这主要是为了停止用户误操作。默认值是假。
AllowIsolate= :布尔值。如果是真值,则此服务可以使用 systemctl isolate 命令进行操作。否则会拒绝此操作。最好的办法是不要动这处选项,除非目标服务的行为类似于 SysV 启动系统中的 runlevels。只是一种预防措施,避免系统无法使用的状态。默认值是假。
DefaultDependencies= :布尔值。如果是真(默认值),一些本服务默认的依赖会隐式的建立,具体是哪些依赖,则于服务的类型决定。比如,对于普通的服务(.service类型),它会确保在系统基本服务启动后才启动本服务,会在系统关机前确保本服务已关闭。一般来说,只有早期开机服务和后期的关机服务,才需要把这个设成假。强烈对大多数普通服务,让这个选项启用即可。如果设成假,也不会禁用所有的隐式依赖,只是禁用那些非必要的。
ConditionPathExists=
, ConditionPathExistsGlob=
, ConditionPathIsDirectory=
, ConditionPathIsSymbolicLink=
, ConditionPathIsMountPoint=
, ConditionPathIsReadWrite=
, ConditionDirectoryNotEmpty=
,ConditionFileNotEmpty=
, ConditionFileIsExecutable=
, ConditionKernelCommandLine=
, ConditionVirtualization=
, ConditionSecurity=
, ConditionCapability=
, ConditionHost=
, ConditionACPower=
,ConditionNull= :这是一组类似的东西。检测特定的条件是不是真值,如果不是真值,服务会略过启动,但是它依赖的服务还是会正常运行的。这个条件测试失败不会让服务进入失败状态。条件是在服务开始运行时检查的。
ConditionPathExists=
是指定在服务启动时检查指定文件的存在状态。如果指定的绝对路径名不存在,这个条件的结果就是失败。如果绝对路径的带有!前缀,则条件反转,即只有路径不存在时服务才启动。selinux
, apparmor
, 和 smack。可以使用!进行反转判断。
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. 详细信息看下一段。、
特殊字符串
许多设置支持使用特殊的字符串,可以在运行或加载时替换成特定的内容。下表是支持的字符串。
表 3. 在服务文件中可以使用的字符串
字符串 | 简介 | 详细信息 |
---|---|---|
%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)