目录

Linux 启动全流程:从按下电源到用户登录的完整剖析

要成为一名合格的系统工程师,必须深入理解 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
最大磁盘2TB9.4ZB (理论上无限)
启动速度较慢更快
安全启动Secure Boot

2.2 工作内容

  1. POST (Power-On Self-Test)

    • 检查 CPU、内存、显卡
    • 一声短"滴"= 正常,连续长短音 = 硬件故障
  2. 读取启动设备顺序

    • BIOS 设置中配置
    • 依次尝试硬盘、U 盘、网络启动
  3. 加载 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 做了什么?

  1. 解压自身(如果是压缩的 vmlinuz)
  2. 设置 CPU 模式(实模式 → 保护模式 → 64 位长模式)
  3. 初始化内存管理(页表)
  4. 初始化中断(IDT)
  5. 初始化调度器
  6. 挂载 initramfs 为根
  7. 执行 /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:

RunlevelTarget用途
0poweroff.target关机
1rescue.target单用户/救援模式
3multi-user.target多用户命令行
5graphical.target图形界面
6reboot.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.cfgGRUB 命令行
Kernelvmlinuz + 参数启动参数调试
initramfs/init 脚本initramfs shell
Systemdservice/targetjournalctl

核心理解:每个阶段只做一件事——为下一阶段准备环境。理解了这个链条,排错就有了方向。