简要:Systemd服务的基本操作 以及 单元文件的编写。
0x00 Systemd简介
Systemd是常用的Linux服务管理组件,其负责Linux中各种服务的调度和管理,如timedatectl
可管理系统时间,journalctl
管理服务日志,systemctl
管理服务和系统等。
0x01 Systemctl基本操作
# 运行服务
systemctl start sshd
# 停止服务
systemctl stop sshd
# 重启服务
systemctl restart sshd
# 重新加载服务(对于优化的服务,可平滑加载配置文件而不重启其程序)
systemctl reload sshd
# 杀死服务(将直接杀死服务的进程和子进程)
systemctl kill sshd
# 服务开机启动
systemctl enable sshd
# 服务开机不启动
systemctl disable sshd
0x02 服务单元文件的编写
Systemd单元文件的默认目录在/etc/systemd/system/
和/usr/lib/systemd/system/
,/etc的具有更高的优先级。
打开/usr/lib/systemd/system/
目录,可以看到一大堆.service
、.socket
、.timer
、.target
结尾的文件和.target.wants
结尾的目录。这些都是systemd需要使用到的服务单元。service表示服务单元,socket表示网络通信单元,timer表示定时执行单元、target表示一组服务。
首先我们来看看sshd服务单元的文件内容:( /usr/lib/systemd/system/sshd.service
)
[Unit]
Description=OpenSSH Daemon
Wants=sshdgenkeys.service
After=sshdgenkeys.service
After=network.target
[Service]
ExecStart=/usr/bin/sshd -D
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=always
[Install]
WantedBy=multi-user.target
这便是一个service文件的基本格式。[Unit]
定义该单元的基本信息和依赖关系;[Service]
定义该单元开始、停止等的执行命令;[Install]
定义该单元在哪个阶段自动启动。下面我们来认识一下吧。
[Unit]
Wants表示这个单元的依赖关系,After表示该单元需要在这些服务启动后才能启动。此外还有Before,表示要在这个单元之前启动。如果只有Wants而不定义After等顺序,那么这两个服务将同时启动。
启动失败的关系:若该单元Wants的服务启动失败,那么该单元也启动失败。如网络启动失败,则sshd也启动失败。
[Service]
ExecStart表示这个单元启动的命令。如在执行systemctl start sshd
后将执行/usr/bin/sshd -D
,此外还可定义ExecStop、ExecReload、ExecRestart。
启动方式
Systemd还支持多种启动方式,启动方式用Type定义。一些用法如下:
Type=simple
默认,进程启动后一直保持运行,systemd会根据该进程的pid等信息判断服务是否启动成功。若该进程一直存在,使用systemctl status xxx查询时会显示“Running”Type=forking
服务开始后启动子程序,并且其父程序立即退出。可以指定PIDFile=/xxx
以让systemd监视服务状态。Type=oneshot
适用于执行脚本,表示服务启动后会立即退出。使用RemainAfterExit=yes
让systemd认为其始终处于运行状态。
还有DBus、idle、notify等启动方式,有兴趣的可以参考https://wiki.archlinux.org/index.php/Systemd#Service_types
重试和重启行为
如果服务启动失败,可定义一些参数配置systemd重试的行为:
Restart=always
表示服务进程一退出便立即重启;Restart=on-failure
表示服务启动失败时重启。
RestartSec=5
定义每次重启重试的间隔时间。
StartLimitInterval=5
表示启动间隔限制,可避免启动失败后重试过于频繁。
StartLimitBurst=10
限制启动失败重试的次数,若超过这个次数将不再尝试启动该服务。
[Install]
Install节主要需要定义WantedBy属性。表示开机启动此服务的时机。上面sshd的例子multi-user.target
表示一个启动阶段。所有的启动阶段如下:
运行阶段 | systemd Target | 备注 |
---|---|---|
0 | runlevel0.target, poweroff.target | Halt the system. |
1, s, single | runlevel1.target, rescue.targetmulti-user.target | 系统处于单用户模式时 |
2, 4 | runlevel2.target, runlevel4.target, multi-user.target | 用户定义的的target |
3 | runlevel3.target, multi-user.target | 图形化界面尚未启动的多用户模式,用户可通过网络登陆多个控制台了。 |
5 | runlevel5.target, graphical.target | 多用户模式,已经显示图形化界面的登录界面。(通常包含阶段3的所有服务和一个图形化登陆界面) |
6 | runlevel6.target, reboot.target | 重启模式 |
emergency | emergency.target | 急救模式 |
一般来说,使用multi-user.target
已经足够。要调整各个服务的依赖关系的话,可通过[Unit]中的Wants和After等属性更改。
0x03 编写一个服务单元
本节介绍一些编写自定义服务的技巧和提示。
被更新覆盖的单元文件
如果使用软件包管理器更新软件时,可能会将其自带的服务单元文件直接复制至/usr/lib/systemd/下,导致所做的更改丢失。所以建议在优先级更高的目录/etc/systemd/下创建并修改服务目录文件。
当然,也不建议将/usr/lib/systemd/下的单元文件复制到/etc/systemd/下修改,这样更新软件后,新的单元文件被复制到/usr/lib/systemd/下,却被优先级更高的/etc/systemd/下的文件顶替,导致新的单元文件没有被应用。所以,若要修改一个已经存在并且被软件包管理器管理的单元文件,我们可以使用另一种方式修改:
在/etc/systemd/
相应位置创建xxx.xxx.d
目录,然后再在该目录下创建相应的.conf
文件,systemd就会自动应用这些.conf
文件内的属性值,应用顺序是按字典排序顺序。
如要修改sshd的运行方式,使其在每次服务启动时均输出一行信息:
首先在/etc/systemd/system/
下创建一文件夹sshd.service.d
然后在该目录下新建一文件如10-override_exec.conf
,内容写入如下:
[Service]
ExecStart=echo "Starting sshd..." && /usr/bin/sshd -D
即可完成属性的重载。
注:在Linux中,配置目录一般是/etc,直接修改/usr/share下的配置文件可不是一个好习惯,因为这个目录中的软件一般是由软件包管理器管理的,随着更新这些文件将被新版本的覆盖,而且大多数软件将其视为较低优先级的配置甚至是默认配置。
by 橙汁
模板使用
在启用一个服务时,你可能会接触到形如systemctl start foo@bar.service的情形。这里使用到了systemd的单元模板。下面让我们来看看怎么做到这一点。
在模板中,使用%i表示@后面.service之前的内容。systemd中称为instance(进程)。可以查看OpenVPN客户端的单元文件:
➜ cat /usr/lib/systemd/system/openvpn-client@.service
[Unit]
Description=OpenVPN tunnel for %I
After=syslog.target network-online.target
Wants=network-online.target
Documentation=man:openvpn(8)
Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage
Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO
[Service]
Type=notify
PrivateTmp=true
WorkingDirectory=/etc/openvpn/client
ExecStart=/usr/bin/openvpn --suppress-timestamps --nobind --config %i.conf
User=openvpn
Group=network
AmbientCapabilities=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE
CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE
LimitNPROC=10
DeviceAllow=/dev/null rw
DeviceAllow=/dev/net/tun rw
ProtectSystem=true
ProtectHome=true
KillMode=process
[Install]
WantedBy=multi-user.target
如果单元正常启动,那么将在/etc/systemd/
下相应位置创建openvpn@bar.service
软链接,链接至/usr/lib/systemd/
下的openvpn@.service
,所以在成功执行了一次该单元相关的命令后,可方便地补全相应服务进程。
参考文献和链接
systemd配置文件及管理方法详解https://blog.csdn.net/weixin_33812433/article/details/92656944
systemd.unit 中文手册 译者:金步国
http://www.jinbuguo.com/systemd/systemd.unit.html#
systemd.service 中文手册 译者:金步国(推荐阅读)
http://www.jinbuguo.com/systemd/systemd.service.html