当前位置: 首页>>技术教程>>正文


在Linux中,如何创建systemd服务单元

, ,

尽管systemd一直是许多争议的对象,但到目前为止,有些发行版只是为了摆脱它(请参见Devuan,Debian的一个分支,默认情况下用sysvinit替换systemd),最后它已成为Linux世界中的de-facto标准初始化系统。

在本教程中,我们将了解systemd服务的结构,并学习如何创建服务。

在本教程中,您将学习:

  • 什么是服务单位
  • 服务单元的组成部分是什么。
  • 每个部分中可以使用的最常见的选项是什么。
  • 可以定义哪些不同类型的服务。

使用的软件要求和约定

软件要求和Linux命令行约定
类别 要求,约定或使用的软件版本
系统 使用systemd作为初始化系统的GNU /Linux发行版
软件 系统的
其他 需要root用户权限才能安装和管理服务。
约定 -要求给出linux命令以root特权直接作为root用户执行或通过使用sudo命令$-要求给出linux命令以普通非特权用户身份执行

systemd初始化系统

rpm

Rhel,CentOS,Fedora,Ubuntu,Debian和Archlinux等所有主要发行版都将systemd用作其初始系统。实际上,Systemd不仅仅是一个init系统,这就是为什么某些人强烈反对其设计的原因之一,该设计与公认的unix座右铭相反:“做一件事情,做好一件事情”。在其他初始化系统使用简单的shell脚本来管理服务的情况下,systemd使用其自身的.service文件(带有.service后缀的单元):在本教程中,我们将了解它们的结构以及如何创建和安装它们。




(adsbygoogle = window.adsbygoogle || [])。push({});


服务单元剖析

什么是服务单位?带有.service后缀包含有关由systemd管理的进程的信息。它由三个主要部分组成:

  • [单位]:此部分包含与单位类型没有特别关系的信息,例如服务说明
  • [服务]:包含有关设备特定类型的信息,在这种情况下为服务
  • [安装]:本节包含有关本机安装的信息

让我们对其进行详细分析。

[单位]部分

[Unit]一个部分.service文件包含对单元本身的描述,以及有关其行为及其依赖关系的信息:(要正常工作,一项服务可能依赖于另一项服务)。在这里,我们讨论可以在本节中使用的一些最相关的选项

“Description”选项

首先我们有Description选项。通过使用此选项,我们可以提供单位的描述。例如,当调用systemctl命令,该命令返回systemd状态的概述。作为示例,这里是如何描述httpd服务在Fedora系统上定义:


[Unit]
Description=The Apache HTTP Server

“After”选项

通过使用After选项,我们可以声明应该以空格分隔的列表形式在提供的单元之后启动我们的单元。例如,再次观察定义Apache Web服务的服务文件,我们可以看到以下内容:

After=network.target remote-fs.target nss-lookup.target httpd-init.service

上面的行指示systemd启动服务单元httpd.service只有在networkremove-fsnss-lookup目标和httpd-init service

用”Requires”指定硬依赖性




(adsbygoogle = window.adsbygoogle || [])。push({});


如上文所述,一个单元(在我们的情况下为服务)可以依赖于其他单元(不一定是”service”单元)才能正常工作:可以使用Requires选项。

如果服务所依赖的任何单元无法启动,则该服务的激活将停止:这就是为什么将这些单元称为hard dependencies。在这一行中,从avahi-daemon的服务文件中提取出来,我们可以看到它如何从avahi-daemon.socket单元中声明为从属文件:

Requires=avahi-daemon.socket

使用”Wants”声明”soft”依赖性

我们刚刚看到了如何使用来声明服务的所谓”hard”依赖关系Requires选项;我们还可以使用以下命令列出”soft”依赖项Wants选项。

有什么区别?如上所述,如果任何”hard”依赖关系失败,则服务本身也会失败;任何”soft”依赖项的失败都不会影响从属单元发生的情况。在提供的示例中,我们可以看到docker.service单位对docker-storage-setup.service之一:

[Unit]
Wants=docker-storage-setup.service

[服务]部分

在里面[Service]一个部分service我们可以将单位指定为启动服务时要执行的命令或服务本身的类型。让我们看看其中的一些。

启动,停止和重新加载服务

可以启动,停止,重新启动或重新加载服务。可以使用以下选项中的相关选项来指定执行这些操作中的每一个时要执行的命令。[Service]部分。

服务启动时要执行的命令是通过使用ExecStart选项。传递给该选项的参数也可以是脚本的路径。 (可选)我们可以使用以下命令声明要在服务启动之前和之后执行的命令:ExecStartPreExecStartPost选项。这是用于启动NetworkManager服务的命令:



(adsbygoogle = window.adsbygoogle || [])。push({});


[Service]
ExecStart=/usr/sbin/NetworkManager --no-daemon

以类似的方式,我们可以使用以下命令指定重新加载或停止服务时要执行的命令:ExecStopExecReload选项。与发生的情况类似ExecStartPost,可以使用以下命令指定一个或多个进程停止后要启动的命令:ExecStopPost选项。

服务类型

Systemd根据其预期行为定义和区分某些不同类型的服务。可以使用以下命令定义服务类型Type选项,提供以下值之一:

  • 简单
  • 分叉
  • 单发
  • 公交车
  • 通知

