接前一篇文章:Linux系统服务之一次性服务(1)
本文内容参考以下文章:
Systemd OneShot 系统启动时运行一次特定的命令或脚本,并在执行完毕后自动退出-CSDN博客
oneshot一次性服务_type=oneshot-CSDN博客
特此致谢!
三、读懂服务配置文件
上一回已讲过,systemd的Service Unit文件(服务单位文件)用于配置和管理系统中的服务。Service Unit文件的扩展名为.service,通常存储在/etc/systemd/system/目录下或/usr/lib/systemd/system/目录下。
下面是Service Unit文件的一些常见组成部分即配置项:
1. [Unit] 部分
此部分定义服务的基本信息、启动顺序与依赖关系。包括以下字段:
- Description
描述此服务的简短说明、简单描述。
- Documentation
给出文档位置。
- After
指定此服务在哪些其它服务之后启动。
- Before
指定此服务在哪些其它服务之前启动。
注:After和Before字段只涉及启动顺序,不涉及依赖关系。
- Requires、Wants、BindsTo
指定此服务所依赖的其它服务。其中:Wants表示当前服务与其所依赖服务之间的弱依赖关系,即如果所依赖服务启动失败或异常退出,并不影响当前服务继续执行;Requies表示当前服务与其所依赖服务之间的强依赖关系,即如果所依赖服务启动失败或异常退出,那么当前服务也必须退出。
注:Requires和Wants字段只涉及依赖关系,不涉及启动顺序。
2. [Service] 部分
此部分定义服务的执行参数和行为,更通俗地说是定义如何启动当前服务。分为命令、类型、重启行为三类。
(1)命令
包括以下字段:
- ExecStart
在启动该服务时需要执行的命令行(命令+参数)。即指定服务的启动命令或可执行文件路径。
- ExecStop
当该服务被要求停止时所执行的命令行。即停止该服务时执行的命令。执行完此处设置的所有命令行之后,该服务将被视为已经停止。此字段是可选的。
- ExecStartPre
在执行ExecStart之前执行的命令行。即启动此服务之前执行的命令。
- ExecStartPos
在执行ExecStart之后执行的命令行。即启动此服务之后执行的命令。
- ExecStopPost
在该服务停止之后所执行的命令行。无论服务是否启动成功, 此选项中设置的命令都会在服务停止后被无条件的执行。此字段是可选的。
- ExecReload
当该服务被要求重新载入配置时所执行的命令行。即重新加载服务配置时执行的命令。此字段是可选的。
- Environment
设置环境变量。
- EnvironmentFile
从指定的文件中加载环境变量。即指定当前服务的环境参数文件。
(2)类型
Type字段用于定义服务的类型,其指定了如何启动和管理服务的主进程。通过在Service Unit文件中设置Type选项,可以根据服务的特性和需求选择合适的服务类型,以确保systemd正确地管理和监控服务的状态和行为。Type选项的值可以是以下之一:
- simple(默认值)
如果设为simple(
当设置了ExecStart=
、 但是没有设置Type=
与BusName=
时,这是默认值), 那么ExecStart=
进程就是该服务的主进程,并且systemd会认为在创建了该服务的主服务进程之后,该服务就已经启动完成。
如果此进程需要为系统中的其它进程提供服务,那么必须在该服务启动之前先建立好通信渠道(例如套接字)。 这样,在创建主服务进程之后、执行主服务进程之前,即可启动后继单元,从而加快了后继单元的启动速度。
simple最常见的服务类型。当使用simple类型时,systemd假定服务的主进程会一直运行,直到服务被显式停止或发生错误。这是大多数服务的默认类型。
- exec
exec
与simple
类似,不同之处在于,只有在该服务的主服务进程执行完成之后,systemd才会认为该服务启动完成。其它后继单元必须一直阻塞到这个时间点之后才能继续启动。换句话说,simple
表示当fork()
返回时,即算是启动完成,而exec
则表示仅在fork()
与execve()
函数都执行成功时,才算是启动完成。这就意味着对于exec
类型的服务来说,如果不能成功调用主服务进程(例如User=
不存在、或者二进制可执行文件不存在),那么systemctl start将会执行失败。
- forking
如果设为forking
,那么表示ExecStart=
进程将会在启动过程中使用fork()
系统调用。也就是当所有通信渠道都已建好、启动亦已成功之后,父进程将会退出,而子进程将作为主服务进程继续运行。 这是传统UNIX守护进程的经典做法。 在这种情况下,systemd 会认为在父进程退出之后,该服务就已经启动完成。
如果使用了此种类型,那么建议同时设置PIDFile=
选项,以帮助systemd准确可靠的定位该服务的主进程。systemd将会在父进程退出之后 立即开始启动后继单元。
forking适用于那些在启动过程中会创建一个子进程的服务。在这种类型的服务中,systemd会等待主进程启动,并通过监视子进程的退出来确定服务的启动状态。通常,服务的主进程会立即启动子进程,然后退出,而子进程则负责实际的服务运行。
- oneshot
oneshot
与simple
类似,不同之处在于,只有在该服务的主服务进程退出之后,systemd才会认为该服务启动完成,才会开始启动后继单元。此种类型的服务通常需要设置RemainAfterExit=
选项。 当Type=
与ExecStart=
都没有设置时,Type=
oneshot
就是默认值。
oneshot适用于只需执行一次操作的服务,例如在系统启动时运行一个脚本或执行一个命令。当服务的主进程退出后,systemd将认为服务已经完成,并将其标记为已停止。
- dbus
dbus
与simple
类似,不同之处在于,该服务只有获得了BusName=
指定的D-Bus名称之后,systemd才会认为该服务启动完成,才会开始启动后继单元。设为此类型相当于隐含的依赖于dbus.socket
单元。当设置了BusName=
时, 此类型就是默认值。
用于通过DBus系统总线启动的服务。这种类型的服务通常用于与其它进程进行通信或提供DBus接口。
- notify
notify
与exec
类似,不同之处在于,该服务将会在启动完成之后通过sd_notify(3)之类的接口发送一个通知消息。systemd将会在启动后继单元之前,首先确保该进程已经成功的发送了这个消息。
如果设为此类型,那么下文的NotifyAccess=
将只能设为非none
值;如果未设置NotifyAccess=
选项、或者已经被明确设为none
,那么将会被自动强制修改为main
。
notify适用于在服务启动完成后向systemd发送通知的服务。服务主进程应在启动完成后向systemd发送一个特定的信号,以通知systemd该服务已准备好接受请求。
注意:目前Type=
notify
尚不能与PrivateNetwork=
yes
一起使用。
- idle
idle
与simple
类似,不同之处在于,服务进程将会被延迟到所有活动任务都完成之后再执行。这样可以避免控制台上的状态信息与shell脚本的输出混杂在一起。
idle适用于以非常低优先级运行的服务。这种类型的服务将在所有其它活动任务完成后才会启动。