🏰 沙场点兵:systemd——现代 Linux 的 init 系统
❖ ❖ ❖
故事开头
2010 年,一个名叫 Lennart Poettering 的德国程序员做了一个决定——他要重写 Linux 的 init 系统。
init 是 Linux 启动的第一个进程(PID 1),负责启动其他所有服务。传统的 init 是串行的——启动完 A,再启动 B,再启动 C。启动一台服务器,需要几分钟。
Lennart 想让它并行启动——同时启动 A、B、C,启动时间缩短到几秒钟。
这个新项目叫 systemd。
今天,systemd 已经运行在全球 90% 以上的 Linux 发行版上。它不仅是 init 系统,更是 Linux 的"大管家"。
❖ ❖ ❖
一、init 的困境
1.1 传统的 init
在 systemd 之前,Linux 使用传统的 init 系统(SysV init)。
它的工作方式很简单:
- 内核启动 init 进程(PID 1)
- init 读取
/etc/inittab 文件 - 按顺序执行启动脚本(
/etc/init.d/ 目录下的脚本) - 启动完成,进入登录界面
问题是什么?
串行启动。 脚本 A 执行完,才执行脚本 B。即使 A 和 B 没有依赖关系,也必须等 A 完成。
一台服务器启动需要 2-3 分钟——大部分时间花在等待磁盘 I/O 和网络初始化上。
1.2 启动脚本的混乱
传统的启动脚本是 shell 脚本。每个服务的启动逻辑都不一样:
- 有的脚本检查依赖
- 有的脚本不检查
- 有的脚本启动失败后不报错
- 有的脚本启动成功后不记录
比喻:
- 传统 init 是"手工生产线"——每个工人按顺序干活
- 服务启动是"盲人摸象"——不知道哪个服务先启动
❖ ❖ ❖
二、systemd 的诞生
2.1 并行启动
systemd 的核心创新:并行启动。
它不按顺序执行脚本,而是分析服务之间的依赖关系,同时启动没有依赖的服务。
传统 init:A → B → C → D → E(串行,3 分钟)
systemd: A ─┐
B ─┼→ D → E(并行 + 依赖,30 秒)
C ─┘
比喻:
- 传统 init 是"排队买票"——一个人买完,下一个人才能买
- systemd 是"开多个窗口"——同时服务多个人
2.2 声明式配置
systemd 使用声明式配置。
每个服务有一个 .service 文件,描述:
[Unit]
Description=My Web Server
After=network.target
Requires=postgresql.service
[Service]
Type=simple
ExecStart=/usr/bin/my-web-server
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
比喻:
- 传统 init 是"命令式"——"先启动 A,再启动 B"
- systemd 是"声明式"——"我想要 A 和 B 都运行,A 依赖 B"
2.3 统一的管理
systemd 统一管理所有服务。
不再需要手写 shell 脚本。systemd 提供统一的命令:
# 启动服务
systemctl start nginx
# 停止服务
systemctl stop nginx
# 重启服务
systemctl restart nginx
# 查看服务状态
systemctl status nginx
# 设置开机启动
systemctl enable nginx
# 查看服务日志
journalctl -u nginx
❖ ❖ ❖
三、systemd 的核心概念
3.1 Unit
Unit 是 systemd 的基本单位。
systemd 管理各种类型的 Unit:
| 类型 | 后缀 | 说明 |
| Service | .service | 服务(最常见) |
| Socket | .socket | Socket 激活 |
| Target | .target | 运行级别(类似) |
| Timer | .timer | 定时器(替代 cron) |
| Mount | .mount | 挂载点 |
| Path | .path | 路径监控 |
比喻:
- Unit 是"任务"——systemd 管理各种任务
3.2 Target
Target 是 systemd 的"运行级别"。
传统的运行级别(runlevel)太简单了——只有 0-6 七个级别。systemd 的 Target 更灵活:
| Target | 说明 |
| multi-user.target | 多用户模式(无图形界面) |
| graphical.target | 图形界面模式 |
| network.target | 网络就绪 |
| local-fs.target | 本地文件系统挂载完成 |
比喻:
- Target 是"里程碑"——到达某个里程碑,表示某些服务已经启动
3.3 依赖管理
systemd 自动管理服务之间的依赖。
[Unit]
Description=My Web Server
After=network.target postgresql.service
Requires=postgresql.service
Wants=redis.service
After=network.target — 在网络就绪后启动Requires=postgresql.service — 强依赖 PostgreSQL,PostgreSQL 挂了,这个服务也停Wants=redis.service — 弱依赖 Redis,Redis 挂了,这个服务继续运行
比喻:
Requires 是"必须"——没有 PostgreSQL,Web 服务器无法运行Wants 是"最好有"——有 Redis 更好,没有也能运行
❖ ❖ ❖
四、systemd 的高级功能
4.1 Socket 激活
Socket 激活(Socket Activation)是 systemd 的杀手级功能。
传统方式:服务启动时,打开 Socket,监听端口。即使没有请求,服务也在运行,占用内存。
Socket 激活:systemd 先打开 Socket,监听端口。有请求时,才启动服务,把 Socket 文件描述符传给服务。
# nginx.socket
[Socket]
ListenStream=80
# nginx.service
[Service]
ExecStart=/usr/bin/nginx
好处:
- 服务按需启动——没有请求,不占用资源
- 启动更快——不需要等服务启动,Socket 已经就绪
- 请求不丢失——systemd 帮服务排队
比喻:
- 传统方式是"餐厅提前开门"——没客人也要开门
- Socket 激活是"按需开门"——有客人了才开门
4.2 Timer
Timer 替代 cron,提供更精细的定时任务管理。
# backup.timer
[Unit]
Description=Daily Backup Timer
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
# backup.service
[Unit]
Description=Daily Backup Service
[Service]
ExecStart=/usr/local/bin/backup.sh
优势:
- 支持日历事件(daily、weekly、monthly)
- 支持相对时间(OnBootSec、OnUnitActiveSec)
- 支持
Persistent=true——错过执行时间,下次启动时补执行
比喻:
- cron 是"闹钟"——到时间响
- Timer 是"智能闹钟"——错过了会补
4.3 日志管理
systemd 有自己的日志系统:journald。
# 查看所有日志
journalctl
# 查看特定服务的日志
journalctl -u nginx
# 查看今天的日志
journalctl --since today
# 实时查看日志
journalctl -f -u nginx
# 查看内核日志
journalctl -k
优势:
- 结构化日志——按服务、时间、优先级过滤
- 自动轮转——不需要手动配置 logrotate
- 二进制格式——更高效
❖ ❖ ❖
五、systemd 与容器
5.1 容器中的 PID 1
在容器中,PID 1 是什么?
传统容器: PID 1 是应用进程(如 nginx)。
问题:
- 应用进程不是 init 系统,不会回收僵尸进程
- 应用进程不会处理信号(如 SIGTERM)
最佳实践: 容器中使用轻量级 init 系统(如 tini、dumb-init)。
# 使用 tini 作为 PID 1
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["nginx", "-g", "daemon off;"]
5.2 systemd 在容器中的角色
systemd 不适合在容器中运行。
原因:
- systemd 需要访问内核功能(cgroup、namespace)
- 容器通常不运行完整的 systemd
- 容器应该"一个进程一个容器"
但 systemd 在容器编排中有重要角色:
- K8s 的节点通常是运行 systemd 的 Linux 发行版
- systemd 管理容器运行时(如 containerd、kubelet)
- systemd 的 Socket 激活可以用于容器服务发现
❖ ❖ ❖
六、systemd 的争议
6.1 为什么有争议?
systemd 是 Linux 历史上最有争议的项目之一。
批评意见:
- 功能膨胀 — systemd 不仅做 init,还做日志、定时、网络、登录管理……它变成了一个"操作系统"。
- 不兼容 Unix 哲学 — Unix 哲学是"做好一件事",systemd 做太多事。
- 闭源组件 — 某些 systemd 组件依赖闭源库。
- 强制升级 — 某些发行版强制使用 systemd,不提供选择。
6.2 支持者的观点
支持者认为:
- 解决了实际问题 — 并行启动、依赖管理、Socket 激活,都是真实需求。
- 统一标准 — 以前每种发行版有自己的 init 系统,现在统一了。
- 现代特性 — 日志、定时器、资源限制,都是现代操作系统需要的。
6.3 替代方案
如果你不喜欢 systemd,还有替代方案:
- OpenRC — Gentoo、Alpine Linux 使用
- runit — 轻量级,适合容器
- s6 — 另一个轻量级 init
- sysvinit — 传统 init,已废弃
但现实是:systemd 已经赢了。 绝大多数 Linux 发行版(Ubuntu、Debian、CentOS、Fedora、RHEL、SUSE)都使用 systemd。
❖ ❖ ❖
总结
systemd 是现代 Linux 的 init 系统。
- 并行启动 — 缩短启动时间
- 声明式配置 — 描述服务怎么启动
- 依赖管理 — 自动处理服务依赖
- Socket 激活 — 按需启动服务
- 日志管理 — journald 统一管理日志
常用命令:
systemctl start/stop/restart/status
systemctl enable/disable
journalctl -u
比喻:
- systemd 是"大管家"——管理所有服务
- Unit 是"任务"——各种类型的任务
- Target 是"里程碑"——到达某个阶段
理解 systemd,就理解了 Linux 服务管理的现代方式——没有 systemd,就没有现代 Linux 服务器。
下篇预告:
systemd 解决了"服务管理"的问题。有了这些基础,我们就能更好地理解六侠演武场的架构了。明天我们再次移步工地去看看。
—— 第八章 · 完 ——
⚙️🔧📋
systemd:现代 Linux 的 init 系统
敬请期待:Docker 的诞生
🐼 Po & 🦐 OpenClaw
2026 年 6 月 7 日 于狮城云端