概述
Linux 系统的启动是一个精密编排的多阶段过程,从固件加电自检到内核加载、再到用户空间服务启动,每个阶段都有其特定职责。理解完整的启动流程不仅有助于排查启动故障,还能进行启动性能优化。从固件层出发,逐层解析 BIOS/UEFI、GRUB2、initramfs、内核初始化、systemd 启动流程,并覆盖启动优化和内核崩溃恢复。
启动流程概览
[电源开启]
│
▼
[1. 固件阶段] BIOS / UEFI
│ POST (加电自检)
│ 硬件初始化
│ 查找启动设备
▼
[2. 引导阶段] GRUB2
│ 加载 GRUB 到内存
│ 读取 grub.cfg
│ 加载内核和 initramfs
▼
[3. 内核阶段] Linux Kernel
│ 内核解压并初始化
│ 硬件检测和驱动加载
│ 挂载 initramfs
│ 启动 init (systemd)
▼
[4. 用户空间阶段] systemd
│ 读取 default.target
│ 按依赖顺序启动服务
│ 启动登录服务
▼
[5. 登录阶段]
│ getty / display-manager
│ 用户认证
│ Shell 启动
▼
[系统就绪]
BIOS 与 UEFI
BIOS vs UEFI
| 特性 | BIOS | UEFI |
|---|---|---|
| 启动模式 | Legacy | UEFI |
| 固件接口 | 16位 | 32/64位 |
| 分区表 | MBR (≤2TB) | GPT (>2TB) |
| 启动代码 | 512字节MBR | EFI分区 |
| 启动速度 | 慢 | 快 |
| 网络功能 | 无 | 有(PXE/HTTP启动) |
| 安全启动 | 不支持 | 支持 |
| 分辨率 | 文本模式 | 图形模式 |
BIOS 启动流程
1. POST (Power-On Self Test)
├── CPU 初始化
├── 内存检测
├── 硬件检测
└── BIOS 设置检查
2. 启动设备选择
├── 按 BIOS 设置的顺序
├── 第一个可启动设备
└── 读取 MBR (前 512 字节)
3. MBR 结构
├── 446 字节: 引导代码
├── 64 字节: 分区表 (4个主分区)
└── 2 字节: 魔数 (0x55AA)
4. 执行 MBR 中的引导代码
└── 加载 GRUB 的 core.img
UEFI 启动流程
1. POST
└── 同 BIOS
2. UEFI 固件初始化
├── 初始化 UEFI 驱动
├── 运行 UEFI 应用
└── 安全启动验证
3. 启动管理器
├── 读取 BootOrder 变量
├── 查找 EFI System Partition (ESP)
│ └── 通常在 /dev/sda1 (FAT32, ~512MB)
└── 执行 EFI 应用: /EFI/<distro>/grubx64.efi
4. 安全启动 (Secure Boot)
├── 验证 EFI 应用签名
├── 使用内核内置密钥
└── 拒绝未签名或签名无效的引导程序
UEFI 启动项管理
# 查看 UEFI 启动项
$ efibootmgr
BootCurrent: 0000
BootOrder: 0000,0001,0002
Boot0000* ubuntu HD(1,GPT,...)/File(\EFI\ubuntu\grubx64.efi)
Boot0001* UEFI:USB ...
Boot0002* UEFI:CDROM ...
# 添加启动项
$ efibootmgr -c -d /dev/sda -p 1 -L "My Linux" -l '\EFI\mylinux\grubx64.efi'
# 修改启动顺序
$ efibootmgr -o 0000,0001,0002
# 删除启动项
$ efibootmgr -b 0002 -B
安全启动
# 查看安全启动状态
$ mokutil --sb-state
SecureBoot enabled
# 查看已注册的密钥
$ mokutil --list-enrolled
# 注册新的密钥(需要重启进入 MokManager)
$ mokutil --import /path/to/key.der
# 禁用安全启动(需要在 UEFI 设置中操作)
# 重启 → 进入 UEFI 设置 → Security → Secure Boot → Disabled
GRUB2 配置
GRUB2 启动阶段
1. boot.img (446字节)
├── 位于 MBR 或 ESP
└── 加载 core.img
2. core.img (32KB)
├── diskboot.img: 从磁盘加载
├── lzma_decompress.img: 解压
└── kernel.img: GRUB 核心
3. GRUB 正常运行
├── 读取 /boot/grub/grub.cfg
├── 显示启动菜单
└── 加载选定的内核
GRUB 配置文件层级
/etc/default/grub ← 主配置文件(用户修改)
│
▼
/etc/grub.d/ ← 脚本目录
├── 00_header ← 头部配置
├── 10_linux ← Linux 菜单项
├── 20_memtest ← Memtest 菜单项
├── 30_os-prober ← 其他 OS 检测
└── 40_custom ← 自定义菜单项
│
▼
/boot/grub/grub.cfg ← 生成的配置(不要手动修改)
主配置文件
# /etc/default/grub
# 启动菜单等待时间(秒)
GRUB_TIMEOUT=5
# 默认启动项(0 = 第一项)
GRUB_DEFAULT=0
# 菜单显示方式
GRUB_TIMEOUT_STYLE=menu # menu/countdown/hidden
# 内核参数
GRUB_CMDLINE_LINUX="quiet splash"
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
# 禁用子菜单(显示所有内核)
GRUB_DISABLE_SUBMENU=y
# 禁用恢复模式
GRUB_DISABLE_RECOVERY=true
# 分区 UUID
GRUB_DISABLE_LINUX_UUID=false
# 图形终端
GRUB_TERMINAL=gfxterm
GRUB_GFXMODE=1920x1080
# 背景图片
GRUB_BACKGROUND="/boot/grub/background.png"
# 字体
GRUB_FONT="/boot/grub/fonts/unicode.pf2"
# 串口控制台(服务器场景)
#GRUB_TERMINAL="serial console"
#GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"
内核参数详解
# /etc/default/grub
GRUB_CMDLINE_LINUX=""
# 常用内核参数:
# quiet - 隐藏启动消息
# splash - 显示启动画面
# nomodeset - 不加载图形驱动(排查显示问题)
# text - 启动到文本模式
# single / 1 - 单用户模式
# rescue - 救援模式
# init=/bin/bash - 替换 init(紧急恢复)
# systemd.unit=rescue.target - 启动到救援模式
# systemd.unit=emergency.target - 启动到紧急模式
# 调试参数:
# debug - 启用内核调试
# loglevel=8 - 内核日志级别
# print-fatal-signals=1 - 打印信号信息
# 性能参数:
# nohz_full=1-7 - 无 tick CPU
# isolcpus=1-7 - 隔离 CPU
# transparent_hugepage=never - 禁用 THP
# 安全参数:
# apparmor=1 - 启用 AppArmor
# audit=1 - 启用审计
生成 GRUB 配置
# Debian/Ubuntu
$ update-grub
# 或
$ grub-mkconfig -o /boot/grub/grub.cfg
# RHEL/CentOS
$ grub2-mkconfig -o /boot/grub2/grub.cfg
# UEFI 系统 (RHEL/CentOS)
$ grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
自定义启动项
# /etc/grub.d/40_custom
#!/bin/sh
exec tail -n +3 $0
menuentry "Custom Linux Rescue" {
set root='(hd0,msdos1)'
linux /boot/vmlinuz-rescue root=/dev/sda1 ro single
initrd /boot/initramfs-rescue.img
}
menuentry "Windows 10" {
insmod part_gpt
insmod chain
set root='(hd0,gpt1)'
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}
menuentry "Memtest86+" {
linux16 /boot/memtest86+.bin
}
GRUB 密码保护
# 1. 生成密码哈希
$ grub-mkpasswd-pbkdf2
Enter password:
Reenter password:
PBKDF2 hash of your password is grub.pbkdf2.sha512.10000.ABC123...
# 2. 添加到 /etc/grub.d/40_custom
set superusers="admin"
password_pbkdf2 admin grub.pbkdf2.sha512.10000.ABC123...
# 3. 为特定菜单项添加保护
# 在 /etc/grub.d/10_linux 的 menuentry 中添加 --users ""
# 允许无需密码启动默认项,但编辑需要密码
# 4. 重新生成配置
$ update-grub
GRUB 命令行模式
# 在 GRUB 菜单界面按 'c' 进入命令行
# 查看可用命令
grub> help
# 查看磁盘
grub> ls
(hd0) (hd0,msdos1) (hd0,msdos2)
# 查看分区内容
grub> ls (hd0,msdos1)/
boot/ etc/ home/ ...
# 手动启动
grub> set root=(hd0,msdos1)
grub> linux /boot/vmlinuz-6.6.0 root=/dev/sda1 ro
grub> initrd /boot/initramfs-6.6.0.img
grub> boot
# 搜索文件
grub> search.file /boot/grub/grub.cfg
initramfs
initramfs 的作用
initramfs(Initial RAM Filesystem)是一个临时的根文件系统,在内核启动后、真正的根文件系统挂载前使用。其主要职责:
- 加载必要的内核模块(存储驱动、文件系统驱动)
- 查找并挂载真正的根文件系统
- 切换到真正的根文件系统
内核启动 → 挂载 initramfs → 加载驱动 → 挂载真实根 → switch_root → systemd
initramfs 结构
# 查看 initramfs 内容
$ lsinitramfs /boot/initrd.img-$(uname -r) | head -30
.
bin
bin/busybox
conf
conf/conf.d
conf/init
cryptroot
etc
etc/ld.so.conf
etc/ld.so.conf.d
...
init
lib
lib/modules/6.6.0/kernel/drivers/
...
scripts
scripts/init-premount
scripts/local-top
initramfs 的 init 脚本
# initramfs 的 /init 脚本(简化版)
#!/bin/sh
# 1. 挂载基本文件系统
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
# 2. 加载内核模块
modprobe ext4
modprobe sd_mod
modprobe nvme
# 3. 解析内核命令行参数
# root=/dev/sda1
# 或 root=UUID=xxx
# 或 root=LABEL=root
# 4. 查找并挂载根文件系统
mount /dev/sda1 /mnt/root
# 5. 切换到真实根文件系统
exec switch_root /mnt/root /sbin/init
重新生成 initramfs
# Debian/Ubuntu
$ update-initramfs -u # 更新当前内核
$ update-initramfs -u -k all # 更新所有内核
$ update-initramfs -c -k 6.6.0 # 为指定内核创建
# RHEL/CentOS
$ dracut -f # 强制重新生成
$ dracut -f /boot/initramfs-6.6.0.img 6.6.0
# 查看包含的模块
$ lsinitramfs /boot/initrd.img-$(uname -r) | grep "kernel/drivers/"
# 或
$ dracut --list-modules
添加模块到 initramfs
# Debian/Ubuntu: /etc/initramfs-tools/modules
# 添加需要的模块名
nvme
nvme-core
ext4
xfs
# 重新生成
$ update-initramfs -u
# RHEL/CentOS: /etc/dracut.conf.d/custom.conf
add_drivers+=" nvme nvme-core ext4 xfs "
force_drivers+=" my_custom_driver "
$ dracut -f
initramfs 故障排查
# 1. 在 GRUB 中添加 debug 参数
# GRUB_CMDLINE_LINUX="rd.debug"
# 2. 添加 shell 到 initramfs
# GRUB_CMDLINE_LINUX="rd.break"
# 在 initramfs 阶段暂停,进入 shell
# 3. 常见问题
# - 根文件系统找不到: 缺少存储驱动
# - LVM/LUKS 无法解锁: 缺少 lvm2/cryptsetup
# - NFS 根挂载失败: 缺少 nfs 模块
内核初始化
内核启动过程
1. 内核解压
├── 从 bzImage 解压到内存
└── 跳转到内核入口
2. 早期初始化
├── CPU 初始化
├── 内存子系统初始化
├── 页表设置
└── 中断控制器初始化
3. 硬件检测
├── PCI 总线扫描
├── 设备树解析(ARM)
├── ACPI 表解析(x86)
└── 加载内置驱动
4. 内存管理初始化
├── buddy 分配器
├── slab 分配器
└── vmalloc 区域
5. 调度器初始化
├── 创建 init 任务 (PID 0)
└── 启动 idle 进程
6. 挂载 initramfs
├── 解压 cpio 归档
└── 执行 /init
7. 挂载真实根文件系统
└── switch_root 到 /sbin/init
内核启动参数
# 在 GRUB 中传递内核参数
# /etc/default/grub
GRUB_CMDLINE_LINUX="参数列表"
# 临时在 GRUB 菜单中修改
# 按 'e' 编辑 → 在 linux 行末尾添加参数 → Ctrl+X 启动
# 查看当前启动参数
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-6.6.0 root=UUID=xxx ro quiet splash
# 常用故障排查参数:
# single - 单用户模式
# rescue - 救援模式
# emergency - 紧急模式
# init=/bin/bash - 直接启动 bash(跳过 systemd)
# systemd.unit=rescue.target
# rd.break - 在 initramfs 阶段暂停
# root=/dev/sda1 - 指定根分区
# rootflags=subvol=root - 根分区挂载选项
# nomodeset - 不加载图形驱动
# acpi=off - 禁用 ACPI
# noapic - 禁用 APIC
# nodmraid - 禁用 dmraid
# rd.shell - 提供紧急 shell
内核启动日志
# 查看本次启动的内核日志
$ dmesg
# 或
$ journalctl -k
# 查看上次启动的内核日志
$ journalctl -k -b -1
# 查看启动耗时
$ systemd-analyze
Startup finished in 5.123s (kernel) + 12.456s (userspace) = 17.579s
# 查看各服务启动耗时
$ systemd-analyze blame | head -20
12.345s systemd-journal-flush.service
8.123s networkd-dispatcher.service
5.456s docker.service
3.789s sshd.service
...
systemd 启动流程
systemd 初始化阶段
1. 早期初始化
├── 读取 /etc/systemd/system.conf
├── 初始化核心功能
├── 挂载 /proc /sys /dev
└── 启动基础服务
2. 加载默认 target
├── 读取 default.target
├── 通常为 graphical.target 或 multi-user.target
└── 解析依赖关系
3. 按依赖启动
├── 拉起所有 Before= 的单元
├── 并行启动无依赖的服务
└── 处理 Requires=/Wants= 关系
4. 启动完成
├── 所有 target 依赖满足
├── 启动登录服务
└── 系统就绪
Target 与 Runlevel
| Runlevel | Target | 说明 |
|---|---|---|
| 0 | poweroff.target | 关机 |
| 1 | rescue.target | 单用户模式 |
| 2 | multi-user.target | 多用户(无图形) |
| 3 | multi-user.target | 多用户(无图形) |
| 4 | multi-user.target | 自定义 |
| 5 | graphical.target | 多用户+图形 |
| 6 | reboot.target | 重启 |
# 查看当前 target
$ systemctl get-default
multi-user.target
# 查看所有 target
$ systemctl list-units --type=target
# 修改默认 target
$ systemctl set-default graphical.target
# 临时切换 target
$ systemctl isolate rescue.target
$ systemctl isolate multi-user.target
Target 依赖关系
graphical.target
│
├── Wants: multi-user.target
│
└── multi-user.target
│
├── Wants: basic.target
│
└── basic.target
│
├── Wants: sysinit.target
│
└── sysinit.target
│
├── systemd-update-utmp.service
├── systemd-tmpfiles-setup.service
└── ...
启动阶段关键服务
1. sysinit.target 阶段(最早)
├── systemd-journald.service # 日志服务
├── systemd-modules-load.service # 加载内核模块
├── systemd-tmpfiles-setup-dev.service # /dev
└── kmod-static-nodes.service
2. basic.target 阶段(基础就绪)
├── paths.target
├── slices.target
├── sockets.target
├── timers.target
└── systemd-udevd.service
3. multi-user.target 阶段(多用户就绪)
├── sshd.service
├── network.service / NetworkManager.service
├── cron.service
├── getty.target # 登录终端
└── docker.service
4. graphical.target 阶段(图形就绪)
├── display-manager.service # GDM/LightDM
└── multi-user.target
服务依赖管理
# 查看服务依赖关系
$ systemctl list-dependencies nginx.service
# 查看反向依赖(谁依赖此服务)
$ systemctl list-dependencies --reverse nginx.service
# 查看服务的启动顺序
$ systemctl list-dependencies --after nginx.service
$ systemctl list-dependencies --before nginx.service
unit 文件中的依赖
# /etc/systemd/system/myservice.service
[Unit]
Description=My Service
Requires=network.target # 强依赖(必须启动)
Wants=remote-fs.target # 弱依赖(尽量启动)
After=network.target # 在 network 后启动
Before=multi-user.target # 在 multi-user 前启动
Conflicts=sendmail.service # 互斥服务
[Service]
Type=notify
ExecStart=/usr/bin/myservice
Restart=on-failure
[Install]
WantedBy=multi-user.target
| 依赖类型 | 说明 | 失败行为 |
|---|---|---|
Requires= | 强依赖 | 依赖失败则本服务也失败 |
Wants= | 弱依赖 | 依赖失败不影响本服务 |
Requisite= | 强依赖(不启动) | 依赖未运行则本服务直接失败 |
Conflicts= | 互斥 | 不能同时运行 |
After= | 顺序 | 在指定 unit 后启动 |
Before= | 顺序 | 在指定 unit 前启动 |
启动性能优化
分析启动耗时
# 总体耗时
$ systemd-analyze
# 各服务耗时
$ systemd-analyze blame | head -20
# 关键路径分析
$ systemd-analyze critical-chain
# 显示启动的关键路径上的服务
# 特定服务的关键路径
$ systemd-analyze critical-chain docker.service
# 生成启动图
$ systemd-analyze plot > boot-analysis.svg
# 在浏览器中打开 SVG 文件查看详细时间线
# 分析各阶段耗时
$ systemd-analyze --profile
常见启动慢的原因
| 原因 | 现象 | 解决方案 |
|---|---|---|
| 网络等待 | network.service 耗时长 | 配置静态 IP 或减小 DHCP 超时 |
| 磁盘检测 | fsck 耗时 | 定期执行 fsck,启用日志文件系统 |
| 硬件初始化 | udev 耗时 | 排除不必要的硬件 |
| 服务串行 | 服务未并行启动 | 检查 After= 依赖是否过度 |
| DNS 解析 | 某服务等待 DNS | 配置本地 DNS 缓存 |
| Entropy 不足 | 某服务等待随机数 | 安装 haveged 或 rng-tools |
优化措施
1. 禁用不必要的服务
# 查看所有启用的服务
$ systemctl list-unit-files --state=enabled
# 禁用不必要的服务
$ systemctl disable bluetooth.service
$ systemctl disable cups.service
$ systemctl disable modemmanager.service
$ systemctl disable avahi-daemon.service
$ systemctl disable speech-dispatcher.service
2. 优化网络等待
# DHCP 超时优化
# /etc/dhcp/dhclient.conf
timeout 10;
retry 3;
# 或使用 NetworkManager
# /etc/NetworkManager/conf.d/dhcp.conf
[connection]
ipv4.dhcp-timeout=10
3. 减少内核模块加载
# 查看加载的模块
$ lsmod | wc -l
# 禁用不需要的模块
# /etc/modprobe.d/blacklist.conf
blacklist bluetooth
blacklist firewire-core
blacklist thunderbolt
blacklist uas
4. 优化 fsck
# 使用日志文件系统(ext4/xfs)减少 fsck 时间
# 调整 fsck 频率
# /etc/fstab
# 第 6 列: pass(0=不检查, 1=根分区优先, 2=其他分区)
/dev/sda1 / ext4 defaults 0 1
/dev/sda2 /home ext4 defaults 0 2
5. 并行化服务启动
# 检查服务是否设置了不必要的 After=
$ systemctl cat docker.service | grep -E "After=|Requires="
# 移除不必要的串行依赖
# 创建 override
$ systemctl edit docker.service
[Unit]
After= # 清空默认的 After
After=network.target # 只保留必要的
6. 使用 systemd-networkd 替代 NetworkManager
# systemd-networkd 启动更快
$ systemctl disable NetworkManager
$ systemctl enable systemd-networkd
$ systemctl enable systemd-resolved
# 配置
# /etc/systemd/network/20-wired.network
[Match]
Name=eth0
[Network]
DHCP=yes
# 或静态 IP
# Address=192.168.1.100/24
# Gateway=192.168.1.1
# DNS=8.8.8.8
优化效果验证
# 优化前
$ systemd-analyze
Startup finished in 5.1s (kernel) + 25.3s (userspace) = 30.4s
# 优化后
$ systemd-analyze
Startup finished in 4.8s (kernel) + 8.2s (userspace) = 13.0s
# 持续监控
$ systemd-analyze plot > before-optimization.svg
# 优化后
$ systemd-analyze plot > after-optimization.svg
内核崩溃恢复
内核 panic
# 内核 panic 时的行为
$ sysctl kernel.panic
kernel.panic = 0
# 0 = 不自动重启(挂起)
# N = N 秒后自动重启
# 推荐:生产环境设置 10 秒后重启
$ sysctl -w kernel.panic=10
kdump:内核崩溃转储
kdump 在内核崩溃时启动第二个内核(capture kernel),转储崩溃内核的内存。
# 1. 安装
$ apt install kdump-tools # Debian/Ubuntu
$ dnf install kexec-tools # RHEL/CentOS
# 2. 配置
# /etc/default/kdump-tools
KDUMP_SYSCTL="kernel.panic=10"
KDUMP_COREDIR="/var/crash"
# RHEL/CentOS: /etc/default/kexec
KDUMP_KERNEL="/boot/vmlinuz-$(uname -r)kdump"
KDUMP_INITRD="/boot/initramfs-$(uname -r)kdump.img"
# 3. 启用
$ systemctl enable kdump
$ systemctl start kdump
# 4. 验证
$ kdump-config show
# 或
$ kexec -p --status
# 5. 测试(触发 panic)
# ⚠️ 警告:这会导致系统崩溃!
$ echo 1 > /proc/sys/kernel/sysrq
$ echo c > /proc/sysrq-trigger
kdump 转储分析
# 查看崩溃转储
$ ls /var/crash/
202607101530/ # 按时间组织的目录
# 分析转储文件
$ crash /usr/lib/debug/boot/vmlinux-$(uname -r) /var/crash/202607101530/dump.202607101530
# crash 常用命令
crash> bt # 查看崩溃时的调用栈
crash> ps # 查看进程列表
crash> log # 查看内核日志
crash> sys # 系统信息
crash> vm <pid> # 查看进程内存
crash> dev # 查看设备信息
紧急恢复模式
rescue target(救援模式)
# 在 GRUB 中添加
systemd.unit=rescue.target
# 或在启动后
$ systemctl rescue
# rescue 模式:
# - 挂载根文件系统(只读)
# - 启动最小服务集
# - 需要 root 密码
# - 可以编辑文件
emergency target(紧急模式)
# 在 GRUB 中添加
systemd.unit=emergency.target
# 或
$ systemctl emergency
# emergency 模式:
# - 仅挂载根文件系统(只读)
# - 不启动任何服务
# - 需要 root 密码
# - 最小化环境
init=/bin/bash
# 在 GRUB 中添加
init=/bin/bash
# 或
linux /boot/vmlinuz-6.6.0 root=/dev/sda1 ro init=/bin/bash
# 效果:
# - 跳过 systemd
# - 直接进入 bash
# - 根文件系统只读
# - 无网络、无服务
# 重新挂载根文件系统为读写
mount -o remount,rw /
# 修改密码
passwd root
# 修改配置文件
vi /etc/fstab
# 重启
exec /sbin/init
# 或
mount -o remount,ro /
reboot -f
rd.break(initramfs 阶段暂停)
# 在 GRUB 中添加
rd.break
# 效果:
# - 在 initramfs 阶段暂停
# - 根文件系统未挂载
# - 可以修复 GRUB、initramfs 等
# 挂载真实根
switch_root /sysroot
# 修改 root 密码
mount -o remount,rw /sysroot
chroot /sysroot
passwd root
touch /.autorelabel # SELinux 重新标记
exit
exit
SysRq 魔术键
# 启用 SysRq
$ echo 1 > /proc/sys/kernel/sysrq
# 常用 SysRq 组合(Alt+SysRq+字母)
# Alt+SysRq+s - 同步文件系统
# Alt+SysRq+u - 重新挂载为只读
# Alt+SysRq+b - 立即重启
# Alt+SysRq+e - 终止所有进程
# Alt+SysRq+i - 强制终止
# Alt+SysRq+k - 终止当前终端所有进程
# Alt+SysRq+t - 显示任务状态
# Alt+SysRq+w - 显示阻塞任务
# Alt+SysRq+p - 显示寄存器
# Alt+SysRq+c - 触发 panic(kdump 测试)
# 安全重启序列(记忆: Raising Elephants Is So Utterly Boring)
# Alt+SysRq+r - 取消原始模式
# Alt+SysRq+e - 终止进程
# Alt+SysRq+i - 强制终止
# Alt+SysRq+s - 同步
# Alt+SysRq+u - 只读挂载
# Alt+SysRq+b - 重启
# 命令行方式
$ echo s > /proc/sysrq-trigger # 同步
$ echo u > /proc/sysrq-trigger # 只读
$ echo b > /proc/sysrq-trigger # 重启
实战案例
案例 1:修复 GRUB 引导
# 场景:GRUB 损坏,无法启动
# 1. 从 Live USB 启动
# 2. 挂载根分区
$ mount /dev/sda1 /mnt
# 如果有 EFI 分区
$ mount /dev/sda2 /mnt/boot/efi
# 3. 挂载虚拟文件系统
$ mount --bind /dev /mnt/dev
$ mount --bind /proc /mnt/proc
$ mount --bind /sys /mnt/sys
# 4. chroot 到系统
$ chroot /mnt
# 5. 重新安装 GRUB
# BIOS:
$ grub-install /dev/sda
# UEFI:
$ grub-install --target=x86_64-efi --efi-directory=/boot/efi
# 6. 重新生成配置
$ update-grub # Debian/Ubuntu
$ grub2-mkconfig -o /boot/grub2/grub.cfg # RHEL
# 7. 退出并重启
$ exit
$ reboot
案例 2:忘记 root 密码
# 方法 1: init=/bin/bash
# 1. GRUB 菜单按 'e'
# 2. 在 linux 行末添加: init=/bin/bash
# 3. Ctrl+X 启动
# 4. 重新挂载
mount -o remount,rw /
# 5. 修改密码
passwd root
# 6. SELinux 重新标记
touch /.autorelabel
# 7. 重启
exec /sbin/init
# 方法 2: rd.break
# 1. GRUB 菜单按 'e'
# 2. 在 linux 行末添加: rd.break
# 3. Ctrl+X 启动
# 4. 重新挂载 sysroot
mount -o remount,rw /sysroot
chroot /sysroot
passwd root
touch /.autorelabel
exit
exit
案例 3:修复 fstab 错误
# 场景:/etc/fstab 配置错误导致无法启动
# systemd 进入 emergency 模式
# 1. 输入 root 密码进入 emergency shell
# 2. 重新挂载为读写
mount -o remount,rw /
# 3. 检查 fstab
cat /etc/fstab
# 找到错误的行
# 4. 修复 fstab
vi /etc/fstab
# 注释掉错误的行
# 5. 验证挂载
mount -a
# 无报错则修复成功
# 6. 重启
reboot
案例 4:initramfs 缺少驱动
# 场景:升级内核后无法启动,提示找不到根分区
# 原因:initramfs 缺少 NVMe 驱动
# 1. 从旧内核启动(GRUB 菜单选择 Advanced options)
# 2. 添加驱动到 initramfs
# Debian/Ubuntu:
echo "nvme" >> /etc/initramfs-tools/modules
echo "nvme-core" >> /etc/initramfs-tools/modules
update-initramfs -u -k $(uname -r)
# RHEL/CentOS:
echo 'add_drivers+=" nvme nvme-core "' > /etc/dracut.conf.d/nvme.conf
dracut -f
# 3. 重启验证
reboot
启动流程检查清单
#!/bin/bash
# boot-check.sh - 启动健康检查
echo "=== 启动健康检查 ==="
echo ""
echo "1. 启动模式"
[ -d /sys/firmware/efi ] && echo " UEFI" || echo " Legacy BIOS"
echo ""
echo "2. 启动耗时"
systemd-analyze
echo ""
echo "3. 启动最慢的服务(Top 10)"
systemd-analyze blame | head -10
echo ""
echo "4. 默认 target"
systemctl get-default
echo ""
echo "5. 失败的服务"
systemctl --failed
echo ""
echo "6. GRUB 配置"
echo " 内核参数: $(cat /proc/cmdline)"
echo ""
echo "7. 内核版本"
uname -r
echo ""
echo "8. 最近启动记录"
journalctl --list-boots | tail -5
echo ""
echo "9. 上次启动的错误"
journalctl -b -1 -p err --no-pager 2>/dev/null | tail -10
echo ""
echo "10. kdump 状态"
systemctl is-active kdump 2>/dev/null || echo " kdump 未安装/未启用"
总结
Linux 启动流程是一个精密的多阶段过程,每个阶段都可能出问题。核心要点:
- 理解五个阶段:固件(BIOS/UEFI)→ 引导(GRUB2)→ 内核 → initramfs → systemd,每个阶段有不同的排查方法。
- UEFI 是现代标准:支持 GPT 分区、安全启动、快速启动,新服务器应优先使用 UEFI。
- GRUB2 配置通过
/etc/default/grub:修改后必须执行update-grub/grub2-mkconfig,不要手动编辑grub.cfg。 - initramfs 是启动的关键中间件:缺少驱动会导致无法挂载根分区,修改后需要重新生成。
- systemd 的 target 取代了 runlevel:
multi-user.target对应 runlevel 3,graphical.target对应 runlevel 5。 - 服务依赖决定启动顺序:
Requires/Wants/After/Before控制依赖和顺序,systemctl list-dependencies查看依赖树。 - 启动优化从分析开始:
systemd-analyze blame找出最慢的服务,systemd-analyze critical-chain分析关键路径。 - 紧急恢复有多种方式:
rescue.target(最小服务)、emergency.target(无服务)、init=/bin/bash(跳过 systemd)、rd.break(initramfs 阶段)。 - kdump 是内核崩溃分析的基础:生产环境必须配置,崩溃后可分析转储文件定位根因。
- SysRq 是最后的手段:系统完全无响应时,用 REISUB 序列安全重启,避免直接断电导致数据损坏。
启动故障排查的黄金法则:从最后成功的阶段开始排查。如果 GRUB 能显示菜单,说明固件和 GRUB 正常;如果内核能加载但卡在挂载根分区,问题在 initramfs;如果 systemd 启动了但某服务失败,用
journalctl查看具体错误。