服务的默认类型,如果TypeBusname选项未定义,但是通过ExecStart选项,是simple。设置此类型的服务后,在ExecStart被认为是主要过程/服务。

forking类型的工作方式不同:随附的命令ExecStart预计将分叉并启动一个子进程,该子进程将成为主要的进程/服务。启动过程结束后,预计父进程将死亡。

oneshot如果将TypeExecStart选项未定义。它的工作原理很像simple:区别在于,该过程有望在其他部门启动之前完成工作。但是,即使命令退出后,该单元仍被视为”active”。RemainAfterExit选项设置为”yes”(默认为”no”)。

下一类服务是dbus。如果使用此类型的服务,则守护程序应从中获取名称Dbus,如BusName选项,在这种情况下成为必需。对于其余的,它像simple类型。但是,仅在获得DBus名称后才启动后续单元。

另一个过程的工作原理与simple,这是notify:区别在于,该守护程序应通过以下方式发送通知:sd_notify功能。仅在发送此通知后,后续单元才会启动。

设置进程超时

通过使用特定选项,可以为服务定义一些超时。让我们开始RestartSec:通过使用此选项,我们可以设置systemd在重新启动服务之前应等待的时间(默认为秒)。时间跨度也可以用作此选项的值,例如“ 5min 20s”。默认是100ms




(adsbygoogle = window.adsbygoogle || [])。push({});


TimeoutStartSecTimeoutStopSec选项可用于分别指定服务启动和停止的超时(以秒为单位)。在第一种情况下,如果在指定的超时后守护进程启动过程未完成,则将其视为失败。

在第二种情况下,如果服务要停止但在指定的超时后没有终止,则首先SIGTERM然后,经过相同的时间后,SIGKILL信号被发送给它。这两个选项都接受时间跨度作为值,并且可以使用快捷方式立即进行配置:TimeoutSec。如果infinity作为值提供,则禁用超时。

最后,我们可以使用以下命令设置服务运行时间的限制RuntimeMaxSec。如果服务超过此超时,则它将终止并视为失败。

[安装]部分

在里面[install]部分,我们可以使用与服务安装相关的选项。例如,通过使用Alias选项,我们可以指定使用systemctl命令时用于服务的别名的空格分隔列表。enable)。

与发生的情况类似RequiresWants中的选项[Unit]部分中的建立依赖关系[install]部分,我们可以使用RequiredByWantedBy。在这两种情况下,我们都将根据所配置的单元声明一个单元列表:使用前一种选项时,它们将是hard-dependent,而使用后一种选项,它们将仅被视为weak-dependent。例如:


[Install]
WantedBy=multi-user.target

在上面的行中,我们声明multi-user目标对我们单位有软依赖性。在系统术语中,以.target后缀,可以与所谓的runtimes在其他init系统中Sysvinit。因此,在我们的情况下,达到multi-user目标时应包括我们的服务。

创建和安装服务单元

在文件系统中,基本上有两个位置安装了systemd服务单元:/usr/lib/systemd/system/etc/systemd/system。前者路径用于已安装软件包提供的服务,而后者可以由系统管理员用于其自己的服务(可以覆盖默认服务)。

让我们创建一个自定义服务示例。假设我们要创建一个服务,该服务在启动时在特定的以太网接口(在本例中为ens5f5)上禁用wake-on-lan功能,在停止时禁用re-enables。我们可以使用ethtool命令完成主要任务。我们的服务文件如下所示:

[Unit]
Description=Force ens5f5 ethernet interface to 100Mbps
Requires=Network.target
After=Network.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/ethtool -s ens5f5 wol d
ExecStop=/usr/sbin/ethtool -s ens5f5 wol g

[Install]
WantedBy=multi-user.target


(adsbygoogle = window.adsbygoogle || [])。push({});


我们设置了一个简单的单元描述,并声明该服务取决于network.target单位,并应在达到目标后启动。在里面[Service]部分,我们将服务类型设置为oneshot,并指示systemd使用以下命令将服务视为已激活:RemainAfterExit选项。我们还定义了启动和停止服务时要运行的命令。最后,在[Install]部分,我们基本上宣布我们的服务应包含在multi-user目标。

要安装该服务,我们会将文件复制到/etc/systemd/system目录为wol.service,那么我们将开始:

$ sudo cp wol.service /etc/systemd/system && sudo systemctl start wol.service

我们可以使用以下命令来验证该服务是否处于活动状态:


$ systemctl is-active wol.service
active

如预期的那样,命令的输出为active。现在验证是否已将“唤醒局域网”设置为d,因此现在已将其禁用,我们可以运行:


$ sudo ethtool ens5f5|grep Wake-on
Supports Wake-on: pg
Wake-on: d

现在,停止服务应该产生相反的结果,并且re-enable wol:


$ sudo systemctl stop wol.service && sudo ethtool ens5f5|grep Wake-on
Supports Wake-on: pg
Wake-on: g

结论

在本教程中,我们了解了systemd服务文件的组成方式,其节以及可以在每个文件中使用的一些选项。我们学习了如何设置服务描述,定义其依赖关系以及声明在启动,停止或重新加载时应执行的命令。

由于systemd(无论是否喜欢它)已成为Linux世界中的标准初始化系统,因此熟悉其工作方式非常重要。可以找到官方的系统服务文档在freedesktop网站上。您也可能对阅读我们的文章感兴趣用systemd管理服务

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/11168.html,未经允许,请勿转载。