一、Systemd简介

Systemd 是 Linux 系统工具,用来启动守护进程,已成为大多数发行版的标准配置。Linux系统启动流程是由通电-BIOS-主引导记录-操作系统组成,开发者和程序员能够任性修改的天地基本都在操作系统各部分,其他部分已经被写死无法修改。操作系统的启动过程首先会加载内核文件,在读入成功后会启动init程序,它的作用是初始化系统环境。之后系统依据设定好的运行级别,即本次系统运行所扮演的角色,例如服务器、桌面模式、单用户模式、多用户模式、重启等等,运行级别一般是开机/默认指定好的,读取/etc目录下的配置文件可获得本次系统运行级别,/etc下配置文件还包含每一级运行级别所需要启动的进程名单,init初始化程序会以串行的脚本启动方法依次启动列表中的程序,至此系统初始化完成,用户可以对系统进行正常操作。
但事实上,init的系统初始化方法有两个重要的缺陷, 一是启动时间长。init进程是串行启动,只有前一个进程启动完,才会启动下一个进程。二是启动脚本复杂。init进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,这往往使得脚本变得很长。

Systemd 就是为了解决这些问题而诞生的。它的设计目标是,为系统的启动和管理提供一套完整的解决方案。根据 Linux 惯例,字母d是守护进程(daemon)的缩写。 Systemd 这个名字的含义,就是它要守护整个系统。使用了 Systemd,就不需要再用init了。Systemd 取代了initd,成为系统的第一个进程(PID 等于 1),其他进程都是它的子进程。
更多的介绍详见**这里**

综上所述,对于项目开发者,Systemd使得开发者可以安全的自定义项目系统启动的顺序,同时Systemd提供了完善的日志记录查找、服务状态查看维护等配套工具,大大方便了开发者对于系统自启动服务的掌控力。

二、设置步骤

1. 书写service文件

AlarmManagement.service(示例):

[Unit]
Description=AlarmManagement
Before=alarmstorage.service
After=gateway.service

[Service]
User=map
Type=forking
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/java/jdk-11.0.1/bin" ""
ExecStart=/usr/local/java/jdk/bin/java -jar /opt/map/module/alarmmanagement/AlarmManagement.jar
Restart=no
TimeoutSec=180

[Install]
WantedBy=multi-user.target

正如示例所展示,任一service文件均有Unit、Service、Install三部分组成,使用者需要依据systemd.unit文档中所提供的选项进行文件配置,下面只介绍一些常用选项

单元文件中的 [Unit] 小节 包含与单元类型无关的通用信息
	Description= :有利于人类阅读的、对单元进行简单描述的字符串,将被 systemd 或其他程序用来标记此单元
	Before= , After= :强制指定单元之间的启动先后顺序,接受一个空格分隔的单元列表
	
单元文件中的 [Service] 小节 含有所有单元启动过程中的配置功能选项
	Type= :设置进程的启动类型。必须设为 simple(默认值), exec, forking, oneshot, dbus, notify, idle 之一
	ExecStart= :启动该服务时需要执行的 命令行(命令+参数),除非 Type=oneshot ,否则必须且只能设置一个命令行
	ExecStartPre=, ExecStartPost= :设置在执行 ExecStart= 之前/后执行的命令行。 语法规则与 ExecStart= 完全相同。
	ExecStop= :这是一个可选的指令, 用于设置当该服务被要求停止时所执行的命令行。
	TimeoutSec= :一个同时设置 超时时长 与 最大启动时长的快捷方式。
	Restart= :当服务进程 正常退出、异常退出、被杀死、超时的时候,是否重新启动该服务。该选项的值可以取 no(默认值), on-success, on-failure, on-abnormal, on-watchdog, on-abort, always 之一
	User=, Group= :设置进程在执行时使用的用户与组,默认是用户root
	Environment= :设置进程的环境变量, 接受一个空格分隔的 VAR=VALUE 列表。

单元文件中[Install] 小节包含单元的启用信息。事实上,systemd 在运行时并不使用此小节。只有 systemctl的 enable 与 disable 命令在启用/停用单元时才会使用此小节。故在绝大部分情况下该部分无需自定义设置

关于各个选项的详细解释请看这里:UnitServiceExce

2. Systemd自启动部署流程

1. 将写好的XXX.service文件放入systemd所指定的位置

Systemd启动时会加载一系列的单元目录(总共有10个),这些单元目录依照加载顺序分为优先级。
单元目录描述
/etc/systemd/system.control通过 dbus API 创建的永久系统单元
/run/systemd/system.control通过 dbus API 创建的临时系统单元
/run/systemd/transient动态配置的临时单元(系统与全局用户共用)
/run/systemd/generator.early生成的高优先级单元(系统与全局用户共用)
/etc/systemd/system本地配置的系统单元
/run/systemd/system运行时配置的系统单元
/run/systemd/generator生成的中优先级系统单元
/usr/local/lib/systemd/system本地软件包安装的系统单元
/usr/lib/systemd/system发行版软件包安装的系统单元
/run/systemd/generator.late生成的低优先级系统单元

事实上,在大部分情况简单需求下,使用者只需要将service文件放入/usr/lib/systemd/system才是正确的
网上很多教程所说的是/etc/systemd/system,这个是不符合规范的做法!

2.使用Systemd命令配置service单元使其生效

顺序执行以下命令即可完成自启动设置

  • sudo systemctl daemon-reload (重新加载配置)
  • sudo systemctl enable XXXX.service (将该单元加入开机启动列表)

注:每次修改完.service文件之后需要重新执行systemctl daemon-reload

建议在配置完成之后进行手动service启动测试

  • sudo systemctl start XXXX(启动某service单元)
  • sudo systemctl status XXXX(查看某service单元的运行状态)
  • sudo systemctl stop XXXX(停止某service单元)

总结

事实上,使用systemd进行服务自启动的步骤十分简单,往往难住很多使用者的是对于service文件内容的书写出现错误所造成的,这其中牵扯到诸多细节问题,除去对于各个选项不理解的这一最常见问题外,还包括文件访问权限问题、配置环境问题、service文件重名覆盖问题等等,但幸好使用者可以通过systemd运行日志进行错误排查,后面一篇我将借助我遇到的systemd错误给大家展示如何进行排查。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