背景:今天跟大家一起学习一下linux系统服务systemd,这个东西可以用来守护进程,比如可以用来解决你们关心的sillyGirl、node-onebot总是掉线的问题。一步一个脚印,把基础知识学习好,底子打得牢,以后就能如鱼得水的摸鱼了!
- 官方地址:https://systemd.io/
- 项目地址:https://github.com/systemd/systemd
我相信,你可能看不下去官方介绍,我也有点看不下去,我说点大白话好了。
systemd应该就是Linux系统服务的一个系统工具,可以用来守护进程。
它是通过编辑一个 Uint 配置文件,并通过 systemctl 的命令来激活使用。
理论的东西太枯燥,小白看的也云里雾里,所以我们等会儿就结合 sillyGirl 这个实例来学习。
感谢 @Dswang 和 @Ciel 在我学习路上的指导。
我的运行环境是:腾讯云Centos7
解题思路
systemd基础学习?systemd配置文件?systemd实践
systemd基础学习
systemd 是一套用于 Linux 系统的基本构建块。它提供了一个系统和服务管理器,作为 PID 1 运行并启动系统的其余部分。
systemd 提供了积极的并行化能力,使用套接字和 D-Bus 激活来启动服务,提供按需启动守护进程,使用 Linux 控制组跟踪进程,维护挂载和自动挂载点,并实现精细的基于事务依赖的服务控制逻辑。systemd 支持 SysV 和 LSB 初始化脚本,可以替代 sysvinit。
其他部分包括日志守护程序、用于控制基本系统配置(如主机名、日期、区域设置)的实用程序、维护登录用户列表和正在运行的容器和虚拟机、系统帐户、运行时目录和设置,以及用于管理简单网络的守护程序配置、网络时间同步、日志转发和名称解析。
引自官方介绍
systemd的架构图

systemd程序基本信息查询
whereis一下也好判断具体系统的服务文件位置在哪(来自科技玩家@Ciel 教学)。
查看路径是因为等下新建Unit配置文件的时候用得上。
whereis systemd #查看路径
whereis systemctl #查看路径
systemctl --version #查看版本
systemctl --help #查看帮助
ps -p 1 #查看进程,可以看到 systemd 作为 PID 1 运行

