systemd service之:服务配置文件编写(1)
回到Linux基础系列文章大纲
回到Systemd系列文章大纲
回到Shell系列文章大纲
systemd服务配置文件编写(1)
systemd service:简介
Systemd Service是systemd提供的用于管理服务启动、停止和相关操作的功能,它极大的简化了服务管理的配置过程,用户只需要配置几项指令即可。相比于SysV的服务管理脚本,用户不需要去编写服务的启动、停止、重启、状态查看等等一系列复杂且有重复造轮子嫌疑的脚本代码了,相信写过SysV服务管理脚本的人都深有体会。所以,Systemd Service是面向所有用户的,即使对于新手用户来说,配置门槛也非常低。
systemd service是systemd所管理的其中一项内容。实际上,systemd service是Systemd Unit的一种,除了Service,systemd还有其他几种类型的unit,比如socket、slice、scope、target等等。在这里,暂时了解两项内容:
- Service类型,定义服务程序的启动、停止、重启等操作和进程相关属性
- Target类型,主要目的是对Service(也可以是其它Unit)进行分组、归类,可以包含一个或多个Service Unit(也可以是其它Unit)
此外,Systemd作为管家,还将一些功能集成到了Systemd Service中,个人觉得比较出彩的两个集成功能是:
- 用户可以直接在Service配置文件中定义CGroup相关指令来对该服务程序做资源限制。在以前,对服务程序做CGroup资源控制的步骤是比较繁琐的
- 用户可以选择Journal日志而非采用rsyslog,这意味着用户可以不用单独去配置rsyslog,而且可以直接通过systemctl或journalctl命令来查看某服务的日志信息。当然,该功能并不适用于所有情况,比如用户需要管理日志时
Systemd Service还有其它一些特性,比如可以动态修改服务管理配置文件,比如可以并行启动非依赖的服务,从而加速开机过程,等等。例如,使用systemd-analyze blame
可分析开机启动各服务占用的时长:
1 | $ systemd-analyze blame |
systemd服务配置文件存放路径
如果用户需要,可以将服务配置文件手动存放至用户配置目录/etc/systemd/system下。该目录下的服务配置文件可以是普通.service
文件,也可以是链接至/usr/lib/systemd/system目录下服务配置文件的软链接。
例如:
1 | # 位于/usr/lib/systemd/system下的服务配置文件 |
systemd service文件格式说明
一个Systemd Service的服务配置文件大概长这样:
1 | [Unit] |
一个.Service
配置文件分为三部分:
- Unit:定义该服务作为Unit角色时相关的属性
- Service:定义本服务相关的属性
- Install:定义本服务在设置服务开机自启动时相关的属性。换句话说,只有在创建/移除服务配置文件的软链接时,Install段才会派上用场。这一配置段不是必须的,当未配置
[Install]
时,设置开机自启动或禁止开机自启动的操作将无任何效果
[Unit]
和[Install]
段的配置指令都来自于man systemd.unit
,这些指令都用于描述作为Unit时的属性,[Service]
段则专属于.Service
服务配置文件。
这里先介绍一些常见的[Unit]
和[Install]
相关的指令(虽然支持的配置指令很多,但只需熟悉几个即可),之后再专门介绍Service段落的配置指令。
[Unit]段落指令
Unit指令 | 含义 |
---|---|
Description | Unit的描述信息 |
Documentation | 本Unit的man文档路径 |
After | 本服务在哪些服务启动之后启动,仅定义启动顺序,不定义服务依赖关系,即使要求先启动的服务启动失败,本服务也依然会启动 |
Before | 本服务在哪些服务启动之前启动,仅定义启动顺序,不定义服务依赖关系。通常用于定义在关机前要关闭的服务,如Before=shutdown.target |
Wants | 本服务在哪些服务启动之后启动,定义服务依赖关系,不定义服务启动顺序。启动本服务时,如果被依赖服务未启动,则也会启动被依赖服务。如果被依赖服务启动失败,本服务不会受之影响,因此本服务会继续启动。如果未结合After使用,则本服务和被依赖服务同时启动。 当配置在 [Install] 段落中时,systemctl enable操作将会将本服务安装到对应的.wants 目录下(在该目录下创建一个软链接),在开机自启动时,.wants 目录中的服务会被隐式添加至目标Unit的Wants 指令后。 |
Requires | 本服务在哪些服务启动之后启动,定义服务强依赖关系,不定义服务启动顺序。启动本服务时,如果被依赖服务未启动,则也会启动被依赖服务。如果结合了After,当存在非active状态的被依赖服务时,本服务不会启动。且当被依赖服务被手动停止时,本服务也会被停止,但有例外。如果要保证两服务之间状态必须一致,使用BindsTo指令。 当配置在 [Install] 段落中时,systemctl enable操作将会将本服务安装到对应的.requires 目录下(在该目录下创建一个软链接),在开机自启动时,.requires 目录中的服务会被隐式添加至目标Unit的Requires 指令后。 |
Requisite | 本服务在哪些服务启动之后启动,定义服务依赖关系,不定义服务启动顺序。启动本服务时,如果被依赖服务处于尚未启动状态,则不会主动去启动这些服务,所以本服务直接启动失败。该指令一般结合After一起使用,以便保证启动顺序。 |
BindsTo | 绑定两个服务,两服务的状态保证一致。如服务1为active,则本服务也一定为active。 |
PartOf | 本服务是其它服务的一部分,定义了单向的依赖关系,且只对stop和restart操作有效。当被依赖服务执行stop或restart操作时,本服务也会执行操作,但本服务执行这些操作,不会影响被依赖服务。一般用于组合target使用,比如a.service和b.service都配置PartOf=c.target,那么stop c的时候,也会同时stop a和b。 |
Conflicts | 定义冲突的服务,本服务和被冲突服务的状态必须相反。当本服务要启动时,将会停止目标服务,当启动目标服务时,将会停止本服务。启动和停止的操作同时进行,所以,如果想要让本服务在目标服务启动之前就已经处于停止状态,则必须定义After/Before。 |
OnFailure | 当本服务处于failed时,将启动目标服务。如果本服务配置了Restart重启指令,则在耗尽重启次数之后,本服务才会进入failed。 有时候这是非常有用的,一个典型用法是本服务失败时调用定义了邮件发送功能的service来发送邮件,特别地,可以结合systemd.timer定时任务实现cron的MAILTO功能。 |
RefuseManualStart, RefuseManualStop | 本服务不允许手动启动和手动停止,只能被依赖时的启动和停止,如果手动启动或停止,则会报错。有些特殊的服务非常关键,或者某服务作为一个大服务的一部分,为了保证安全,都可以使用该特性。例如,系统审计服务auditd.service中配置了不允许手动停止指令RefuseManualStop,network.target中配置了不允许手动启动指令RefuseManualStart。 |
AllowIsolated | 允许使用systemctl isolate切换到本服务,只配置在target中。一般来说,用户服务是绝不可能用到这一项的。 |
ConditionPathExists, AssertPathExists | 要求给定的绝对路径文件已经存在,否则不做任何事(condition)或进入failed状态(assert),可在路径前使用! 表示条件取反,即不存在时才启动服务。 |
ConditionPathIsDirectory, AssertPathIsDirectory | 如上,路径存在且是目录时启动。 |
ConditionPathIsReadWrite, AssertPathIsReadWrite | 如上,路径存在且可读可写时启动。 |
ConditionDirectoryNotEmpty, AssertDirectoryNotEmpty | 如上,路径存在且是非空目录时启动。 |
ConditionFileNotEmpty, AssertFileNotEmpty | 如上,路径存在且是非空文件时启动。 |
ConditionFileIsExecutable, AssertFileIsExecutable | 如上,路径存在且是可执行普通文件时启动。 |
对于自定义的服务配置文件来说,需要定义的常见指令包括Description、After、Wants及可能需要的条件判断类指令。所以,Unit段落是非常简单的。
[Install]段落指令
下面是[Install]
段落相关的指令,它们只在systemctl enable/disable
操作时有效。如果期望服务开机自启动,一般只配置一个WantedBy指令,如果不期望服务开机自启动,则Install段落通常省略。
Install指令 | 含义 |
---|---|
WantedBy | 本服务设置开机自启动时,在被依赖目标的.wants 目录下创建本服务的软链接。例如WantedBy = multi-user.target 时,将在/etc/systemd/multi-user.target.wants目录下创建本服务的软链接。 |
RequiredBy | 类似WantedBy,但是是在.requires 目录下创建软链接。 |
Alias | 指定创建软链接时链接至本服务配置文件的别名文件。例如reboot.target中配置了Alias=ctrl-alt-del.target,当执行enable时,将创建/etc/systemd/system/ctrl-alt-del.service软链接并指向reboot.target。 |
DefaultInstance | 当是一个模板服务配置文件时(即文件名为Service_Name@.service ),该指令指定该模板的默认实例。例如trojan@.service中配置了DefaultInstall=server时,systemctl enable trojan@.service时将创建名为trojan@server.service的软链接。 |
例如,下面是sshd的服务配置文件/usr/lib/systemd/system/sshd.service,只看Unit段落和Install段落,是否很简单?
再来一个auditd.service的配置文件示例:
1 | $ cat /usr/lib/systemd/system/auditd.service |
[Service]段配置
Systemd Service配置文件中的[Service]
段落可配置的指令很多,可配置在此段落中的指令来源有多处,包括:
例如,/usr/lib/systemd/system/rsyslog.service文件的内容:
1 | [Service] |
再比如,想要限制一个服务最多允许使用300M内存(比如512M的vps主机运行一个比较耗内存的博客系统时,可设置内存使用限制),最多30%CPU时间:
1 | [Service] |
此外还需要了解systemd的一项功能,systemctl set-property
,它可以在线修改已启动服务的属性。例如
1 | # 直接限制,且写入配置文件,所以下次启动服务也会被限制 |
目前来说,可以不用过多关注来自其它位置的指令,应该给予重点关注的是来自systemd.service自身的指令,比如:
- Type:指定服务的管理类型
- ExecStart:指定启动服务时执行的命令行
- ExecStop:指定停止服务时运行的命令
- ExecReload:指定重载服务进程时运行的命令
- Restart:指定systemd是否要自动重启服务进程以及什么情况下重启
特别是Type指令,它直接影响[Service]
段中的多项配置方式。
下面将从Type指令开始引入Service段的配置方式。
根据man systemd.service
,Type指令支持多种值:
- simple
- exec
- forking
- oneshot
- dbus
- notify
- idle
如果配置的是服务进程,Type的值很可能是forking或simple,如果是普通命令的进程,Type的值可能是simple、oneshot。而dbus类型一般情况下用不上,notify要求服务程序中使用代码对systemd notify进行支持,所以多数情况下可能也用不上。
关于Type,内容较长,见下一篇文章systemd service之:服务配置文件编写(2)。