写给linux系统管理员看的systemd 三如何把SysV Init脚本转换成一个systmed的service文件 (systemd作者blog翻译过来的)

本文详细介绍了如何将传统的SysVInit脚本转换为systemd服务文件,包括从提取脚本信息、创建systemd单元配置、调整服务类型到最终测试和激活服务的过程。通过实例解析了如何利用systemd提供的特性提高服务管理和系统启动效率。

原文地址:http://0pointer.de/blog/projects/systemd-for-admins-3.html


如何把SysV Init脚本转换成一个systmed的service文件?

传统方式,Unix和Linux服务(daemons)由SysV的init脚本启动.这些服务写成Bourne Shell脚本,通常驻留在像/etc/rc.d/init.d/这样的目录里,调用时有一个或几个参数,比如start, stop或restart, 用来控制服务的开始,停止和重启. 开始服务包括调用守护程序的代码, 守护程序再fork一个后台进程.Shell脚本很慢,难以阅读,冗长而脆弱. 尽管shell脚本极其灵活(毕竟,脚本本身就是代码)有些事儿很难拿脚本来完成,比如:安排并发执行的顺序,正确的监督进程或只是详尽的配置执行上下文. systmed可以与脚本兼容, 但下面我们马上就会提到,在安装所有守护进程的时候推荐 安装原生的systemd服务文件. SysV 的启动脚本需要根据发行版的不同做出调整,systemd的服务文件则兼容任何发行版中运行的systemd. 接下来是一个简洁的入门手册:如何把SysV的shell脚本转换成一个systemd服务文件。理想情况下,上位的软件应该在tar包里发行和安装systemd的服务文件. 如果你已经根据入门手册成功的把某个上位软件SysV脚本转换成功了,一个不错的做法是把转换成功的文件作为补丁提交给那个上位软件. 后续的文章将会讨论如何准备这样一个补丁, 现在可以告诉你的是systemd的 daemon(7) 用户手册中有与之相关的很多有用信息.

开始吧,作为例子,我们将把ABRT守护进程的init脚本转换成systemd的服务文件。ABRT是每个Fedora安装版的标准组件,它是自动Bug报告工具(Automatic Bug Reporting Tool)的缩写,比如,它提供收据crash dumps服务。它的SysV脚本上传到这里了。

