前言:
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,功能异常强大与复杂,强列推荐从以下网站获取相关的信息:金步国作品集[ 链接地址 ];本文大量参考了此网站的信息;