这里可以看到,排第一的路径/usr/lib/systemd
,记住它,等下用得上。
Unit
这是Systemd的核心知识点,Systemd管理的每个进程,都是一个Unit
,每一个 Unit
都有一个配置文件,告诉 Systemd 怎么启动这个 Unit 。所以Unit
是标配,配置文件中主要包含了系统服务、监听socket、保存的系统快照等。
Uint配置文件的存放路径:
- /etc/systemd/system:系统或用户自定义的配置文件
- /run/systemd/system:软件运行时生成的配置文件
- /usr/lib/systemd/system:系统或第三方软件安装时添加的配置文件。
- CentOS 7:Unit 文件指向该目录
- ubuntu 16:被移到了 /lib/systemd/system
这三个目录的优先级由上往下依次递减。当三个目录中有同名文件时,优先级最高的目录里的那个文件会被使用。
其实,一般放在/usr/lib/systemd/system
就好了,Systemd 默认从目录/etc/systemd/system/
读取配置文件。但是,里面存放的大部分文件都是符号链接,指向目录/usr/lib/systemd/system/
,真正的配置文件存放在那个目录。
Uint配置文件的类型:
一共有12种类型
- Service unit:系统服务
- Target unit:多个 Unit 构成的一个组
- Device Unit:硬件设备
- Mount Unit:文件系统的挂载点
- Automount Unit:自动挂载点
- Path Unit:文件或路径
- Scope Unit:不是由 Systemd 启动的外部进程
- Slice Unit:进程组
- Socket Unit:进程间通信的 socket
- Swap Unit:swap 文件
- Timer Unit:定时器
- snapshot Unit:表示由 systemctl snapshot 命令创建的 Systemd Units 运行状态快照
配置文件的后缀名,就是该 Unit 的类型,比如 sillyGirl.service
就是系统服务。如果省略,Systemd 默认后缀名为.service
,如
会被理解成sillyGirl
。sillyGirl
.service
Uint相关命令
systemctl list-units
查看当前系统的所有 Unit 。
systemctl list-units #列出正在运行的Unit
systemctl list-units --all #列出所有Unit,包括缺失配置文件或启动失败的
systemctl list-units --all --state=inactive #列出所有没有运行的Unit
systemctl list-units --failed #列出所有加载失败的Unit
systemctl list-units --type=service #列出所有正在运行的类型为service的Unit
systemctl status
查看系统状态和单个 Unit 的状态。
sysystemctl status sillyGirl.service #显示单个Unit状态
systemctl is-active sillyGirl.service #显示某个Unit是否正在运行
systemctl is-enabled sillyGirl.service #显示某个Unit是否开机自启
除了status
命令,systemctl
还提供了三个查询状态的简单方法,主要供脚本内部的判断语句使用。
systemctl is-active sillyGirl.service #显示某个 Unit 是否正在运行
systemctl is-failed sillyGirl.service #显示某个 Unit 是否处于启动失败状态
systemctl is-enabled sillyGirl.service #显示某个 Unit 服务是否建立了启动链接
systemctl list-dependencies
列出一个 Unit 的所有依赖。
Unit 之间存在依赖关系:A 依赖于 B,就意味着 Systemd 在启动 A 的时候,同时会去启动 B。
systemctl list-dependencies nginx.service
systemctl list-dependencies --all nginx.service #有些依赖是 Target 类型,默认不会展开显示。如果要展开 Target,就需要使用--all参数。
常用命令:用于启动和停止 Unit(主要是 service)。
systemctl start sillyGirl.service #启动一个服务
systemctl stop sillyGirl.service #停止一个服务
systemctl kill sillyGirl.service #如果服务无法正常停止则使用kill方式终止
systemctl restart sillyGirl.service #重启指定服务
systemctl reload sillyGirl.service #重新加载指定服务的配置
systemctl daemon-reload #重新加载所有被修改过的服务配置,否则配置不会生效
Uint配置文件
咱们就以sillyGirl为?来介绍吧。给傻妞发送“守护傻妞”,在 /usr/lib/systemd/system 目录下就会生成一个 sillyGirl.service
的文件,通过 vi
/usr/lib/systemd/system
/sillyGirl.service
命令来查看一下。
[Unit]
Description=silly silly girl bot
After=network.target mysql.service mariadb.service mysqld.service
[Service]
Type=forking
ExecStart=/root/sillyGirl/sillyGirl -d
PIDFile=/var/run/sillyGirl.pid
Restart=always
User=root
Group=root
[Install]
WantedBy=multi-user.target
Alias=sillyGirl.service
可以看出来,配置文件一共3个部分 [Unit]、[Service]、[Install],下面分别来说一下。
[Unit]区块
通常是第一个区块,定义Unit元数据信息以及与其他服务的依赖关系
- Description:服务描述信息
Documentation:服务文档地址 - Before:如果该字段指定了其它Unit则代表该Unit需要在其它Unit启动之前启动,但是没有严格的依赖关系
After:如果该字段有指定了其它Unit则代表该Unit需要在其它Unit启动之后才能启动,但是没有严格的依赖关系
Wants:与当前Unit配合的其他Unit,如果需要配合的Unit没有运行,当前Unit也能正常启动 - Requires:为当前Unit指定一个强依赖关系,如果该配置项所指定的Unit没有运行,则当前Unit无法启动。
BindsTo:与Requires类似,如果指定的Unit发生退出,则当前Unit也会停止运行
Conflicts:指定冲突Unit,这里指定的Unit不能与当前Unit同时运行
Condition:当前Unit运行必须满足的条件,否则不会运行
关于Requires、After、Conflicts依赖的说明:
如果没有配置DefaultDependencies=no,那么该Unit会自动隐式添加Requires=sysinit.target, After=sysinit.target,After=basic.target, Conflicts=shutdown.target, Before=shutdown.target的依赖关系。这样是为了保证普通Unit在系统启动完毕之后才能启动、在关闭系统之前先被停止,只有需要在系统启动早期就必须启动的服务以及那些必须在关机动作的结尾才能停止的服务才需要设置DefaultDependencies=no。
[Service]区块
如果Unit类型为Service,则通过该区域进行详细配置,如服务启动脚本、环境变量、配置文件名、重启方式等
- Type=simple:默认值,直接执行ExecStart选项所指定的命令
Type=forking:多数服务会在启动后放入后台,systemd通过Type=forking来支持这种工作方式。如果启用该项,建议同时设置PIDFile选项,这样可以帮助systemd更准确的定位到服务进程 - Type=notify:确保服务启动后发送一个通知消息给systemd,systemd会在启动后面的服务之前确保该进程已经成功的发送了这个消息
Type=idle:若同时有其他任务在执行,需要等那些任务完成后才对当前服务进行处理 - PIDFile:配置Unit的PID文件路径,systemd将会在服务启动后从该文件中读取进程PID。建议Type=forking时明确配置该选项。如果设为相对路径表示相对于/run/目录。
ExecStart:启动某个服务的具体命令,如果有变量的话则来自Environment所指定的配置文件,在所有的启动命令(Exec开头的命令)设置之前都可以加上一个连词号(-),表示抑制错误,即发生错误的时候不影响其他命令的执行。比如EnvironmentFile=-/etc/sysconfig/sshd表示即使/etc/sysconfig/sshd文件不存在,也不会抛出错误。
ExecStartPre:启动某个服务之前执行的命令
ExecStartPost:启动某个服务之后执行的命令
ExecReload:重启服务时执行的命令,Unit需要重新载入配置时所执行的命令行,可通过kill命令结合一个环境变量$MAINPID来完成,如/bin/kill -HUP $MAINPID。如果服务有特定的重启命令,建议不要使用kill的方式
ExecStop:停止服务时执行的命令,如果没有指定的话则会按照kill的方式终止
ExecStopPost:服务停止之后需要执行的命令
RestartSec:自动重启当前服务间隔的秒数,如RestartSec=20s代表systemd自动重启之前需要等20秒。
Restart:定义Systemd自动重启当前服务的场景,比如always(除了使用命令systemctl stop停止服务,其他情况下都进行重启)、on-success、on-failure(发生意外退出就重启。如果是systemctl stop这种正常停止则不会重启)、on-abnormal、on-abort、on-watchdog - RestartPreventExitStatus:指定Unit在什么情况下的退出不需要自动重启,该参数的值支持exit状态码以及信号名2种写法,多个状态以空格分隔
- TimeoutSec:定义Systemd停止当前服务时需要等待的秒数
Environment:指定Unit所需的环境变量,如Environment="ONE=one",ExecStart=echo $ONE - EnvironmentFile:指定Unit所需的环境变量配置文件,如ssh需要/etc/sysconfig/sshd
[Install]区块
通常是配置文件最后一个区块,定义服务如何启动以及是否开机启动
- WantedBy:指定一个或多个Target(Target就是Unit组,启动某个Target的时候会启动里面所有的Unit,它的作用有点类似init的runlevel),如WantedBy=multi-user.target代表服务所在的 Target是multi-user.target(多用户命令行状态专用Target,也是systemd默认Target)。这个设置比较重要,因为对某个Unit执行enable时,该Unit的软链接就会存放于/etc/systemd/system/multi-user.target.wants目录中(以Target名+.wants后缀构成)
- RequiredBy:指定一个或多个Target,当Unit状态为enable时,服务的软连接文件会创建到/etc/systemd/system目录下面并以Target 名+.required后缀构成的子目录中
Alias:Unit别名
Also:当Unit设置为enable时,会被同时enable的其他Unit
了解了各个板块一些配置选项之后,就可以自己编写配置文件了。
当然最简单的办法就是在已有的一些配置文件上修改。
说了这么多,我相信你已经晕菜了,没事,下面我们继续通过sillyGirl这个实例来温故而知新。
systemctl实践
其实,sillyGirl的“守护傻妞”,systemd方法来守护进程的,只不过作者把这个过程进行了傻瓜化,方便用户使用。
我们可以直接自己建立 sillyGirl.service 系统服务文件,并通过命令激活启动它。马上进入实战学习!
新建配置文件
vim /usr/lib/systemd/system/sillyGirl.service
按键盘字母 i 进入编辑模式,复制下面?的内容,然后按键盘 esc 退出编辑模式,再输入命令 :wq
保存并退出。
[Unit]
Description=silly silly girl bot
After=network.target mysql.service mariadb.service mysqld.service
[Service]
Type=forking
ExecStart=/root/sillyGirl/sillyGirl -d
PIDFile=/var/run/sillyGirl.pid
Restart=always
User=root
Group=root
[Install]
WantedBy=multi-user.target
Alias=sillyGirl.service
然后分别输入下面的命令激活
systemctl daemon-reload #重新加载所有被修改过的服务配置,否则配置不会生效
systemctl enable sillyGirl.service #设置为开机自启
systemctl start sillyGirl.service #启动服务
# 其他常用的管理命令
systemctl restart sillyGirl.service #重启服务
systemctl stop sillyGirl.service #停止服务
下面我们来感受一下系统级进程守护的威力

ps -A|grep sillyGirl #查看傻妞进程,返回的第一个数字就是pid进程号
kill -9 pid进程号 #杀死傻妞进程
ps -A|grep sillyGirl #再次查看一下傻妞进程是否被杀死

从此你的 傻妞 就被你捧在手心里了,再也不会掉了!!!
你们的 node-onebot 也可以通过同样的方法来守护,快去练习一下吧!
参考学习资料
【1】https://juejin.cn/post/7059400745665167397
【2】https://www.linuxe.cn/post-371.html
【3】https://cloud.tencent.com/developer/article/1516125
【4】https://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html
【5】https://www.freedesktop.org/wiki/Software/systemd/
先收藏
学习学习
学习了
谢谢分享,学习了
太牛了 学习学习
学习学习
学到了,谢谢楼主
学习学习
谢谢大佬分享,谢谢!
谢谢,分享学习了
谢谢分享,学习了
插眼评论涨分
谢谢分享,学习了
谢谢大佬分享,谢谢!
感谢分享
真棒,感谢分享!
七年前来顶贴!
先看看,不明白的地方再问
mark一下。