编写Systemd service 配置文件
# man systemd.service
中文参考手册 systemd.unit https://kinvolk.io/docs/flatcar-container-linux/latest/setup/systemd/environment-variables/
Systemd 单元文件中的以 “#” 开头的行后面的内容会被认为是注释
Systemd 下的布尔值,1、yes、on、true 都是开启,0、no、off、false 都是关闭。
Systemd 下的时间单位默认是秒,所以要用毫秒(ms)分钟(m)等请显式说明。
配置文件存放位置
/usr/lib/systemd/system/
/etc/systemd/system
Systemd 单元类型有:
类型 | 描述 |
---|---|
Target | A group of units that defines a synchronization point. The synchronization point is used at boot time to start the system in a particular state. |
Service | A unit of this type starts, stops, restarts or reloads a service daemon such as Apache webserver. |
Socket | A unit of this type activates a service when the service receives incoming traffic on a listening socket. |
Device | A unit of this type implements device-based activation such as a device driver. |
Mount | A unit of this type controls the file-system mount point. |
Automount | A unit of this type provides and controls on-demand mounting of file systems. |
Swap | A unit of this type encapsulates/activates/deactivates swap partition. |
Path | A unit of this type monitors files/directories and activates/deactivates a service if the specified file or directory is accessed. |
Timer | A unit of this type activates/deactivates specified service based on a timer or when the set time is elapsed. |
Snapshot | A unit that creates and saves the current state of all running units. This state can be used to restore the system later. |
Slice | A group of units that manages system resources such as CPU, and memory. |
Scope | A unit that organizes and manages foreign processes. |
busname | A unit that controls DBus system. |
可以使用systemctl -t help
命令列出所有支持的单元。
依赖关系
- Requires 这个单元启动了,那么
Requires
单元也会被启动;Requires
单元被停止了,这个单元也会停止,是强依赖关系。Requires
并不能控制启动顺序,通常是本单元和Requires
单元并行启动的。这个选项不能作为启动顺序保证。 - RequiresOverridable与
Requires
类似。只不过是如果这个服务是用户手动启动的,那么RequiresOverridable
即使启动不成功也不报错。如果不是手动启动的,和Requires
一样。 - Requisite 强势版本的 Requires,
Requisite
必须已经处于全部成功,否则本单元会马上进入启动失败的状态。且系统不会尝试去启动未成功启动的Requisite
单元。 - Wants:本单元启动后,
want
单元也会被启动。但是本单元与wants
是弱依赖关系。 - Conflicts 当此单元启动的时候,
Conflicts
的所有单元都将被停止。 - OnFailure 当该单元进入失败状态时,将会启动
OnFailure
中的单元
启动顺序
Before/After 用于强制指定单元之间的先后顺序。且停止顺序与启动顺序正好相反。这两个选项仅用于指定先后顺序,而与 Requires
, Wants
, BindsTo
这些选项没有任何关系。
启动类型
-
simple 如果设为
simple
(当设置了ExecStart=
、但是没有设置Type=
与BusName=
时,这是默认值),那么ExecStart=
进程就是该服务的主进程,并且systemd
会认为在创建了该服务的主服务进程之后,该服务就已经启动完成。如果此进程需要为系统中的其他进程提供服务,那么必须在该服务启动之前先建立好通信渠道(例如套接字),这样,在创建主服务进程之后、执行主服务进程之前,即可启动后继单元,从而加快了后继单元的启动速度。这就意味着对于simple
类型的服务来说, 即使不能成功调用主服务进程(例如User=
不存在、或者二进制可执行文件不存在),systemctl start
也仍然会执行成功。 -
forking 标准
Unix Daemon
使用的启动方式。启动程序后会调用fork()
函数,把必要的通信频道都设置好之后父进程退出,留下守护精灵的子进程。你要是使用的这种方式,最好也指定下PIDFILE=
,以帮助systemd
准确可靠的定位该服务的主进程。systemd 将会在父进程退出之后立即开始启动后继单元。 - oneshot
oneshot
与simple
类似,不同之处在于,只有在该服务的主服务进程退出之后,systemd 才会认为该服务启动完成,才会开始启动后继单元。此种类型的服务通常需要设置RemainAfterExit=
选项。当Type=
与ExecStart=
都没有设置时,Type=``oneshot
就是默认值。 - dbus 这个程序启动时需要获取一块 DBus 空间,所以需要和 BusName= 一起用。只有它成功获得了 DBus 空间,依赖它的程序才会被启动。
- notify
notify
与exec
类似,不同之处在于,该服务将会在启动完成之后通过sd_notify(3)之类的接口发送一个通知消息。systemd 将会在启动后继单元之前,首先确保该进程已经成功的发送了这个消息。如果设为此类型,那么下文的NotifyAccess=
将只能设为非none
值。如果未设置NotifyAccess=
选项、或者已经被明确设为none
,那么将会被自动强制修改为main
。注意,目前Type=notify
尚不能与PrivateNetwork=yes
一起使用。 - idle
idle
与simple
类似,不同之处在于,服务进程将会被延迟到所有活动任务都完成之后再执行。这样可以避免控制台上的状态信息与shell脚本的输出混杂在一起。注意:(1)仅可用于改善控制台输出,切勿将其用于不同单元之间的排序工具;(2)延迟最多不超过5秒,超时后将无条件的启动服务进程。
定义流程
定义控制单元 [Unit]
[Unit]
Description= 描述这个单元
定义服务体 [Service]
[Service]
Type= 启动类型
安装服务 [Install]
[Install]
WantedBy=multi-user.target
Alias=给你自己的别名,这样 systemctl command xxx.service 的时候就可以不输入完整的单元名称。比如你给 NetworkManager 一个别名叫 Alias=nm,那你就可以 systemctl status nm.service 查看实际是 NetworkManager.service 的服务了。
Also=安装本服务的时候还要安装别的什么服务。比如我们的 He.net 脚本按理应该需要一个 iproute2.service 作为 also,但是 iproute2 实际上不需要 systemd 控制,所以就没写。它和 [Unit] 定义里面的依赖关系相比,它管理的不是运行时依赖,而是安装时。安装好了之后启动谁先谁后,谁依赖谁,和 Also= 都没有关系。
示例
Network Manager
[Unit]
Description=Network Manager
Documentation=man:NetworkManager(8)
Wants=network.target
After=network-pre.target dbus.service
Before=network.target
[Service]
Type=dbus
BusName=org.freedesktop.NetworkManager
ExecReload=/usr/bin/busctl call org.freedesktop.NetworkManager /org/freedesktop/NetworkManager org.freedesktop.NetworkManager Reload u 0
#ExecReload=/bin/kill -HUP $MAINPID
ExecStart=/usr/sbin/NetworkManager --no-daemon
Restart=on-failure
# NM doesn't want systemd to kill its children for it
KillMode=process
CapabilityBoundingSet=CAP_NET_ADMIN CAP_DAC_OVERRIDE CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_MODULE CAP_AUDIT_WRITE CAP_KILL CAP_SYS_CHROOT
ProtectSystem=true
ProtectHome=read-only
[Install]
WantedBy=multi-user.target
Also=NetworkManager-dispatcher.service
# We want to enable NetworkManager-wait-online.service whenever this service
# is enabled. NetworkManager-wait-online.service has
# WantedBy=network-online.target, so enabling it only has an effect if
# network-online.target itself is enabled or pulled in by some other unit.
Also=NetworkManager-wait-online.service