到现在为止,systemd 已经被广泛使用,它存在于大多数 Linux 发行版中,比如Ubuntu, Fedora, RHEL, Debian, Pop!_OS, openSUSE, Arch 等。所以,学习如何创建 systemd 服务是有必要的。我们今天来介绍一下这个问题。
什么是 systemd 服务
简单来说,服务(service)是一个”后台“进程,根据特定情况启动或停止,一般情况下不需要手动启动或停止。systemd 服务是以某种格式编写的一个文件,其被 systemd 进程解析和理解文件中的内容,然后按照要求执行。
从技术上来讲,“systemd 服务”文件确切的来讲应该是“systemd 单元(unit)”文件。不过本文讲述主要是关于创建 systemd 服务的,所以我们还是称其为 systemd 服务文件。
systemd 服务文件的基本结构
systemd 服务文件由三个主要部分组成,分别是 [Unit], [Service] 和 [Install],文件扩展名为 .service。
如下是一个 systemd 服务文件的示例:
[Unit]Description=Apache web serverAfter=network.targetBefore=nextcloud-web.service[Service]ExecStart=/usr/local/apache2/bin/httpd -D FOREGROUND -k startExecReload=/usr/local/apache2/bin/httpd -k gracefulType=notifyRestart=always[Install]WantedBy=default.targetRequiredBy=network.target
这是 systemd 服务文件的基本结构,下面我们来详细了解下。
[Unit] 部分
Unit 部分包括服务的描述和详情信息。在上面的例子中,详情信息比如“它描述的是什么”,“它的依赖关系是什么”等。
以下为对该部分字段的解释:
Description:systemd 服务的标题;
After:设置对服务的依赖关系。例如,如果正在配置Apache web服务器,则希望服务器在网络联机后启动,这通常包括目标或其他服务;
Before:在指定服务之前启动当前服务。在上述例子中,描述为:在启动 Nextcloud 之前运行 Apache web server。这是因为(在该示例中)Nextcloud 服务依赖于 Apache web server,这也包括目标或其他服务。
[Service] 部分
该部分包含有关服务执行和终止的详细信息。
以下是各字段解释:
ExecStart:服务启动时需要执行的命令。在本例中,我们希望Apache服务器启动;
ExecReload:这是一个可选字段。它指定如何重新启动服务。对于执行磁盘I/O(特别是写入磁盘,如数据库)的服务,最好平滑的地终止它们并重新启动。如果希望具有特定的重新启动机制,请使用此字段;
Type:服务进程的启动类型,包括:simple, exec, forking, oneshot, dbus, notify 以及 idle 等;
Restart:可选字段,但大多数情况下可能会用到,这里指定是否要重新启动服务(取决于环境),可选的值包括:no, on-success, on-failure, on-abnormal, on-watchdog, on-abort 以及 always。
[Install] 部分
该部分处理 systemd service/unit 文件的安装,当使用 systemctl enable 或者 systemctl disable 命令来启动或禁用服务时,使用该选项。
WantedBy:它与前面描述的 After 和 Before 类似,主要的区别是这里是用于指定 systemd 相同的运行级别。default.target 是当所有系统初始化完成时,即要求用户登录时。大多数面向用户的服务(比如Apache,cron,GNOME等)都使用这个值;
RequiredBy:该字段可能与WantedBy非常相似,但主要区别在于该字段指定了硬依赖项。这意味着,如果存在依赖关系,该服务将失败。
创建一个 systemd 服务
上面我们了解了 systemd 服务文件的基本结构,那现在我们根据一个例子来了解一下如何创建一个 systemd 服务。
这个例子,我写了一个名为 check-file-system.sh 的 bash 脚本,放在 ~/.scripts/ 目录下,在系统启动时运行。如下为脚本代码:
#!/usr/bin/env bashROOT_PARTITION=$(mount | grep '/ ' | awk '{print $1}')PHYSICAL_DISK=$(lsblk -no pkname ${ROOT_PARTITION} | head -n 1)if [ ${EUID} -ne 0 ]thenexit 1 # this is meant to be run as rootfifsck dev/${PHYSICAL_DISK}
注意:上述脚本只用于演示,实际运行的时候会失败,因为我们 fsck 的设备是根文件系统(rootfs)。
我们先来解释一下上述脚本所要做的事情。首先查找根目录挂载的磁盘分区,可能是 dev/sda1 或者 dev/sdb2,或者其他地方,使用它,可以找到实际的磁盘名(sda)。
有了这些信息,在该驱动器上使用 fsck 命令运行文件系统检查,然后在每次启动时运行此脚本。
然后,我们创建一个 systemd 服务文件,如下:
[Unit]Description=Checking filesytems on bootAfter=multi-user.target[Service]ExecStart=/usr/bin/bash home/pratham/.scripts/check-file-system.shType=simple[Install]WantedBy=multi-user.target
选择 systemd 服务文件的存放位置
现在,我们的启动脚本和 systemd 服务文件都准备好了,那么 systemd 服务文件应该放在哪里呢?
在回答这个问题之前,我们先来考虑另外一个问题:这个 systemd 服务,谁来执行它?需要超级用户权限吗?需要特定用户来执行吗?
根据执行服务的用户,以下是可以用来存放 systemd 服务文件的可选位置:
注:pratham 为本例中的一个系统用户名。
如果一个服务需要超级用户权限,比如每6小时生成一个文件系统数据库,那么就需要放在 /etc/systemd/system/ 目录中。
注意:由普通用户执行的 systemd 服务需要传递 --user 选项。比如,如果只有用户 pratham 拥有名为 greet-pratham.service 的服务,为了重启它,我们需要运行命令:systemctl --user restart greet-pratham.service
对于没有什么特殊权限的服务,最好由普通用户来执行,比如 pratham,因此,这种类型的服务可以放在 ~/.config/systemd/user/ 路径下。
/etc/systemd/system/fsck-on-boot.service。
现在我们已经创建了 systemd 服务文件并将其放在了合适的位置中,现在需要做的就是告诉 systemd 重新加载这个单元文件。systemd 是在系统启动时检测服务,而我们的服务是系统启动后新建的,所以我们需要手动启动。
让 systemd 重新加载单元文件,可以使用如下命令(需要超级用户权限):
sudo systemctl daemon-reload
或者,如果创建了用户服务,可使用以下命令:
systemctl --user daemon-reload
之后,就可以启动该服务了,我们使用如下命令启动 fsck-on-boot.service :
sudo systemctl enable fsck-on-boot.service
启动服务后,使用 systemctl status 命令来检查服务状态:
$ sudo systemctl status fsck-on-boot.service× fsck-on-boot.service - Checking filesytems on bootLoaded: loaded (/etc/systemd/system/fsck-on-boot.service; enabled; vendor preset: enabled)Active: failed (Result: exit-code) since Tue 2022-09-06 09:57:04 IST; 8s agoMain PID: 130145 (code=exited, status=8)CPU: 82msSep 06 09:57:04 vidhyaa systemd[1]: Started Checking filesytems on boot.Sep 06 09:57:04 vidhyaa bash[130153]: fsck from util-linux 2.37.2Sep 06 09:57:04 vidhyaa bash[130155]: e2fsck 1.46.5 (30-Dec-2021)Sep 06 09:57:04 vidhyaa bash[130155]: /dev/sda is in use.Sep 06 09:57:04 vidhyaa bash[130155]: e2fsck: Cannot continue, aborting.Sep 06 09:57:04 vidhyaa systemd[1]: fsck-on-boot.service: Main process exited, code=exited, status=8/n/aSep 06 09:57:04 vidhyaa systemd[1]: fsck-on-boot.service: Failed with result 'exit-code'.
现在你可以将其视为常规服务进行停止、启动、重启、禁用等操作了。
以上就是本次分享全部内容,欢迎讨论。




