Linux 系统启动流程
加电自检 → Bootloader 引导 → GRUB 加载内核 → 1 号进程初始化 → 服务 / 自定义程序启动 → 登录加载 Shell
📋 60秒速览(时间线总览)
text
[硬件层] 加电自检(POST) → 固件配置 → 发现启动盘
↓
[引导层] MBR/ESP → GRUB2 Stage1/1.5/2 → 加载 vmlinuz + initramfs
↓
[内核层] 解压内核 → initramfs临时根 → 挂载真实根分区(/) → 转交PID 1
↓
[初始化] systemd/init → 运行级别/Target → 分批启动服务
↓
[用户层] rc.local自定义 → 登录提示符 → Shell环境加载
一、Phase 0:硬件加电自检(POST)
触发:电源键 → 主板供电 → CPU 复位 → 执行 BIOS/UEFI 固件
| 步骤 | 核心操作 | 用户可干预点 |
|---|---|---|
| 属性定制 | 加载 CMOS/UEFI 设置(启动顺序、内存频率、硬盘模式 AHCI/RAID) | 按 Del/F2 进入 BIOS Setup |
| 硬件检测 | 检测 CPU、内存、显卡、键盘("滴"声=通过,蜂鸣=故障) | 听声音判断硬件健康 |
| 自举程序 | 按 Boot Priority 查找可引导设备(硬盘/CD/USB) | 按 F11/F12 临时选择启动项 |
💡 救援模式入口 :此阶段插入救援U盘/光盘,选择从 USB/CD 启动,可进入救援环境(Rescue Mode)修复系统。
二、Phase 1:引导发现(Bootloader Discovery)
固件找到硬盘后,读取引导代码的方式因模式而异:
2.1 BIOS vs UEFI 双模式对比
| 特性 | Legacy BIOS | UEFI(现代推荐) |
|---|---|---|
| 分区表 | MBR (msdos) | GPT |
| 引导位置 | 磁盘第 0 扇区 (前 446 字节为引导代码) | EFI 系统分区 (ESP) /boot/efi/EFI/rocky/grubx64.efi |
| 后续扇区 | 1~2047 扇区存 Stage 1.5 | 无此概念,直接加载完整 EFI 程序 |
| Rocky 支持 | 兼容旧硬件 | 支持安全启动(Secure Boot) |
2.2 MBR 三阶段详解(BIOS 模式)
text
第 0 扇区 (512字节)
├── [0-445] Stage 1: 446字节引导代码(定位 Stage 1.5)
├── [446-509] 分区表: 64字节(4个主分区信息)
└── [510-511] 魔数: 0xAA55(有效性标记)
第 1-2047 扇区 (~1MB)
└── Stage 1.5: 存放 ext4/xfs 驱动,用于识别 /boot 分区
/boot 分区
└── Stage 2: 完整 GRUB2 程序 + 菜单配置
2.3 GRUB2 加载内核
找到 Stage 2 后,GRUB2 显示启动菜单,执行:
bash
# GRUB2 实际执行的加载命令(按 e 可编辑查看)
linux16 /vmlinuz-5.14.0-xxx.el9.x86_64 \
root=UUID=xxxxx \ # 根分区标识(比 /dev/sda1 稳定)
ro \ # 初始只读(为 fsck 磁盘检查做准备)
rhgb quiet # 图形启动条 + 静默模式
initrd16 /initramfs-5.14.0-xxx.el9.x86_64.img
三、Phase 2:内核初始化(Kernel Space)
3.1 initramfs(初始内存文件系统)------ 关键桥梁
本质 :一个 gzip 压缩的 cpio 归档,启动时解压为临时根分区。
为什么需要它?
- 内核刚启动时没有磁盘驱动(NVMe/RAID/LVM驱动通常作为模块存在)
- initramfs 包含这些驱动和挂载脚本,让内核能"认出"真正的根分区
流程:
text
1. 解压 vmlinuz 内核
2. 挂载 initramfs 作为临时 /(内存中运行)
3. 执行 /init 脚本,加载真实根分区所需驱动
4. pivot_root 切换到真实根分区(/dev/sda2 或 LVM 等)
5. 释放 initramfs,启动 /sbin/init(即 systemd)
实操命令:
bash
# 查看当前 initramfs 内容(排查看是否包含某驱动)
lsinitrd /boot/initramfs-$(uname -r).img | grep nvme
# 重新生成(修改磁盘配置后必须执行)
dracut -f -v /boot/initramfs-$(uname -r).img $(uname -r)
四、Phase 3:系统初始化(核心差异区)
4.1 第一个进程进化史
| 发行版 | 第一个进程 | PID | 特点 |
|---|---|---|---|
| CentOS 6 及以前 | init (SysV) |
1 | 串行启动,按脚本顺序执行 |
| CentOS 7 | systemd |
1 | 并行启动,兼容 init 脚本 |
| Rocky 8/9/10 | systemd |
1 | 纯 systemd,无传统 rcx.d |
| Ubuntu 16.04+ | systemd |
1 | 纯 systemd |
验证命令:
bash
# 查看 PID 1 是什么
ps -p 1
# 查看 init 软链接指向
ls -l /sbin/init
# 输出:/sbin/init -> ../lib/systemd/systemd
4.2 运行级别 vs Target 映射表
传统运行级别(0-6):
| 级别 | 名称 | 场景 | systemd Target |
|---|---|---|---|
| 0 | 关机 | 关闭系统 | poweroff.target |
| 1 | 单用户 | 修复模式(无网络,仅 root) | rescue.target |
| 2 | 多用户无网络 | rarely used | multi-user.target |
| 3 | 多用户字符 | 服务器主流模式 | multi-user.target |
| 4 | 保留 | 自定义 | multi-user.target |
| 5 | 图形界面 | 桌面版默认 | graphical.target |
| 6 | 重启 | 重新启动 | reboot.target |
systemd 管理命令:
bash
# 查看当前默认启动目标
systemctl get-default
# 输出示例:graphical.target(桌面)或 multi-user.target(服务器)
# 临时切换(立即生效,不重启用)
systemctl isolate multi-user.target # 切到字符界面(类似 init 3)
systemctl isolate graphical.target # 切到图形界面(类似 init 5)
# 永久设置(开机生效)
systemctl set-default multi-user.target
systemctl set-default graphical.target
4.3 发行版核心差异总结
CentOS 7(过渡版):
- 保留
/etc/rc.d/rc3.d/、/etc/rc.d/rc5.d/等传统目录(兼容旧习惯) - 新增 systemd target 管理,两者并存
- 服务启动脚本既可以用旧版
service sshd start,也可以用新版systemctl start sshd
Rocky Linux 8/9/10(现代纯 systemd):
- 无
/etc/rcx.d/目录,完全通过 target 管理 - 服务管理统一用
systemctl - 启动流程:
default.target→ 依赖树并行启动服务 → 达成目标状态
Ubuntu(现代纯 systemd):
- 同 Rocky,纯 systemd 管理
- 服务配置文件路径略有不同(
/lib/systemd/system/vs/usr/lib/systemd/system/)
启动耗时分析(通用):
bash
# 查看哪个服务启动最慢(优化开机速度必备)
systemd-analyze blame
# 查看依赖链
systemd-analyze critical-chain
# 查看本次启动日志(排查卡住问题)
journalctl -xb -p err
五、Phase 4:自定义启动(/etc/rc.local)
系统初始化完成后,执行用户自定义脚本:
| 发行版 | rc.local 状态 | 使用注意 |
|---|---|---|
| Rocky Linux | ✅ 默认保留,但可能无执行权限 | 必须执行 chmod +x /etc/rc.d/rc.local 才能生效 |
| CentOS 7 | ✅ 保留,同样需执行权限 | 同上 |
| Ubuntu 20.04+ | ❌ 默认不存在,需手动创建 | 自建 /etc/rc.local,写入 #!/bin/bash 头,加执行权限 |
内容示例:
bash
#!/bin/bash
# /etc/rc.local 示例(Rocky/Ubuntu 通用格式)
# 自定义挂载
mount -o remount,noexec /tmp
# 启动自定义脚本
/usr/local/bin/my-startup.sh &
exit 0
⚠️ 注意 :systemd 时代推荐编写
.service单元文件替代 rc.local,但rc.local 仍是最快的临时方案。
六、Phase 5:登录与 Shell 环境
text
getty 服务(systemd 管理)
↓
显示登录提示符(tty1-tty6 字符终端,或图形登录管理器 gdm/sddm)
↓
用户输入账号密码 → PAM 认证通过
↓
启动用户 Shell(bash/zsh)
↓
加载配置文件:
/etc/profile ← 全局配置(所有用户)
~/.bash_profile ← 个人登录配置(仅登录时执行)
~/.bashrc ← 个人交互配置(每次开终端都执行)
↓
显示命令提示符 $/#,启动流程结束
🔧 故障排查速查表
| 故障现象 | 可能原因 | 紧急修复方法 |
|---|---|---|
grub> 提示符 |
GRUB 配置损坏 | 手动引导:set root=(hd0,1), linux /vmlinuz..., initrd /initramfs..., boot;进入系统后执行 grub2-mkconfig 和 grub2-install |
Kernel panic |
找不到根分区(UUID 变更) | 启动参数改为 root=/dev/sda1(试);进入救援模式修正 /etc/fstab;重建 initramfs (dracut -f) |
| 卡在启动进度条 | 某 systemd 服务卡死 | 按 Esc 看详细日志;重启进入 systemd.unit=rescue.target;systemctl mask 屏蔽故障服务 |
Welcome to emergency mode |
/etc/fstab 配置错误 |
输入 root 密码进入;vim /etc/fstab 注释错误行;reboot |
| 忘记 root 密码 | 需单用户模式 | 启动参数加 rd.break 或 systemd.unit=rescue.target;chroot /sysroot;passwd;touch /.autorelabel(SELinux 环境必须) |
📝 核心文件速查(建议背诵)
| 文件/命令 | 作用 | 发行版差异 |
|---|---|---|
/boot/vmlinuz-$(uname -r) |
压缩的内核镜像 | 通用 |
/boot/initramfs-*.img |
初始内存盘(临时根系统) | 通用 |
/etc/default/grub |
GRUB2 主配置文件 | 通用 |
/boot/grub2/grub.cfg |
GRUB2 菜单(勿直接编辑) | Rocky/CentOS (Ubuntu 在 /boot/grub/grub.cfg) |
/etc/rc.d/rc.local |
用户自定义启动脚本 | Rocky/CentOS 保留 Ubuntu 需自建 |
/etc/systemd/system/default.target |
默认启动目标软链接 | 通用(纯 systemd) |
systemctl set-default |
设置开机默认运行级别 | 通用 |
dracut -f |
重建 initramfs | 通用 |