1. 课程导论与初始化流程概览:理解 systemd 初始化阶段的重要性,从内核启动到 PID 1 的交接过程

1.1 为什么初始化阶段是故障排查的核心战场?

Linux 系统的启动过程可以划分为两个截然不同的阶段:内核引导与用户空间初始化。内核引导阶段相对固定,故障通常集中在硬件兼容性或驱动加载上;而用户空间初始化阶段——即 systemd 接管后的部分——则涉及数百个服务、依赖关系、资源限制和自定义配置,是生产环境中 70% 以上启动故障 的根源。

理解从内核启动到 PID 1 交接的完整链路,是定位“系统卡在启动”、“服务启动超时”、“依赖循环”等问题的前提。本章将建立这一关键认知框架。

关键认知: 内核启动完成后,控制权移交给用户空间的第一个进程(PID 1)。在 systemd 系统中,这个进程就是 /lib/systemd/systemd。此后的所有服务、挂载点、套接字、定时器都由它管理。初始化阶段的故障,本质上是 PID 1 与其管理的单元之间的交互失败。

1.2 从内核启动到 PID 1 交接:四阶段模型

整个启动流程可以抽象为四个连续阶段。下表总结了每个阶段的核心动作、输出产物以及常见的故障点:

阶段 核心动作 输出/标志 常见故障点
1. 固件/引导加载器 BIOS/UEFI 初始化硬件 → 引导加载器(GRUB2)加载内核与 initramfs 内核映像与 initramfs 位于内存 引导参数错误、initramfs 损坏、磁盘加密密码输入失败
2. 内核引导 解压内核 → 初始化核心子系统(内存管理、调度器、中断)→ 挂载根文件系统 内核日志环形缓冲区(dmesg) 驱动缺失、根文件系统无法挂载、硬件 ACPI 错误
3. initramfs 过渡 运行临时根文件系统中的 /init → 加载必要驱动与模块 → 挂载真实根文件系统 → 执行 switch_root PID 1 从 /init 切换到 /sbin/init(指向 systemd) 块设备无法识别、LVM/RAID 无法激活、switch_root 失败
4. systemd 初始化 PID 1 执行 → 加载配置 → 启动默认目标单元 → 按依赖图并行启动服务 系统进入 multi-user.target 或 graphical.target 服务依赖循环、单元文件语法错误、资源耗尽、超时
排查提示: 如果系统在启动早期(内核日志最后一条信息之后)卡住,通常问题出在第 3 阶段(initramfs)或第 4 阶段(systemd 初始化)。可以通过在 GRUB 引导参数中添加 systemd.log_level=debug 和 rd.debug 来获取更详细的诊断输出。

1.3 PID 1 交接的精确时刻:switch_root 与 exec

交接过程并非瞬间完成,而是通过 switch_root 系统调用实现。initramfs 中的 /init 脚本完成以下步骤后,才会将控制权交给真正的 systemd:

  1. 挂载真实根文件系统到 /sysroot(例如 /dev/sda2)。
  2. 移动当前挂载点:将 /dev、/proc、/sys 等虚拟文件系统从 initramfs 移动到 /sysroot 下。
  3. 执行 switch_root:将根目录切换到 /sysroot,并执行 /sbin/init(即 systemd)。

从这一刻起,PID 1 的身份正式变为 systemd,它开始读取配置文件并构建初始单元依赖图。

# 典型的 initramfs /init 脚本末尾(简化)
# 挂载真实根文件系统
mount /dev/sda2 /sysroot

# 移动虚拟文件系统
mount --move /proc /sysroot/proc
mount --move /sys /sysroot/sys
mount --move /dev /sysroot/dev

# 切换到真实根并执行 systemd
exec switch_root /sysroot /sbin/init
故障场景: 如果 switch_root 执行失败(例如 /sbin/init 不存在或损坏),系统会陷入 kernel panic。此时应检查 initramfs 是否包含正确的 systemd 二进制文件,以及根文件系统是否完整。

1.4 systemd 初始化阶段的核心架构

systemd 接管后,其初始化过程并非线性执行,而是基于 目标单元(target) 和 依赖关系 的并行启动模型。下图展示了从 PID 1 启动到默认目标达成的高层架构:

systemd 初始化阶段核心架构图 PID 1: systemd 加载配置与单元文件 构建初始依赖图 启动 default.target 并行启动服务 套接字/定时器激活 挂载点/设备激活 说明:所有服务、套接字、挂载点、定时器均作为“单元”由 systemd 统一管理,通过依赖图实现并行启动

1.5 目标单元(Target)与运行级别的对应关系

systemd 使用 目标单元(.target) 替代传统的 SysV 运行级别。目标单元本身不执行任何操作,它只是将其他单元(服务、挂载点、套接字等)组织成一个同步点。下表列出了常见的目标单元及其与传统运行级别的对应关系:

systemd 目标单元 传统运行级别 用途描述 典型包含的服务
poweroff.target 0 关机 关闭所有服务 → 卸载文件系统 → 断电
rescue.target 1 单用户救援模式 仅挂载根文件系统,启动 emergency.service
multi-user.target 3 多用户非图形模式 网络服务、SSH、cron、日志系统
graphical.target 5 多用户图形模式 multi-user.target + 显示管理器(GDM/SDDM)
reboot.target 6 重启 关闭所有服务 → 重新挂载根文件系统为只读 → 重启
排查技巧: 当系统启动失败时,可以在 GRUB 引导参数中临时指定 systemd.unit=rescue.target 来进入救援模式,绕过有问题的服务。这是最常用的故障隔离手段之一。

1.6 初始化阶段的故障分类与排查思路

根据故障发生的时机和表现,可以将初始化阶段故障分为以下三类。理解分类有助于快速缩小排查范围:

  • 依赖图构建失败:systemd 在启动初期解析单元文件时发现循环依赖、缺失依赖或语法错误。表现为系统在启动早期卡住,systemctl list-jobs 显示大量 pending 作业。
  • 服务启动超时:某个服务在指定的 TimeoutStartSec 内未能完成启动。表现为系统进入 degraded 状态,systemctl status 显示该服务为 failed。
  • 资源耗尽:PID 1 或关键服务因内存不足、文件描述符耗尽、磁盘 I/O 阻塞而无法继续。表现为系统响应缓慢,日志中出现 Cannot allocate memory 或 Too many open files。
重要原则: 在排查初始化故障时,始终从 日志 入手。使用 journalctl -b -p err 查看当前启动的错误级别日志,或使用 journalctl --list-boots 查看历史启动记录。不要盲目重启或修改配置。

1.7 本章小结与课程路线图

本章建立了 systemd 初始化阶段的基础认知框架:从内核启动到 PID 1 交接的四阶段模型、systemd 初始化架构、目标单元的作用以及故障分类。后续章节将深入每个环节:

  • 第 2-5 章:目标单元与依赖关系分析
  • 第 6-10 章:服务单元启动机制与超时处理
  • 第 11-15 章:资源限制与 cgroup 故障排查
  • 第 16-20 章:套接字、定时器与路径激活
  • 第 21-25 章:日志分析与调试工具实战
  • 第 26-30 章:高级故障场景与性能优化

掌握本章的流程概览,是后续深入排查所有初始化阶段故障的基石。