[TOC]
一、Systemd 语法
1、三个规定
- Systemd 单元文件中的以 “#” 开头的行后面的内容会被认为是注释
- Systemd 下的布尔值,1、yes、on、true 都是开启,0、no、off、false 都是关闭。但特定shell语句中的布尔值不能互相替换。
- Systemd 下的时间单位默认是秒,所以要用毫秒(ms)分钟(m)等请显式说明。
2、定义控制单元 [Unit]
(1)服务描述
Description
:单元的描述,简要说明这个service是做什么的
(2)控制各个单元的关系
Wants
:推荐使用。本单元启动了,它“想要”的单元也会被启动。但是启动不成功,对本单元没有影响。大多数时候 Wants 的都是一个固定的系统状态而不是其它 systemd 服务。比如一个连通着的网络network-online.target
。OnFailure
:如果本单元失败了,那么启动什么单元作为折衷。
(3)定义服务启动顺序
启动时,
Before
:本服务先启动(无论成功与否)并返回状态,才会启动Before
后面的另一个服务。After
:先启动After
后面的另一个服务(无论成功与否)并返回状态,才会本服务。
关闭时,
Before
是先关自己,After
是先关别人。
3、定义服务本体 [service]
(1)声明服务类型Type
simple
:默认,这是最简单的服务类型。意思就是说启动的程序就是主体程序,这个程序要是退出那么一切皆休。但是命令行程序的一个最基本原则就是一个好的程序不能独占命令行窗口,只有少数程序比如python xxx.py
还使用这种方式。forking
:标准 Unix Daemon 使用的启动方式。启动程序后会调用 fork() 函数,把必要的通信频道都设置好之后父进程退出,留下守护精灵的子进程。你要是使用的这种方式,最好也指定下 PIDFILE=,如PIDFile=/var/run/服务名.pid
。判别上面两种类型
:命令行里运行下你的程序,持续占用命令行要按 Ctrl + C 才可以的,就不会是 forking 类型。oneshot
:一次性服务,不需要持续运行,这种服务类型就是启动、完成,不存在子进程和主进程。因为这类服务运行完就没进程了,我们经常会需要RemainAfterExit=yes
。后面配置的意思是说,即使没进程了,我们也要 Systemd 认为该服务是存在并成功了的。只要在执行那条一次性命令的时候没出错,那么它就永远认为它是成功并一直存在的,直到你关闭服务。dbus
:这个程序启动时需要获取一块 DBus 空间,所以需要和 BusName= 一起用。只有它成功获得了 DBus 空间,依赖它的程序才会被启动。
(2)设置服务启动与停止ExecStart、ExecStop
ExecStart(
**一定要把要运行的脚本权限给足,否则容易运行失败!**
)- 如果你服务的类型不是
oneshot
,那么它只可以接受一个命令,参数不限,比如你先ip tunnel create
再ip tunnel0 up
,那是两个 ip 命令,如果你不是 oneshot 类型这样是不行的。 - 如果有多条命令(
oneshot 类型
),命令之间以分号;
分隔,跨行可用反斜杠\
。 - 除非你的服务类型是
forking
,否则在这里输入的命令都会被认为是主进程
,不管它是不是。 几种写法
- 基本形式:
ExecStart=/path/to/command arg1 arg2
- 带有多个参数的命令:
ExecStart=/path/to/command --arg1=value --arg2=value2
- 带有环境变量的命令:
ExecStart=/bin/bash -c 'export VAR=value && /path/to/command'
- 带有多个命令的脚本:
ExecStart=/bin/bash -c '/path/to/script.sh && /path/to/another/script.sh'
- 带有管道的命令:
ExecStart=/bin/bash -c 'cat /var/log/syslog | grep ERROR'
- 基本形式:
- 命令后加参数
-d
可以将其转换为守护进程,从而脱离终端并在后台运行。
- 如果你服务的类型不是
ExecStop
- 如果程序自己就有stop(如tomcat),就以绝对路径直接运行
- 如果程序自己没有stop,就通过
/bin/kill -TERM $MAINPID
执行结束命令杀掉进程
(3)其他设置
Restart=always
:服务意外终止时自动重启服务RestartSec=10s
:如果服务意外终止,systemd
将在 10 秒后尝试自动重启服务。User=root
:指定服务运行时所使用的用户身份,限制服务进程对系统资源的访问权限,提高安全性和稳定性。
4、安装服务 [install]
这里说的是一种内部状态,默认你放对位置它显示的是 disabled,unloaded,所以我们要在 Systemd 内部对它进行一下 load,没人要的东西是不需要安装的(我们不收渣渣),所以我们要告诉 Systemd 它是有人要的,被multi-user.target
多用户系统需要,所以写WantedBy=multi-user.target
。
二、举个栗子:name.service
命名为 name.service
[Unit]
Description=服务描述
After=network.target
[Service]
Type=forking
PIDFile=/var/run/myservice.pid
ExecStart=/path/to/my/service -D
ExecStop=/bin/kill -TERM $MAINPID
# 或者ExecStop=/bin/kill -s TERM $(cat /var/run/myservice.pid)
Restart=always
RestartSec=10s
User=用户名如root
[Install]
WantedBy=multi-user.target
在 ExecStart 中,我们使用 -D 选项启动服务,将其转换为守护进程,并将 PID 写入 PIDFile 中。
在 ExecStop 中,我们使用 $MAINPID 变量引用服务进程的 PID,发送 SIGTERM 信号以优雅地停止服务。
在 ExecStop 中,我们使用 $MAINPID 变量引用服务进程的 PID,发送 SIGTERM 信号以优雅地停止服务。
**一定要把要运行的脚本权限给足,否则容易运行失败!**
**一定要把要运行的脚本权限给足,否则容易运行失败!**
**一定要把要运行的脚本权限给足,否则容易运行失败!**
三、配置文件放在指定目录
# 两个目录
/etc/systemd/system #供系统管理员和用户使用
/usr/lib/systemd/system #供发行版打包者使用
# 一般用下面那个即可
cp name.service /usr/lib/systemd/system/
四、加载配置文件
systemctl daemon-reload
五、手动开关服务
# 手动启动服务
systemctl start name.service
一定要把要运行的脚本权限给足,否则容易运行失败!
一定要把要运行的脚本权限给足,否则容易运行失败!
一定要把要运行的脚本权限给足,否则容易运行失败!
# 手动关闭服务
systemctl stop name.service
六、设置开机自启动
# 设置开机启动服务
systemctl enable name.service
# 取消开机启动服务
systemctl disable name.service
参考文档:
https://blog.csdn.net/djskl/article/details/46671453
https://chat.openai.com/chat