⏰ 第01章 · Systemd 基础

unit/target 概念

Systemd 基础

这一章先建立"服务是怎么被这台机器拉起来的"这个整体认知。你在这台 Ubuntu 24.04 服务器上敲 systemctl 时,背后有一套统一的进程管理框架在替你干活——它就是 systemd。学完这章,你会明白:一条 node server.js 为什么能被"开机自启、挂了自动拉起",又是被谁记录下来的。

从 SysV init 到 systemd

Linux 机器开机后,内核做完初始化,会启动第一个用户态进程,它的 PID 恒为 1,叫 init。所有其他进程——包括你的 shell、你的 node 服务——不是它的孩子,就是它的孩子的孩子。这个 PID 1 进程决定了一个系统的启动和管理方式。

传统方案叫 SysV init(RHEL 6、Debian 7 及更早),它的毛病是:

  • 启动任务是串行的,一个起完才起下一个,开机慢;
  • 用一堆 /etc/rc?.d/ 里的脚本管理,难读、难配、难并行;
  • 没有"服务崩溃自动重启"这种能力,得靠外部脚本 (monit、supervisor) 补。

所以 systemd 出现了。它是现代的 init 系统 + 服务管理器,特点归纳成一句话:并行启动、统一配置、自带日志、自带监控。

ps -p 1 -o pid,comm,args   # 看看 PID 1 是谁
#  PID COMMAND  ARGS
#    1 systemd  /sbin/init

提示 检查 PID 1 就能判断系统用的是不是 systemd。systemctl --version 还能看到它的具体版本,这台服务器跑的是 255 系列,Ubuntu 24.04 标配。

systemd 是"由谁在管谁"的架构

Systemd 用编号命名的一套配置段来描述每个后台任务。它管的不只是服务,而是一整类单元。你可以把 systemd 想成一栋楼的物业:

systemd 概念 楼里的角色 生活中对应
unit 文件 每套房的管理登记表 /etc/systemd/system/xxxx.service
服务 (service) 一套常驻的房间 node server.js、nginx
定时器 (timer) 定好钟点来查房 cron 的 systemd 版
target 目标状态 multi-user.target(多用户模式)
journal 每套房的事件记录本 日志,统一由 journald 写

Systemd 的核心是一个叫 systemd(作为 PID 1) 的守护进程,配合 journald(写日志)、systemctl(命令行)、systemd-analyze(诊断启动时间)等工具一起工作。

Unit:一切皆是单元

在 systemd 里,每一种"可被管理的对象"都是一个 unit(单元),用 type.后缀 命名。后缀决定了它是哪种单元:

后缀 含义 典型场景
.service 后台服务进程 node API、nginx、mysql 服务
.target 一组单元的集合/目标状态 multi-user.target
.timer 定时触发某个 unit 替代 cron 的定时任务
.socket 监听端口,激活时才起服务 socket 激活的 Web 服务
.mount / .automount 挂载点 磁盘分区挂载
.path 文件/目录变化时触发 监控某个文件出现
.slice 资源分组 按 CPU/内存分组配额
systemctl list-units --type=service --all   # 列出所有 service 单元
systemctl list-unit-files                    # 列出所有 unit 文件 + 是否开机启用

Target:把"开机要启动什么"聚合成目标

multi-user.target 是这里频繁出现的一个词。它不是一个服务,而是一个目标状态:代表"多用户模式下该有的那堆服务都在跑"。把一个服务的 [Install] WantedBy=multi-user.target 配好,就等于告诉 systemd:"进入多用户模式时把我也带上"。

systemctl list-dependencies multi-user.target   # 看这个 target 会拉起哪些服务

你在这台服务器上会看到 bangdream.service、dsh.service 等,它们的 [Install] WantedBy=multi-user.target,这正是"重启机器后自动恢复服务"的神秘来源——第 4 章细讲。

本服务器上的 systemd 规模

这台机器上不仅跑了业务服务,还跑了一堆系统组件,列出几个有代表性的:

服务 干什么的
bangdream / lovelive 两个 Node 角色数据库 API,监听 3000 段端口
dsh DeepSeek Harness Web 界面
dsh-auth-proxy GitHub OAuth 鉴权代理
xray 代理隧道,以 nobody 低权限跑
rustdesk-hbbs / hbbr 远程桌面中继/ID 服务
prometheus / prometheus-node-exporter 性能监控采集 + 导出器
mysql 数据库

它们有的是 node 写的,有的是打包好的二进制,但都靠同一套 systemd 规则管理——这正是这章的书名"统一管理"的意义。

从哪里查信息:三条只读命令

刚接触 systemd,先掌握三条绝不改状态的查询命令,怎么敲都不会把服务搞坏:

systemctl status bangdream.service   # 单个服务的详细状态
systemctl list-units --type=service  # 当前活动(active)的服务
systemctl list-unit-files            # 所有 unit 文件及其开机状态

status 是最常用的一条,它一次告诉你:是否在跑、PID、内存、CPU、最近日志、以及这段 node server.js 到底是谁在跑。

注意 status、list-units、list-unit-files 都是只读的,随便看。但 start/stop/restart 会真正改动服务状态,一开始别乱敲,先看清楚要动哪个再动。第 2 章专门讲怎么正确地改。

易错点

  • systemctl 不等于 service:service nginx restart 是老式兼容命令,新项目的脚本里优先用 systemctl。
  • 改了 unit 文件必须 daemon-reload:否则 systemd 读的还是内存里的旧配置,你改的字段不生效。这在第 3 章会反复强调。
  • 区分"没启用"和"没运行":disable(开机不启动) 和 stop(现在不跑) 是两个独立概念,别混。
  • root 才能管理服务:普通用户敲 systemctl start xxx 会报 Access denied,要么用 sudo,要么配置 sudoers。

相关命令

systemctl(全家桶)、systemd-analyze(分析启动耗时)、systemd-cgls(看 cgroup 树)、ps -p 1(确认 PID 1)、systemctl --version(看版本)。