init、service、systemd、systemctl
Linux 服务管理方式有三种:init
、service
、systemctl
。
init
https://zh.wikipedia.org/wiki/Init
历史上,Linux 的启动一直采用 init 进程。
在类Unix 的计算机操作系统中,Init(初始化的简称)是在启动计算机系统期间启动的第一个进程。
Init 是一个守护进程,它将持续运行,直到系统关闭。它是所有其他进程的直接或间接的父进程。
init 的参数全在/etc/init.d
目录下,init.d 目录中存放的是一系列系统服务的管理(启动与停止)脚本。/etc/init.d
是指向 /etc/rc.d/init.d
的软连接。
init.d 初始化脚本称之为System V风格初始化,是System V系统传统之一,后来成为一些Unix系统的共同特性的源头。值得一提的是,在 /etc 目录下可能还包含 rc#.d 目录,这也是System V风格,#为数字0到6,为系统的运行级别runlevel。可见System V风格影响深远。
用 service 命令 可执行 init.d 目录中相应服务的脚本。service 是控制系统服务的实用工具。
1 | sudo /etc/init.d/nginx start |
service
service
命令是 System V init
的一层封装,本质上就是调用 /etc/init.d/服务名
脚本去执行对应的 start/stop/restart
操作。
1 | service nginx start |
为什么这样说?
service
只是一个工具脚本,位于/sbin/service
- 它会去查找
/etc/init.d/
目录中的对应脚本,然后执行 - 所以调用
service nginx start
实际就是执行/etc/init.d/nginx start
用 type
命令验证它:
1 | type service |
对比 systemd:
特性 | System V init | systemd |
---|---|---|
状态追踪 | 手动处理 | 自动 |
启动顺序 | 手动配置 + 数字排序 | 自动依赖图 |
并发启动 | 不支持(一个个启动,不能并发) | ✅ 支持,并且支持按需启动(lazy activation)。 |
日志 | 各服务输出独立 | 统一 journalctl |
配置格式 | 脚本 | .service 文件(ini 风格) |
systemd
相关链接:
https://zh.wikipedia.org/wiki/Systemd
https://wiki.archlinuxcn.org/wiki/Systemd
https://systemd.io/#manual-pages 官方手册,分为两部分:索引页和指令页。索引页列出 systemd 项目中的所有手册页。
索引页:
https://www.freedesktop.org/software/systemd/man/latest/index.html
https://www.jinbuguo.com/systemd/systemd.index.html 中文
指令页:
https://www.freedesktop.org/software/systemd/man/latest/systemd.directives.html
https://www.jinbuguo.com/systemd/systemd.directives.html 中文
systemd 是一个 Linux 系统基础组件的集合,提供了 系统和服务管理器(System and Service Manager)。是 Linux 系统中最新的初始化系统(init),它主要的设计目的是克服 System V init
固有的缺点,提高系统的启动速度。根据 Linux 惯例,字母 d 是守护进程(daemon)的缩写。 Systemd 这个名字的含义,就是它要守护整个系统。
执行 ps -ef
发现,PID 等于 1 的进程是 systemd。也就是说,systemd 已经取代了 init 成为系统的第一个进程,其他进程都是它的子进程。
查看 Systemd 版本信息的方式之一:systemctl --version
systemd.unit
本手册列出了所有单元类型通用的配置选项。这些选项需要在单元文件的 [Unit] 或 [Install] 部分进行配置。除了通用 [Unit] 和 [Install] 部分外,每个单元可能还有特定于类型的部分,例如服务单元的 [Service] 部分。
Unit 文件是 systemd 用于描述“单元”的配置文件,是 systemd 管理 Unit 的“说明书”,告诉 systemd 该服务如何启动、何时启动、依赖谁、崩溃后怎么办 ……。
Unit 文件的常见类型后缀:service, socket, device, mount, automount, swap, target, path, timer, slice, scope。
unit 文件存放路径(优先级从高到低):
/etc/systemd/system/
:Local configuration。用户自定义 unit 文件的习惯位置。该目录有很多*.target.wants/
子目录,它们决定哪些服务随 target 自启动,其中都是指向其他 unit 文件的符号链接。[!IMPORTANT]
systemctl enable nginx
做了以下几件事:1、按 unit 文件存放路径的优先级(从高到低)查找 unit 文件。
2、根据
[Install]
段中的WantedBy=
或RequiredBy=
字段,决定符号连接创建在哪个.target.wants/
子目录下。比如:1
2[Install]
WantedBy=multi-user.target会创建:
1
2
3Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.
或
Created symlink from /etc/systemd/system/multi-user.target.wants/mysqld@3306.service to /etc/systemd/system/mysqld@.service.3、下次启动
multi-user.target
时,就会自动启动该 unit。提示:任何 unit 类型,只要它的
[Install]
段中有WantedBy
或RequiredBy
,就可以被enable
,就可以实现开机/触发自启。/run/systemd/system/
:Runtime units。程序运行时动态生成 unit 文件的位置(临时)。很少触碰,除非需要修改程序运行时的一些参数。/usr/lib/systemd/system/
和/lib/systemd/system/
:Units of installed packages。安装软件包时默认生成 unit 文件的位置。专门供软件发行者使用。/lib/systemd/
通常是指向/usr/lib/systemd/
的符号链接。/etc/systemd/user/
、/usr/lib/systemd/user/
:用户级 unit。
systemd.exec
本手册列出了 service, socket, mount, swap 单元所共有的 、 用于定义进程执行环境的配置选项(亦称”配置指令”或”单元属性”)。
此外,通过 cgroup 控制资源占用的选项位于 systemd.resource-control(5). 手册中。它们是对本文所列选项的补充。
systemd.service
Type=
配置服务通知管理器服务启动完成的机制。可选值包括:simple
(默认)、exec
、forking
、oneshot
、dbus
、notify
、notify-reload
、idle
。
simple(默认)
如果设置为 simple
(这是默认值——当指定了 ExecStart=
,但没有设置 Type=
或 BusName=
,且未使用凭据时),那么服务管理器会在主服务进程刚刚通过 fork()
被创建出来时,就立即认为该服务已启动完成。也就是说,它不会等到该进程完成各种属性配置,甚至不会等到它调用 execve()
来真正执行服务程序。这种方式启动非常快,但有一定风险。
通常,更推荐使用 Type=exec
,详见下文说明。
在 simple
模式下,ExecStart=
所指定的进程应当是服务的主进程。如果这个服务需要对系统中的其他进程提供功能,那么它的通信接口(例如 socket)应当在服务启动前就准备好,比如通过 systemd 的 socket 激活机制预先创建好。因为 systemd 会在服务主进程刚创建完(但服务程序还未真正开始运行)时,就立刻开始启动后续依赖的服务单元。
需要特别注意的是:这意味着即便服务的程序实际上无法成功执行(例如指定的 User=
用户不存在,或服务的可执行文件缺失),systemctl start
命令仍然会报告“启动成功”。
exec
exec
类型与 simple
类型类似,但服务管理器会在主服务程序被成功执行(即 execve()
调用成功)之后,才将该服务单元视为“已启动”。在此之前,服务管理器会延迟启动后续的服务单元。
换句话说:
- 使用
simple
类型时,systemd 会在服务进程调用fork()
返回之后立即继续处理其他任务,不管实际的服务程序是否成功运行; - 而使用
exec
类型时,systemd 会等到服务进程完成fork()
和execve()
,即真正开始执行服务的主程序之后,才继续后续操作。
这也意味着,对于 exec
类型的服务,如果服务的主程序无法成功执行(例如指定的 User=
用户不存在,或者服务的可执行文件丢失),systemctl start
命令会报告启动失败,而不是像 simple
那样误报成功。
另外,当使用 凭据(credentials) 时(参见 LoadCredential=
,详见 systemd.exec(5)
手册),将隐式采用 Type=exec
类型。
使用场景:见 Consul 开机自启 、filebrowser 开机自启 。
forking
如果将类型设置为 forking
,管理器会在由管理器派生出的子进程(fork 出的二进制)退出后立刻将该单元视为已启动。此类型的使用并不推荐,建议改用 notify
、notify-reload
或 dbus
。
通常情况下,配置在 ExecStart=
的进程应在启动过程中调用 fork()
。父进程在完成启动并建立所有通信通道后会退出,而子进程则继续作为主要服务进程运行,当父进程退出时服务管理器便会将该单元视为已启动。这与传统 UNIX 服务的行为相同。如果使用此设置,建议同时指定 PIDFile=
选项,以便 systemd 能够可靠地识别服务的主进程。当父进程退出后,管理器会继续启动后续单元。
oneshot
Type=oneshot
的行为类似于 simple
,但区别在于服务管理器会在主进程退出之后才认为该单元已启动完成,随后才会启动后续的依赖单元。对于此类型的服务,RemainAfterExit=
选项尤其有用。如果既未指定 Type=
,又未指定 ExecStart=
,则默认会推断为 Type=oneshot
。
请注意,如果在未设置 RemainAfterExit=
的情况下使用此类型,则该服务单元将永远不会进入 “active(激活)” 状态,而是会直接从 “activating(激活中)” 状态过渡到 “deactivating(去激活)” 或 “dead(停止)” 状态,因为 systemd 并未配置一个需要持续运行的进程来维持活跃状态,特别是,这意味着该类型的服务在运行完成后(且未设置 RemainAfterExit=
的情况下)将不会显示为已启动,而是显示为 dead(停止)状态。
dbus
Type=dbus
的行为类似于 simple
,但此类型的单元必须指定 BusName=
,服务管理器会在指定的总线名称被获取后才认为该单元已启动。如果指定了 BusName=
,则默认类型即为 dbus
。
配置了此选项的服务单元会隐式地依赖于 dbus.socket
单元。此类型的服务单元在指定总线名称尚未获取时被视为处于激活中(activating)状态,而在总线名称被占用期间则被视为已激活(activated)。一旦总线名称被释放,服务将被视为不再可用,这会导致服务管理器尝试终止该服务所属的任何残留进程。因此,将释放总线名称作为关机逻辑的一部分的服务应当准备好接收 SIGTERM
(或 KillSignal=
中配置的信号)。
notify
Type=notify
的行为类似于 exec
,但要求服务在完成启动后通过 sd_notify(3)
或等效调用发送 "READY=1"
通知消息。systemd 会在收到此通知消息之后才继续启动后续依赖单元。如果使用此类型,应当设置 NotifyAccess=
,以开放 systemd 提供的通知套接字的访问权限;
如果未设置 NotifyAccess=
或将其设置为 none
,则会强制设置为 main
。
如果服务支持重新加载,并且使用信号触发重新加载,则建议使用 notify-reload
类型。
notify-reload
Type=notify-reload
的行为类似于 notify
,但有一个区别:当服务被要求重新加载时,会向服务的主进程发送 SIGHUP
UNIX 信号,并且服务管理器会等待关于重新加载完成的通知。
在启动重新加载过程时,服务应当通过 sd_notify(3)
发送一条通知消息,其中包含 "RELOADING=1"
字段,并且 "MONOTONIC_USEC="
设置为当前单调时间(即 clock_gettime(2)
的 CLOCK_MONOTONIC
)的微秒数,并以十进制字符串格式表示。一旦重新加载完成,必须发送另一条通知消息,其中包含 "READY=1"
。使用这种服务类型并实现该重新加载协议,是提供 ExecReload=
命令以重新加载服务配置的高效替代方案。
发送的信号可以通过 ReloadSignal=
进行调整。
idle
Type=idle
的行为与 simple
非常相似,但服务程序的实际执行会被延迟,直到所有活动的作业都已分发完成。此类型可用于避免 shell 服务的输出与控制台上的状态输出交错。需要注意的是,这种类型仅用于改善控制台输出效果,并不适合作为通用的单元排序工具,而且该类型的效果存在一个 5 秒的超时限制,超时后服务程序仍会被执行。
.service 模板及说明
vim /etc/systemd/system/demo.service
注意:单元文件的注释必须独占一行,可以包含中文
1 | demo.service |
Type=forking
Type=forking
:systemd 会等待程序 fork(复制、克隆) 子进程并根据 PIDFile
来追踪主进程。PIDFile
是由服务程序本身生成的,systemd 只是读取它来追踪主进程。在使用 Type=forking
时必须正确配置,否则 systemd 无法管理服务状态。
见 Nginx开机自启 。
Nginx 默认以守护进程模式启动(以 daemon 方式后台运行),即启动后会 fork 子进程并退出主进程。这与 Type=exec
不兼容。若强行使用 exec
,Systemd 会误判主进程已退出(因为启动命令执行完,但没有持续运行的前台进程),从而认为服务启动失败。
如果非要改为 Type=exec
,你必须要禁用 nginx 的守护模式:
解决方法:关闭 Nginx 的守护模式,让它以前台方式运行:
1 | [Service] |
systemctl
systemctl
是用来**管理 systemd 单元(unit)**的命令行工具,它可以用来启动、停止服务,设置开机启动,查看服务状态,以及控制系统本身(重启、关机、睡眠等)。
常用命令速查表(精选高频)
操作 | 命令 | 说明 |
---|---|---|
启动服务 | systemctl start nginx |
立即启动服务 |
停止服务 | systemctl stop nginx |
停止服务 |
重启服务 | systemctl restart nginx |
通常用于服务配置变更 |
重载配置 | systemctl reload nginx |
不重启,只重读配置(服务需支持) |
查看状态 | systemctl status nginx |
查看运行状态、日志、PID |
设置开机启动 | systemctl enable nginx |
创建启动链接 |
取消开机启动 | systemctl disable nginx |
删除启动链接 |
查看是否开机启动 | systemctl is-enabled nginx |
输出 enabled 或 disabled |
重新加载 unit 配置 | systemctl daemon-reload |
修改 .service 文件后必需 |
查看已加载的 unit | `systemctl list-units | grep ‘’<br/> systemctl list-units –type=service |
查看所有 unit | `systemctl list-unit-files | grep ‘’<br/> systemctl list-unit-files –type=service |
systemctl 能管理哪些资源?
systemd
把系统中的组件抽象为不同类型的 unit(单元),systemctl
正是用来管理这些 unit 的:
单元类型 | 后缀 | 说明 |
---|---|---|
服务 | .service |
后台程序或服务 |
目标 | .target |
逻辑启动阶段(类似 SysV 的 runlevel) |
套接字 | .socket |
套接字触发的服务 |
定时器 | .timer |
定时任务(替代 cron ) |
挂载点 | .mount |
文件系统挂载控制 |
设备 | .device |
设备事件 |
路径 | .path |
监控某路径触发服务 |
可以指定类型查看:
1 | systemctl list-units --type=timer |
控制系统本身的操作
命令 | 说明 |
---|---|
systemctl reboot |
重启系统 |
systemctl poweroff |
关机 |
systemctl suspend |
挂起 |
systemctl halt |
停止系统(关机但不切断电源) |
systemctl rescue |
进入救援模式 |
systemctl default |
切换到默认 target(正常启动级别) |
journalctl
https://www.runoob.com/linux/linux-comm-journalctl.html
journalctl 是 Linux 系统中用于查询和显示 systemd 日志的强大工具。作为 systemd 生态系统的一部分,它提供了集中化的日志管理功能,替代了传统的 syslog 服务。
核心特点:
- 二进制日志存储:日志存储在以
.journal
结尾的二进制文件,提高检索效率。 - 结构化日志:支持附加元数据和结构化日志字段
- 实时监控:可以实时跟踪日志变化
- 多种过滤方式:支持按时间、服务、优先级等多种条件过滤
1 | journalctl # 查看所有日志 |
总结:
类型 | 路径 | 持久性 | 是否推荐直接查看 |
---|---|---|---|
持久化日志 | /var/log/journal/ |
✅ 是 | ❌ 用 journalctl |
内存中日志 | /run/log/journal/ |
❌ 重启丢失 | ❌ |
文本形式日志 | ❌(默认无) | ❌ | - |