LINUX添加自定义系统服务[Systemd]

前言:

Init进程作为LINUX系统初代初始化进程服务的程序,目前已逐渐被Systemd程序所取代了。就学习成本与易用性上来说,Init方式显然要简单得多。然而,就目前LINUX系统基本都加入Systemd程序来代替Init程序来管理系统初始化进程服务来说,Systemd想必有其特定的优势。而事实上,Systemd程序也确实有其优势,在处理进程依赖、进程控制、故障处理等方面,要比Init方式要好很多。Systemd程序的功能要强很多,伴随而来的是,更高的学习成本与更复杂的配置指令,就配置指令来说,简单看其配置指令解释文件,大概有上百条不同用途的指令,这当中,某些指令还有其特定的配置参数等等。这也是很多习惯了Init方式的用户不喜欢Systemd的原因,尽管Systemd还保留着对Init方式的兼容。

无论如何,Systemd代替Init程序已是大势所趋,我们也只能去适应时代的需求了。所幸的是,尽管Systemd的配置指令非常多及非常复杂,然而作为大多数的用户或管理人员,我们只需要熟悉少量的指令便享受Systemd的强大功能,以下,就是LINUX添加自定义系统服务基础方法,很多时候,这一基础方法便能满足我们的大部分需求了。

 一、相关目录

与SYSTEMD服务相关的目录:

[/etc/systemd/system/]  :常用目录,系统管理员和用户使用;

[/run/systemd/system/]  :运行时配置文件;

[/usr/lib/systemd/system/]  :很多文章提及此目录,但在较新的LINUX系统上未发现,可能被弃用了[未确定];

 二、区块说明及常用配置

以下操作均基于DEBIAN系统,现在本文以“ssh.service”文件为例说明,以下为本文系统上的文件实际情况:

Edward@FionaWong:~ $ cat /lib/systemd/system/ssh.service 
[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify

[Install]
WantedBy=multi-user.target
Alias=sshd.service

其基本结构分为“[Unit]”、“[Service]”、“[Install]”三个区块。“[Unit]”区块主要任务是决定服务加载前相关条件要求;“[Service]”区块主要是进行对服务加载、加载过程及运行过程的控制;“[Install]”区块相对简单,基本为为配合“systemctl”命令而生成一些系统必须的相关软链接;对于SYSTEMD,实际对还区分为很多种不同类型的单元,具体表现为不同的文件后缀,如:[.socket]、[.mount]、[.service]等,本文仅简单讨论[.service]后缀的单元,虽然是简单介绍,这结合自定义的脚本,这基本上能满足大部人所希望实现的功能了,即使用SYSTEMD对自定义服务实现服务启动、终止、重载、开机启动等。

“[Unit]”区块常用配置项:

Description=
# 对单元的作用或服务进行简单的描述;

Documentation=
# 一组用空格分隔的文档URI列表,可用URI类型是:[ http://、https://、file:、info:、man: ]

Requires=
# 设置此单元所必须依赖的其他单元,即当此单元被启动时,所列出的其他单元也必须被启动;
# 若列出的某个单元启动失败、同时这一失败单元又被设置了[ After= ]依赖,则此单元不会被启动;
# 此选项并不影响单元之间的启动或停止顺序;
# 要添加多个单元,可重复引用此选项;也可使用单选项指定单元列表的方式表示[空格分隔];
# 此配置项还有多个同类功能的项,不同项间有细微区别,此为常用项;

Before=
# 强制指定单元之间的先后顺序[接受一个空格分隔的单元列表],意义:在本单元启动后再启动指定单元;
# 停止顺序与启动顺序正好相反;

After=
# 强制指定单元之间的先后顺序[接受一个空格分隔的单元列表],意义:在指定单元启动后再启动本单元;

OnFailure=
# 接受一个空格分隔的单元列表,当本单元进入失败[ failed ]状态时,将会启动列表中的单元;

PropagatesReloadTo=
# 接受一个空格分隔的单元列表,表示在 reload 本单元时,也同时 reload 所有列表中的单元;

ReloadPropagatedFrom=
# 接受一个空格分隔的单元列表,表示在 reload 列表中的某个单元时,也同时 reload 本单元;

ConditionPathExists= 、AssertPathExists=
# 检测指定的路径是否存在[必须使用绝对路径];
# 区别参看下文“说明A”;

ConditionPathIsDirectory= 、AssertPathIsDirectory=
# 检测指定的路径是否存在并且是一个目录,必须使用绝对路径;
# 区别参看下文“说明A:”;

# 说明A:
# 此类关于合法性条件检测的功能有多个,以上介绍为常用项;
# C字头 :在启动单元之前,首先测试特定的条件是否为真,若为真则开始启动,否则将会跳过此单元[非进入"failed"状态];
# A字头 :在单元启动之前,首先进行相应的断言检查,若为真则开始启动,否则若断言失败,将导致该单元启动失败[进入"failed"状态];
# 注1:部分配置项可使用感叹号[!]前缀表示逻辑反转;
# 注2:部分配置项参数太多,需要查询后使用;

“[Service]”区块常用配置项:

Type=
# 设置进程的启动类型,值:[ simple、forking、oneshot、dbus、notify、idle ];
# 默认值:simple

PIDFile=
# 守护进程的PID文件,必须是绝对路径。

ExecStart=
# 在启动该服务时需要执行的命令行[ 命令 + 参数 ];
# 仅在[ Type=oneshot ]的情况下,才可以设置任意个命令行[包括零个];
# 必须以一个绝对路径表示的可执行文件开始;
# 绝对路径前的特殊前缀:
# --> @  :其后的那些参数将依次作为"argv[0] argv[1] argv[2] …"传递给被执行的进程;
#     -  :即使该进程以失败状态退出,也会被视为成功退出;
#     +  :进程将拥有超级用户权限[将无视部分配置项];
#     !  :同“+”,但无视配置项部分有区别;
#     !! :同“+”,但无视配置项部分有区别;

ExecStartPre=, ExecStartPost=
# 设置在执行[ ExecStart= ]之前/后执行的命令行;语法规则同[ ExecStart= ];

ExecReload=
# 可选,用于设置当该服务被要求重新载入配置时所执行的命令行;语法规则同[ ExecStart= ];

ExecStop=
# 可选,用于设置当该服务被要求停止时所执行的命令行;语法规则同[ ExecStart= ];

ExecStopPost=
# 可选,用于设置在该服务停止之后所执行的命令行;语法规则同[ ExecStart= ];
# 无论服务是否成功启动,此选项中设置的命令都会在服务停止后被无条件的执行;

Restart=
# 当服务进程正常退出、异常退出、被杀死、超时的时候, 是否重新启动该服务;默认值:[ no ];
# 值:[ no、always、on-success、on-failure、on-abnormal、on-watchdog、on-abort ];

“[Install]”区块常用配置项:

Alias=
# 启用时使用的别名,可以设为一个空格分隔的别名列表;
# 每个别名的后缀(也就是单元类型)都必须与该单元自身的后缀相同;

WantedBy=
# 接受一个空格分隔的单元列表,表示在使用[ systemctl enable] 启用此单元时;
# 将会在每个列表单元的[ .wants/ ]目录中创建一个指向该单元文件的软连接;

RequiredBy=
# 接受一个空格分隔的单元列表, 表示在使用[ systemctl enable] 启用此单元时;
# 将会在每个列表单元的[ .requires/ ]目录中创建一个指向该单元文件的软连接;

Also=
# 设置此单元的附属单元,可以设为一个空格分隔的单元列表;
# 表示当使用[ systemctl enable ]启用或[ systemctl disable ]停用此单元时,也同时自动的启用或停用附属单元;

DefaultInstance=
# 仅对模板单元有意义,用于指定默认的实例名称。如果启用此单元时没有指定实例名称,那么将使用这里设置的名称;

三、SYSTEMD守护进程目录

SYSTEMD守护进程是使用“systemctl”命令对服务进行控制的,常用的命令如下:

命令说明
systemctl start ssh.service启动指定服务
systemctl stop ssh.service停止指定服务
systemctl restart ssh.service重新启动指定服务
systemctl reload ssh.service重新加载指定服务的配置
systemctl status ssh.service查看指定服务的运行状态
systemctl daemon-reload刷新SYSTEMD的配置信息
systemctl enable ssh.service设定指定服务启用开机自启动
systemctl disable ssh.service设定指定服务禁用开机自启动
systemctl is-active ssh.service查询指定服务的活动状态
systemctl list-units –type=service查询所有已启动的服务

四、尝试自定义服务示例

现在,本文模拟一个情境,系统上有一个名为“v2ray”的可执行文件,可使用命令[/opt/v2ray/v2ray -config /opt/v2ray/KCP_WSTLS.json]提供某一项长期性的网络服务,但这可执行文件基于某种原因,若长期运行可能产生不稳定状况,于是希望该程序可以实现定时自动重新启动保持稳定性;基于以上需求大概可以考虑的有三种方式:1、编写脚本及利用系统上的定时任务功能[/etc/crontab];2、添加基于SYSTEMD守护进程的自定义服务结合系统上的定时任务功能;3、添加基于SYSTEMD守护进程的自定义服务并使用SYSTEMD的[Timer]区块;由于本文未涉及[Timer]区块,本例将以方式2作说明。

步骤一:在[/lib/systemd/system]目录下创建“v2ray.service”文件,并使用“nano”命令进入编辑界面;

Edward@FionaWong:~ $ touch /lib/systemd/system/v2ray.service
Edward@FionaWong:~ $ nano /lib/systemd/system/v2ray.service

步骤二:在[v2ray.service]文件写入如下配置项;参见下面配置,实际上自定义一项服务需要设定的配置项并不多,下述配置只是定义的服务的描述信息、设定启动条件及其基础的依赖,再加上启动命令与重载命令即完成了自定义服务的配置,另外,下述配置为防止一些配置文件缺失,加入了一条配置文件检测项,实际若不需要配置文件检测,仅需要编写六项配置,即可完成一个自定义服务!

[Unit]
Description=V2ray daemon
# 关于本服务的功能描述性信息;

ConditionPathExists=/opt/v2ray/Server_KCP_WS.json
# 检测配置文件是否存在[当指定文件存在时才能正常启动服务];

After=network.target
# 表示在[network.target]相关服务启动完成后再启动本服务;
# [network.target]包含了系统上所有默认基础的网络服务;
# 对于自定义添加的网络的服务,在系统所有默认网络服务启动完成后,
# 再加载自定义网络服务,是避免意外错误的理想方式;


[Service]
Type=simple
# 自定义服务的启动方式,本处采用默认值;

ExecStart=/opt/v2ray/v2ray -config /opt/v2ray/Server_KCP_WS.json
# 本服务需要执行的命令;

ExecReload=/bin/kill -HUP $MAINPID
# 重新加载服务配置时,以何种方式结束原进程;
# [$MAINPID]为系统变量,记录了该服务的PID值;


[Install]
WantedBy=multi-user.target
# 本服务正常运行需要依赖的单元;
# 若自定义服务可在命令行界面下运行,则配置为[multi-user.target]即可;
# 若自定义服务需要依赖图形化界面,则可配置为[graphical.target];
# 更多[multi-user.target]与[graphical.target]的信息请自行搜索;

步骤三:启用自定义服务并设定开机启动,及服务状态查询;

Edward@FionaWong:~ $ systemctl daemon-reload
# 重新加载STSTYEMD守护进程的配置信息[发现新创建的服务];

Edward@FionaWong:~ $ systemctl start v2ray.service
# 启用自定义的[v2ray.service]服务;

Edward@FionaWong:~ $ systemctl enable v2ray.service
# 设定自定义的[v2ray.service]服务开机自动启动;

Edward@FionaWong:~ $ systemctl status v2ray.service
# 查询自定义的[v2ray.service]服务的状态信息;
# 使用此命令可查看状态信息,包括命令、当前活动状态、是否开机自启动等信息;

步骤四:经过上述步骤,自定义服务已经可以开机自启动了,现在本文将利用LINUX的定时任务功能实际服务定时重启;在[/etc/crontab]文件的末尾加入以下代码,下列代码的意思为:每个周一的早上6时整,以“root”用户身份重新启动[v2ray.service]服务;

0 6 * * 1        root systemctl restart v2ray.service
# 以上每列意义对应如下:
# 分 时 日 月 周 用户  命令
# 0  6  *  *  1  root  systemctl restart v2ray.service

五、强烈推荐

关于SYSTEMD,功能异常强大与复杂,强列推荐从以下网站获取相关的信息:金步国作品集[ 链接地址 ];本文大量参考了此网站的信息;

六、鸣谢

原文地址

发表回复