暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

如何在 Linux 中创建 systemd 服务

TIAP 2022-09-08
1522

到现在为止,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 server
    After=network.target
    Before=nextcloud-web.service


    [Service]
    ExecStart=/usr/local/apache2/bin/httpd -D FOREGROUND -k start
    ExecReload=/usr/local/apache2/bin/httpd -k graceful
    Type=notify
    Restart=always


    [Install]
    WantedBy=default.target
    RequiredBy=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 的完整文档,请参考:
    https://www.freedesktop.org/wiki/Software/systemd/

    创建一个 systemd 服务

    上面我们了解了 systemd 服务文件的基本结构,那现在我们根据一个例子来了解一下如何创建一个 systemd 服务。

    这个例子,我写了一个名为 check-file-system.sh 的 bash 脚本,放在 ~/.scripts/ 目录下,在系统启动时运行。如下为脚本代码:

      #!/usr/bin/env bash


      ROOT_PARTITION=$(mount | grep '/ ' | awk '{print $1}')
      PHYSICAL_DISK=$(lsblk -no pkname ${ROOT_PARTITION} | head -n 1)


      if [ ${EUID} -ne 0 ]
      then
      exit 1 # this is meant to be run as root
      fi


      fsck dev/${PHYSICAL_DISK}

      注意:上述脚本只用于演示,实际运行的时候会失败,因为我们 fsck 的设备是根文件系统(rootfs)。

      我们先来解释一下上述脚本所要做的事情。首先查找根目录挂载的磁盘分区,可能是 dev/sda1 或者 dev/sdb2,或者其他地方,使用它,可以找到实际的磁盘名(sda)。

      有了这些信息,在该驱动器上使用 fsck 命令运行文件系统检查,然后在每次启动时运行此脚本。

      然后,我们创建一个 systemd 服务文件,如下:

        [Unit]
        Description=Checking filesytems on boot
        After=multi-user.target


        [Service]
        ExecStart=/usr/bin/bash home/pratham/.scripts/check-file-system.sh
        Type=simple


        [Install]
        WantedBy=multi-user.target

        选择 systemd 服务文件的存放位置

        现在,我们的启动脚本和 systemd 服务文件都准备好了,那么 systemd 服务文件应该放在哪里呢?

        在回答这个问题之前,我们先来考虑另外一个问题:这个 systemd 服务,谁来执行它?需要超级用户权限吗?需要特定用户来执行吗?

        根据执行服务的用户,以下是可以用来存放 systemd 服务文件的可选位置:

        root: /etc/systemd/system/
        pratham: /home/pratham/.config/systemd/user/

        注:pratham 为本例中的一个系统用户名。

        如果一个服务需要超级用户权限,比如每6小时生成一个文件系统数据库,那么就需要放在 /etc/systemd/system/ 目录中。

        注意:由普通用户执行的 systemd 服务需要传递 --user 选项。比如,如果只有用户 pratham 拥有名为 greet-pratham.service 的服务,为了重启它,我们需要运行命令:systemctl --user restart greet-pratham.service

        对于没有什么特殊权限的服务,最好由普通用户来执行,比如 pratham,因此,这种类型的服务可以放在 ~/.config/systemd/user/ 路径下。

        在我们的例子中,执行的是文件系统检查,这需要超级用户权限。因此,我将把  systemd 服务文件放在/etc/systemd/system/目录中,绝对路径是:

        /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 boot
                Loaded: 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 ago
                Main PID: 130145 (code=exited, status=8)
                CPU: 82ms


                Sep 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.2
                Sep 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/a
                Sep 06 09:57:04 vidhyaa systemd[1]: fsck-on-boot.service: Failed with result 'exit-code'.

                如前所述,脚本执行失败了,不过这不是重点,重点是我们要执行的服务已经启动了。

                现在你可以将其视为常规服务进行停止、启动、重启、禁用等操作了。

                以上就是本次分享全部内容,欢迎讨论。


                文章转载自TIAP,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                评论