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”文件为例说明,以下为本文系统上的文件实际情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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]”区块常用配置项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
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]”区块常用配置项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
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]”区块常用配置项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
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”命令进入编辑界面;
1 2 |
Edward@FionaWong:~ $ touch /lib/systemd/system/v2ray.service Edward@FionaWong:~ $ nano /lib/systemd/system/v2ray.service |
步骤二:在[v2ray.service]文件写入如下配置项;参见下面配置,实际上自定义一项服务需要设定的配置项并不多,下述配置只是定义的服务的描述信息、设定启动条件及其基础的依赖,再加上启动命令与重载命令即完成了自定义服务的配置,另外,下述配置为防止一些配置文件缺失,加入了一条配置文件检测项,实际若不需要配置文件检测,仅需要编写六项配置,即可完成一个自定义服务!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
[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]的信息请自行搜索; |
步骤三:启用自定义服务并设定开机启动,及服务状态查询;
1 2 3 4 5 6 7 8 9 10 11 12 |
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]服务;
1 2 3 4 |
0 6 * * 1 root systemctl restart v2ray.service # 以上每列意义对应如下: # 分 时 日 月 周 用户 命令 # 0 6 * * 1 root systemctl restart v2ray.service |
五、强烈推荐
关于SYSTEMD,功能异常强大与复杂,强列推荐从以下网站获取相关的信息:金步国作品集[ 链接地址 ];本文大量参考了此网站的信息;
网友评论1条