转换脚本的第一步是阅读它的代码并从中提取有用信息。几乎所有的init脚本中都有模板化的代码,通常这些代码就是从另一些脚本中拷贝过来的。下面开始抽取上面链接中脚本的有用信息。

  • 文件中的一个描述句子是“发现崩溃程序的守护进程”。其他很多注释是多余描述,它们不怎么描述服务本身,却描述启动服务的脚本文件。systmd服务也包含描述,描述的应该是服务内容而非服务文件。
  • LSB头[1] 包含服务的依赖关系信息,systemd是基于socket激活进行设计的,通常不需要(或者需要很少量的)手动配置依赖关系。(对socket激活的详细阐述请见这篇博客。本例所依赖的$syslog(表明abrtd需要用到syslog守护进程),只是个变量信息。头部列出的另一依赖关系($local_fs)对systemd来说是冗余项,因为系统服务开始时总是要求本地文件系统可用。
  • LSB头建议服务应该运行在运行级别3(多用户)或5(图形界面)
  • 守护进程的二进制文件是/usr/sbin/abrtd

有用的部分说完了。115行shell脚本的其他部分不是模板化的东西就是冗余代码:用来应付同步和顺序启动(比如,锁文件相关代码),或是输出状态信息(比如调用echo语句的代码),或者进行参数分析(比如case块儿)。

从上述抽取出的信息出发,我们现在可以写我们的systemd服务文件了。

[Unit]
Description=Daemon to detect crashing apps
After=syslog.target

[Service]
ExecStart=/usr/sbin/abrtd
Type=forking

[Install]
WantedBy=multi-user.target

这一文件的简单解释: [Unit] 节包含服务的通用信息. systemd 不止管理系统服务, 而且管理设备, mount 点, 计时器, 和其它系统组件. systemd中这些对象的通用名称是一个unit,[Unit]节中包含的信息不但可能用于服务,也可能用于systemd维护的其它unit类型。本例中我们进行如下的unit设置:设置描述项,并配置守护进程在Syslog后启动[2], 很像原init脚本中的LSB头。针对Syslog依赖关系,我们在systemd的Unit节创建了一个依赖类型After=systlog.target。syslog.target为systmed中专用的目标unit。它是syslog的标准化命名,对标准化命名的更多信息可见systemd.special(7).注意键入After=来创建的依赖关系只是一种建议顺序,它本身没有强制性:当abrtd启动时并不能引起syslog启动--这正是我们想要的,因为abrtd实际上在没有syslog时也能正常工作。但是,如果两者都启动了(通常情况如此),那么这一依赖关系决定了启动顺序。

接下来的一节是[Service]用来配置服务本身的信息。它包含只用于服务本身的设置,而非其它systemd所维护的units(mount点,设备,定时器等)。这里用了两个设置:ExecStart=定位服务启动时二进制文件的路径。Type=配置服务启动完成后如何通知init系统。由于传统的Unix守护进程fork完毕并完成后台守护进程初始化后返回父进程,我们就在这里设置forking类型。这告诉systmed等到启动的二进制文件返回后再考虑守护进程后面仍然运行的进程

最后一节是[Install]. 用于对如何安装给出建议,比如,服务在哪种环境下启动,如何被触发. 本例中服务将在muti-user.target unit激活后启动.muti-user.target是一个专用unit,基本上相当于SysV的运行级3[3].WantedBy= 设置项对运行时的守护进程没啥作用.systemd有个推荐的激活服务的命令,即systmectl enable,它会读取WantedBy=设置项. 此命令保证只要需要multi-user.target,我们制定的这个小服务就能自动启用. 正常的启动都需要multi-user.target[4].

就这些了.现在我们有了个最小的能工作的systmed服务文件.测试下吧, 把它拷贝到/etc/systemd/system/abrtd.service然后执行systemctl daemon-reload. 这会使systmed发现它, 现在我们可以启动它了:systemctl start abrtd.service.  我们能判断它现在是什么状态:systemctl status abrtd.service. 我们能停止它: systemctl stop abrtd.service. 最后,我们能启用它, 以后系统启动时它会自动激活:systemctl enable abrtd.service.

上面的服务文件,  是SysV init 脚本的1:1翻译, 仍有改进空间. 小改动下:

[Unit]
Description=ABRT Automated Bug Reporting Tool
After=syslog.target

[Service]
Type=dbus
BusName=com.redhat.abrt
ExecStart=/usr/sbin/abrtd -d -s

[Install]
WantedBy=multi-user.target


看看我们修改了啥?两件事儿:描述项润色了一下.更重要的是,我们把服务类型改成了dbus,并给它配置了D-Bus总线名.为什么这么干?如前文所述,经典SysV服务启动后变成守护进程, 这一过程包括两次fork并与终端脱离. 当以脚本的方式启动守护进程的时候, 这样做是必要的(也是缓慢的),但在systemd这种要求精心照料其它进程的进程来看,这种做法就适得其反了(毕竟后台化,其全部思想就是移除systmed所需要管理的这种关系),fork完成后,区分哪个进程是服务进程的主进程, 哪个进程只是辅助进程, 对systemd来讲是十分困难的.但这些信息对于精心照料的要求来讲,是至关重要的, 比如监控某一进程,非正常退出时重启进程, 收集崩溃和退出码信息,诸如此类. 为了让systemd容易的区分出守护进程的主进程,我们更改service类型为dbus. 设置这一服务类型差不多就是说服务在初始化的最后一步以D-Bus系统总线命名[5]. 现在ABRT就是dbus类型了.这样设置后systemd将产生ABRT进程, ABRT进程将不再进行fork(配置成-d -s来进入守护进程),当com.redhat.abrt出现在总线上时,systemd就认为服务完全启动起来了.systemd用这种方式产生的进程就是守护进程的主进程, systemd就有了可靠的方法认定什么时候守护进程完全启动了并能容易的监视它.

全部设置就是这些了.我们有了一个10行的systemd服务文件,包含的信息超过了原SysV init脚本的115行代码.现在有更多的空间留给systemd将来提供更多的特性.比如,我们可以设置Restart=restart-always来告诉systemd在服务死掉时自动重启.或者,我们可以用 OOMScoreAdjust=-500来告诉内核当OOM killer(译者:Linux下有一种OOM KILLER 的机制,它会在系统内存耗尽的情况下,启用自己算法有选择性的kill 掉一些进程)施以暴行的时候,别动这个进程.或者,我们可以用CPUSchedulingPolicy=idle来保证abrtd进程只在后台进行crash dumps, 总准许内核去选择其他需要CPU时间的进程运行.

这里提到的配置选项的更多信息, 请见相应手册 systemd.unit(5)systemd.service(5)systemd.exec(5). 或者浏览 all of systemd's man pages.

当然,不是所有的SysV脚本都像这么容易就转换过来,但绝大多数都挺容易的.

就到这里了,下次见!

脚标说明:

[1] init脚本的LSB头是一种惯例:在SysV init脚本的顶部注释块中包含服务的元数据,这一惯例是在Linux Standard Base中规定的。意在规范不同发行版中的init脚本。尽管多数发行版都采用这样惯例,不同发行版对头部的处理千差万别,实际相同功能的脚本在每个发行版中的都需要进行调整。因而LSB规范从未信守诺言。

[2]严格讲,这一依赖关系其实不需要写在这里,它在systemd中是多余的,因为Syslog守护进程是socket可激活的。现代syslog系统(例如rsyslog v5)都已更新为socket可激活的。这样一个init系统用于After=syslog.target 依赖关系配置是多余的和暗含的。为了与那些未更新的syslog服务保持兼容,我们在这里加入这一依赖关系。

[3] 至少在Fedora中是这样

[4] systemd中的图型启动方式(graphical.target, 相当于SysV 中运行级 5)暗含字符节目启动(multi=user.target,比如运行级3).这意味着给后者增加一个服务相当于给前者也增加去了一个

[5]实际上现在的Fedora默认安装绝大多数服务都在启动完成后再以总线命名.


<think>我们被要求回答:如何检查Linux系统使用的是Systemd还是SysV init 根据之前的引用,我们知道: - 传统的SysV init系统使用init进程作为PID 1,配置文件通常在/etc/inittab - Systemd是新的初始化系统,它取代了SysV init,使用systemd作为PID 1,管理单元文件在/usr/lib/systemd/system和/etc/systemd/system 因此,我们可以通过以下方法检查: 方法1:检查PID 1的进程名 执行命令:`ps -p 1 -o comm=` 输出结果可能是: - `systemd` -> 表示使用systemd - `init` 或 `upstart` -> 表示使用SysV init或Upstart(CentOS 6) 方法2:检查相关文件和目录 - 检查是否存在`/usr/lib/systemd`或`/etc/systemd`目录,以及`/usr/bin/systemctl`文件(存在则很可能是systemd) - 检查是否存在`/etc/inittab`文件(但注意:systemd系统也可能保留该文件,但内容不同) 方法3:使用`init`的版本信息 执行命令:`init --version` 或 `systemctl --version` 如果返回systemd的版本信息,则说明是systemd;如果返回的是SysV init的版本信息或错误,则可能是SysV。 方法4:检查运行级别(runlevel)和目标(target) - 在SysV init系统中,可以使用`runlevel`命令查看当前运行级别(如3或5) - 在systemd系统中,运行级别被目标(target)取代,可以使用`systemctl get-default`查看默认目标(如graphical.target) 但是注意:如果系统使用的是Upstart(如Ubuntu 14.04或CentOS 6),则既不是systemd也不是SysV init,而是另一种init系统。不过,Upstart通常也会使用init作为进程名(PID 1),并且会兼容部分SysV init脚本。 因此,最可靠的方法是检查PID 1的进程名。 此外,还可以通过查看发行版版本来辅助判断: - CentOS 7及以上、Ubuntu 15.04及以上、Debian 8及以上默认使用systemd - CentOS 6及以下、Ubuntu 14.04及以下使用SysV init或Upstart 但具体还是要以命令输出为准。 步骤总结: 1. 打开终端 2. 运行 `ps -p 1 -o comm=` 3. 根据输出判断: 输出为 "systemd" -> 使用systemd 输出为 "init" -> 可能是SysV init或Upstart(需要进一步确认) 输出为 "upstart" -> 使用Upstart 如果输出为"init",为了区分是SysV init还是Upstart,可以检查是否有`upstart`进程相关的文件,或者查看`init`的版本信息。 例如,在Ubuntu系统中,可以尝试:`dpkg -s upstart`,如果存在则可能是Upstart。 在CentOS 6中,可以查看`/etc/issue`或`/etc/redhat-release`来确认版本。 但通常,我们只需要知道不是systemd即可,因为管理服务的命令不同。 因此,主要方法就是检查PID 1。 参考引用[3]中提到:systemd取代了SysV init,并且运行级别与目标有所不同[^3]。引用[4]也提到了不同版本的CentOS使用的init程序类型[^4]。 下面我们按照要求给出回答: </think>### 如何检查 Linux 系统使用的是 Systemd 还是 SysV init 以下是快速准确的检查方法,按推荐顺序排列: #### 🔍 1. **检查 PID 1 进程(最可靠)** 执行命令: ```bash ps -p 1 -o comm= ``` 结果解析: - 输出 `systemd` → 使用 **Systemd** - 输出 `init` → 使用 **SysV init** - 输出 `upstart` → 使用 **Upstart**(过渡方案) 原理:系统第一个进程(PID 1)决定初始化系统类型[^3][^4]。 #### 📂 2. **检查关键目录和文件** ```bash ls -ld /usr/lib/systemd /etc/systemd ``` - 存在这些目录 → 使用 **Systemd** - 如不存在,检查旧版标志: ```bash ls /etc/init.d # SysV init 的服务脚本目录 cat /etc/inittab # SysV init 的核心配置文件 ``` #### 📟 3. **检查运行级别管理方式** - **Systemd** 使用目标(target): ```bash systemctl get-default # 查看默认目标 ls /etc/systemd/system/*.target ``` - **SysV init** 使用运行级别(runlevel): ```bash runlevel # 查看当前运行级别 cat /etc/inittab | grep :initdefault: ``` #### ℹ️ 4. **检查系统版本信息(辅助验证)** ```bash cat /etc/os-release ``` 版本关联参考: | 初始化系统 | 典型发行版本 | |------------------|--------------------------| | **Systemd** | CentOS 7+/Ubuntu 15.04+ | | **SysV init** | CentOS 6-/Debian 7- | | **Upstart** | Ubuntu 14.04/CentOS 6 | ### 💡 操作示例 ```bash # 步骤1:确认 PID 1 进程 $ ps -p 1 -o comm= systemd # 确认使用 Systemd # 步骤2:验证服务管理命令 $ systemctl status sshd # Systemd 方式 $ service sshd status # SysV init 方式 ``` ### 关键差异总结 | 特征 | Systemd | SysV init | |--------------------|-----------------------------|----------------------------| | PID 1 进程名 | `systemd` | `init` | | 服务管理命令 | `systemctl start/stop` | `service start/stop` | | 配置文件位置 | `/usr/lib/systemd/system/` | `/etc/init.d/` | | 运行级别管理 | 目标(target) | 数字级别(0-6) | | 日志管理 | `journalctl` | `/var/log/messages` | > 📌 **注意**:混合环境中(如 Docker 容器)可能缺少完整初始化系统,需结合 `ps -p 1` 和文件检查综合判断[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值