前言
init
历史上,Linux 的启动一直采用 init 进程。在类 Unix 的计算机操作系统中,init(初始化的简称)是在启动计算机系统期间启动的第一个进程。init 是一个守护进程,它将持续运行,直到系统关闭。它是所有其他进程的直接或间接的父进程。因为 init 的参数全在/etc/init.d目录下,所以使用 init 启动一个服务,应该这样做:
sudo /etc/init.d/nginx start
service
service 是一个运行System V init
的脚本命令。那么什么是 System V init 呢?也就是 /etc/init.d 目录下的参数。所以分析可知 service 是去/etc/init.d目录下执行相关程序,服务配置文件的存放目录就是/etc/init.d。
使用 service 启动一个服务
service nginx start
可以理解成 service 就是 init.d 的一种实现方式。
所以这两者启动方式(或者是停止、重启)并没有什么区别。
sudo /etc/init.d/nginx start
// 等价于
service nginx start
但是这两种方式均有如下缺点:
- 启动时间长。init 进程是串行启动,只有前一个进程启动完,才会启动下一个进程。
- 启动脚本复杂。init 进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,这往往使得脚本变得很长。
systemd
systemd 就是为了解决这些问题而诞生的。它的设计目标是,为系统的启动和管理提供一套完整的解决方案。
根据 Linux 惯例,字母d是守护进程(daemon)的缩写。 systemd 这个名字的含义,就是它要守护整个系统。
使用了 systemd,就不需要再用 init 了。systemd 取代了initd,成为系统的第一个进程(pid 等于 1),其他进程都是它的子进程。
systemd 的优点是功能强大,使用方便,缺点是体系庞大,非常复杂。systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。systemctl 是 systemd 的主命令,用于管理系统。
总结
- init 是最初的进程管理方式
- service 是 init 的另一种实现
- systemd 则是一种取代 initd 的解决方案
使用
将程序注册为系统服务,需要编辑 xxx.service 配置文件,并将文件存储到 /usr/lib/systemd/system/ 目录下
配置文件介绍
[Unit] 区块:启动顺序与依赖关系。
- Description:简短描述
- Documentation:文档地址
- Requires:当前 Unit 依赖的其他 Unit,如果它们没有运行,当前 Unit 会启动失败
- Wants:与当前 Unit 配合的其他 Unit,如果它们没有运行,当前 Unit 不会启动失败
- BindsTo:与Requires类似,它指定的 Unit 如果退出,会导致当前 Unit 停止运行
- Before:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之后启动
- After:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之前启动
[Service] 区块:启动行为
- Type:定义启动时的进程行为。它有以下几种值。
- Type=simple:默认值,执行ExecStart指定的命令,启动主进程
- Type=forking:以 fork 方式从父进程创建子进程,创建后父进程会立即退出
- Type=oneshot:一次性进程,Systemd 会等当前服务退出,再继续往下执行
- Type=dbus:当前服务通过D-Bus启动
- Type=notify:当前服务启动完毕,会通知Systemd,再继续往下执行
- Type=idle:若有其他任务执行完毕,当前服务才会运行
- ExecStart:启动当前服务的命令
- ExecStartPre:启动当前服务之前执行的命令
- ExecStartPost:启动当前服务之后执行的命令
- ExecReload:重启当前服务时执行的命令
- ExecStop:停止当前服务时执行的命令
- ExecStopPost:停止当其服务之后执行的命令
- RestartSec:自动重启当前服务间隔的秒数
- Restart:定义何种情况 Systemd 会自动重启当前服务,可能的值包括always(总是重启)、on-success、on-failure、on-abnormal、on-abort、on-watchdog
- TimeoutSec:定义 Systemd 停止当前服务之前等待的秒数
- Environment:指定环境变量
注意:Type=simple 时,如果启动脚本中 以 nohup & 形式启动进程时,此时启动脚本后会自动 kill 当前服务。
[Install] 区块
定义如何安装这个配置文件,即怎样做到开机启动。
- WantedBy字段:表示该服务所在的 Target。
Target的含义是服务组,表示一组服务。默认的启动 Target 就是 multi-user.target(多用户命令行))。在这个组里的所有服务,都将开机启动。这就是为什么 systemctl enable 命令能设置开机启动的原因。
程序准备
这里我们注册的服务名为 test_systemd.service
[Unit]
Description=test program
After=network.target
Wants=network.target
[Service]
Type=simple
ExecStart=/root/test_systemd/test_systemd_start.sh
ExecStop=/bin/kill -9 $MAINPID
ExecReload=/bin/kill -s HUP $MAINPID
[Install]
WantedBy=multi-user.target
服务启动要执行的程序为 test_systemd_start.sh
#!/bin/bash
/root/test_systemd/test_while.sh >> /dev/null
test_while.sh 程序内容为
#!/bin/bash
i=1
while [ $i -le 10000 ];do
let i=$i+1
sleep 10
echo `date` >> /root/test_systemd/while_sh.log
done
总结如下
- 我们要注册的服务,启动要做的操作为:开启一个进程,每隔10秒,向 while_sh.log 日志文件追加一条日志记录
- 停止要做的操作为:将上面的进程给 kill 掉
验证
chmod a+x test_systemd_start.sh # 添加执行权限
chmod a+x test_while.sh
cp test_systemd.service /usr/lib/systemd/system/ # 将配置文件拷贝到指定目录
systemctl daemon-reload # 重新加载配置文件
systemctl start test_systemd # 等价于 systemctl start test_systemd.service
tail -f /root/test_systemd/while_sh.log
常用命令为
systemctl status xxx # 查看服务状态
systemctl start xxx # 启动服务
systemctl stop xxx # 停止服务
systemctl restart xxx # 重启服务
systemctl enable xxx # 启用服务开机自启动
systemctl disable xxx # 禁止服务开机自启动
如果启动失败,可以通过以下命令排查
systemctl status xxx
journalctl -xe
参考
Systemd 入门教程:命令篇
Systemd 入门教程:实战篇
Linux init、service、systemctl 三者区别
Linux:注册系统服务