要成为一名合格的系统工程师,必须深入理解 Linux 的启动过程。只有知道"正常是什么样",才能在出问题时快速定位。这篇文章完整剖析从按下电源到出现登录界面的每一个阶段。
一、启动流程概览
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| ┌─────────────────────────────────────────────────────────────────────────┐
│ POWER ON │
└───────────────────────────────┬─────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ 1. BIOS/UEFI │
│ - 硬件自检 (POST) │
│ - 加载 Bootloader │
└───────────────────────────────┬─────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ 2. Bootloader (GRUB2) │
│ - 显示启动菜单 │
│ - 加载 Kernel + initramfs 到内存 │
│ - 传递启动参数 │
└───────────────────────────────┬─────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ 3. Kernel 初始化 │
│ - 解压自身 │
│ - 初始化硬件/中断/内存 │
│ - 挂载 initramfs 为临时根 │
│ - 执行 /init │
└───────────────────────────────┬─────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ 4. initramfs │
│ - 加载必要的驱动(磁盘、文件系统) │
│ - 找到真正的 root 分区 │
│ - pivot_root 切换到真正的根文件系统 │
└───────────────────────────────┬─────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ 5. Systemd (PID 1) │
│ - 并行启动系统服务 │
│ - 挂载其他文件系统 │
│ - 启动目标 (default.target) │
└───────────────────────────────┬─────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ 6. 登录界面 │
│ - getty (TTY) 或 Display Manager (图形界面) │
└─────────────────────────────────────────────────────────────────────────┘
|
二、Stage 1: BIOS/UEFI
2.1 BIOS vs UEFI
| 特性 | BIOS (Legacy) | UEFI |
|---|
| 年代 | 1981 年 | 2005 年起 |
| 启动方式 | MBR (Master Boot Record) | GPT + EFI System Partition |
| 最大磁盘 | 2TB | 9.4ZB (理论上无限) |
| 启动速度 | 较慢 | 更快 |
| 安全启动 | 无 | Secure Boot |
2.2 工作内容
POST (Power-On Self-Test)
- 检查 CPU、内存、显卡
- 一声短"滴"= 正常,连续长短音 = 硬件故障
读取启动设备顺序
- BIOS 设置中配置
- 依次尝试硬盘、U 盘、网络启动
加载 Bootloader
- BIOS:读取 MBR 的前 512 字节
- UEFI:读取 ESP 分区中的 .efi 文件
2.3 排错
现象:开机无反应或报错
1
2
3
4
5
| # 检查启动模式
[ -d /sys/firmware/efi ] && echo "UEFI" || echo "BIOS"
# UEFI 启动项管理
efibootmgr -v
|
三、Stage 2: GRUB2
3.1 GRUB2 的职责
- 提供启动菜单(多系统选择)
- 加载 Kernel 镜像到内存
- 加载 initramfs 到内存
- 传递启动参数给 Kernel
3.2 关键文件
1
2
3
4
5
| /boot/grub/grub.cfg # 主配置(自动生成,勿直接编辑)
/etc/default/grub # 用户配置
/etc/grub.d/ # 配置脚本
/boot/vmlinuz-* # Kernel 镜像
/boot/initrd.img-* 或 initramfs-* # initramfs
|
3.3 grub.cfg 示例
1
2
3
4
5
| menuentry 'Ubuntu' --class ubuntu {
set root='hd0,gpt2'
linux /vmlinuz-5.15.0-generic root=UUID=xxxxx ro quiet splash
initrd /initrd.img-5.15.0-generic
}
|
解读:
set root: Kernel 所在分区linux: Kernel 路径 + 启动参数root=UUID=xxx: 告诉 Kernel 真正的根分区在哪initrd: initramfs 路径
3.4 修改与更新
1
2
3
4
5
6
| # 编辑默认参数
sudo vim /etc/default/grub
# 重新生成 grub.cfg
sudo update-grub # Debian/Ubuntu
sudo grub2-mkconfig -o /boot/grub2/grub.cfg # RHEL/CentOS
|
3.5 排错
现象:卡在 GRUB 菜单或 grub rescue>
1
2
3
4
5
6
7
| # 进入 GRUB 命令行后
grub> ls # 列出分区
grub> ls (hd0,gpt2)/ # 查看分区内容
grub> set root=(hd0,gpt2) # 设置根
grub> linux /vmlinuz root=/dev/sda2
grub> initrd /initrd.img
grub> boot
|
四、Stage 3: Kernel 初始化
4.1 Kernel 做了什么?
- 解压自身(如果是压缩的 vmlinuz)
- 设置 CPU 模式(实模式 → 保护模式 → 64 位长模式)
- 初始化内存管理(页表)
- 初始化中断(IDT)
- 初始化调度器
- 挂载 initramfs 为根
- 执行 /init 或 /sbin/init
4.2 启动参数
1
2
3
4
5
6
7
8
9
| # 查看当前启动参数
cat /proc/cmdline
# 常用参数
root=UUID=xxx # 根分区
ro / rw # 只读/读写挂载
quiet # 减少输出
init=/bin/bash # 指定 init 程序(救援模式)
single / 1 # 单用户模式
|
4.3 排错
现象:Kernel panic
1
2
3
4
| # 常见原因
1. root= 参数指向不存在的设备
2. initramfs 损坏
3. 必要的驱动未编译进内核也不在 initramfs
|
解决:
- 进入 GRUB 命令行,修改 root 参数
- 使用 Live CD 重新生成 initramfs
1
2
3
4
5
6
7
| # 使用 Live CD
mount /dev/sda2 /mnt
mount --bind /dev /mnt/dev
mount --bind /proc /mnt/proc
mount --bind /sys /mnt/sys
chroot /mnt
update-initramfs -u -k all
|
五、Stage 4: initramfs
5.1 为什么需要 initramfs?
鸡生蛋问题:
- 要挂载根文件系统,需要驱动
- 驱动在根文件系统里
- 根文件系统还没挂载…
解决:initramfs 是一个临时的内存文件系统,包含挂载真正根文件系统所需的最小驱动集。
5.2 initramfs 内容
1
2
3
4
5
6
7
8
9
| # 查看 initramfs 内容
lsinitramfs /boot/initrd.img-$(uname -r) | head -50
# 典型结构
/init # 启动脚本
/bin/ # busybox 工具
/lib/modules/ # 驱动模块
/etc/ # 配置
/scripts/ # 初始化脚本
|
5.3 工作流程
1
2
3
4
5
6
7
| 1. Kernel 将 initramfs 解压到内存
2. 挂载为临时根 (/)
3. 执行 /init 脚本
4. 加载必要驱动(SATA/NVMe/LVM/加密等)
5. 找到真正的根分区
6. pivot_root 或 switch_root 切换到真正的根
7. 执行真正根上的 /sbin/init (Systemd)
|
5.4 排错
现象:卡在 initramfs shell
1
2
3
4
5
6
7
8
| # initramfs 会给你一个 busybox shell
(initramfs) # 检查设备
(initramfs) blkid
(initramfs) ls /dev/sd*
# 手动挂载根分区测试
(initramfs) mount /dev/sda2 /root
(initramfs) ls /root
|
重新生成:
1
2
3
4
5
| # Debian/Ubuntu
update-initramfs -u
# RHEL/CentOS
dracut -f
|
六、Stage 5: Systemd
6.1 Systemd 是什么?
Systemd 是现代 Linux 发行版的 init 系统,PID 永远是 1。它负责:
- 启动和管理系统服务
- 挂载文件系统
- 管理用户登录
- 日志管理 (journald)
6.2 启动目标 (Target)
Systemd 使用 target 替代了传统的 runlevel:
| Runlevel | Target | 用途 |
|---|
| 0 | poweroff.target | 关机 |
| 1 | rescue.target | 单用户/救援模式 |
| 3 | multi-user.target | 多用户命令行 |
| 5 | graphical.target | 图形界面 |
| 6 | reboot.target | 重启 |
1
2
3
4
5
6
7
8
| # 查看默认 target
systemctl get-default
# 设置默认 target
systemctl set-default multi-user.target
# 临时切换 target
systemctl isolate rescue.target
|
6.3 服务依赖
1
2
3
4
5
6
| # 查看服务依赖
systemctl list-dependencies sshd.service
# 查看启动顺序
systemctl list-dependencies --before sshd.service
systemctl list-dependencies --after sshd.service
|
6.4 排错
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 查看启动失败的服务
systemctl --failed
# 查看服务日志
journalctl -u sshd.service -b
# 查看启动过程日志
journalctl -b
# 分析启动时间
systemd-analyze
systemd-analyze blame
systemd-analyze critical-chain
|
七、实战:自定义启动过程
7.1 添加启动时执行的脚本
方法 1:rc.local(兼容旧习惯)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| # 创建 rc-local.service
cat > /etc/systemd/system/rc-local.service << 'EOF'
[Unit]
Description=rc.local Compatibility
After=network.target
[Service]
Type=oneshot
ExecStart=/etc/rc.local
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
# 创建脚本
echo '#!/bin/bash
echo "Hello from rc.local" > /tmp/boot-test
' > /etc/rc.local
chmod +x /etc/rc.local
# 启用
systemctl enable rc-local.service
|
方法 2:创建 Systemd 服务(推荐)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| cat > /etc/systemd/system/my-startup.service << 'EOF'
[Unit]
Description=My Startup Script
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/my-startup.sh
[Install]
WantedBy=multi-user.target
EOF
systemctl enable my-startup.service
|
7.2 调试启动问题
策略 1:增加输出
在 GRUB 中移除 quiet splash,增加 debug 参数。
策略 2:使用串口控制台
1
2
| # GRUB 参数
console=ttyS0,115200n8 console=tty0
|
策略 3:进入救援模式
在 GRUB 菜单按 e,在 linux 行末尾添加 init=/bin/bash。
八、总结
| 阶段 | 关键组件 | 排错入口 |
|---|
| BIOS/UEFI | 固件设置 | F2/DEL 进入设置 |
| GRUB | /boot/grub/grub.cfg | GRUB 命令行 |
| Kernel | vmlinuz + 参数 | 启动参数调试 |
| initramfs | /init 脚本 | initramfs shell |
| Systemd | service/target | journalctl |
核心理解:每个阶段只做一件事——为下一阶段准备环境。理解了这个链条,排错就有了方向。