前言
服务器卡在启动界面进不去系统时,看懂启动流程就是看懂排障地图。这篇从固件到 shell,一步步走完 Linux 的"出生过程"。
一、总览:六个阶段
① 固件自检 (BIOS/UEFI)
▼
② 引导加载 (GRUB2)
▼
③ 内核加载 (vmlinuz + initramfs)
▼
④ PID 1 (systemd 启动)
▼
⑤ 并行拉起服务 (target + 依赖)
▼
⑥ 登录 (getty / sshd)
二、阶段一:固件(BIOS/UEFI)
BIOS(老) UEFI(现代)
按 MBR 磁盘前512字节引导 读 FAT 格式的 ESP 分区里的 .efi 文件
│ │
▼ ▼
MBR: 引导代码446B + 分区表64B /boot/efi/EFI/.../grubx64.efi
+ 魔数 55AA
# 看自己的机器是哪种
[ -d /sys/firmware/efi ] && echo UEFI || echo BIOS
# UEFI 下看启动项
efibootmgr -v
# 固件层常见故障: 启动顺序错了 / 磁盘没认出来
# → 进 BIOS Setup 检查 Boot Order 与磁盘是否识别
三、阶段二:GRUB2 引导
GRUB 的任务:找到内核与 initramfs,把控制权交出去。
# GRUB 配置的生成链(别直接改 grub.cfg!)
/etc/default/grub # 人类编辑的配置
│ grub2-mkconfig
▼
/boot/grub2/grub.cfg # 机器生成的最终配置
# 改内核启动参数的标准流程
vim /etc/default/grub
# GRUB_CMDLINE_LINUX="... quiet" ← 加参数在这
grub2-mkconfig -o /boot/grub2/grub.cfg
实战:忘记 root 密码(GRUB 是突破口):
1. 重启, 在 GRUB 菜单按 e 编辑
2. 找到 linux 行, 末尾追加: rd.break
3. Ctrl+X 启动 → 进入紧急 shell(内存里的系统)
4. mount -o remount,rw /sysroot
chroot /sysroot
passwd root
touch /.autorelabel # SELinux 重新打标签(重要!)
exit; exit
四、阶段三:内核与 initramfs
GRUB 加载 /boot/vmlinuz-$(uname -r) ← 内核本体
+ /boot/initramfs-*.img ← 内存里的迷你根文件系统
initramfs 的存在意义:根文件系统可能需要驱动才能挂载(磁盘阵列、LVM、加密盘)——鸡生蛋问题。initramfs 先在内存里起来,加载必要驱动,挂上真根后执行 switch_root 交接。
# 看看 initramfs 里有什么
lsinitrd | head -30
# 能看到内核模块、microcode、mkinitrd 脚本...
# 磁盘/驱动变更后重建
dracut -f
内核起来后最早期日志看:
dmesg | head -30 # 内核环形缓冲
journalctl -b -o short-monotonic | head -30
五、阶段四/五:systemd 时代
内核启动的第一个用户态进程 PID 1 = systemd:
ps -p 1 -o comm= # systemd
systemd --version
并行启动是 systemd 相对 SysV init 的革命:靠声明依赖(After/Wants/Requires,详见服务管理篇)把串行等待变成并行拉起——这就是现代 Linux 十几秒开机的原因。
target = 一组服务的集合(启动里程碑):
systemctl get-default # 当前默认: multi-user.target 或 graphical.target
systemctl list-dependencies multi-user.target | head
# 切换运行级别(即时)
systemctl isolate multi-user.target # 图形 → 字符界面
| target | 含义 |
|---|---|
multi-user.target |
多用户字符界面(服务器标配) |
graphical.target |
图形桌面 |
rescue.target |
单用户救援(本地有控制台) |
emergency.target |
紧急模式(只挂 / 只读) |
六、阶段六:登录与用户会话
# 本地终端(Ctrl+Alt+F2~F6 切换)
systemctl status getty@tty2
# 远程登录
systemctl status sshd
# 登录后发生什么?
# /etc/profile → /etc/profile.d/*.sh → ~/.bash_profile → ~/.bashrc
# (顺序影响环境变量, 排查 PATH 问题时按这条链查)
七、开机慢?逐段计时
systemd-analyze # 总耗时
# Startup finished in 2.1s (kernel) + 4.5s (initrd) + 8.3s (userspace)
systemd-analyze blame | head # 每个服务耗时排名
systemd-analyze critical-chain # 关键路径(谁拖累了谁)
systemd-analyze plot > boot.svg # 可视化时间线
优化手段:systemctl disable 不需要的服务、NetworkManager-wait-online 常是元凶。
八、启动故障排障地图
| 卡住位置 | 线索 | 处理 |
|---|---|---|
| 黑屏无 GRUB | 固件不认盘 | 检查磁盘/启动项;修 MBR/ESP |
GRUB 报错 grub rescue> |
grub.cfg 丢失/分区变 | ls 找到启动分区,手动 insmod normal |
卡在 Loading initramfs |
initramfs 损坏/缺驱动 | 救援盘 chroot 后 dracut -f |
| 进入 emergency mode | fsck 失败/fstab 挂载失败 | 看 journalctl;修 fstub(常是 UUID 写错) |
| 卡在某个服务 | systemd-analyze blame |
disable 或修该服务 |
| 起来了但 ssh 连不上 | sshd 未起/防火墙 | 控制台进 systemctl status sshd |
emergency/rescue 模式进入方式:
# GRUB 内核参数追加
systemd.unit=rescue.target
systemd.unit=emergency.target
# 或已能登录时
systemctl rescue
九、完整排障演练:fstab 写错进不了系统
现象: 开机进 emergency mode, 提示 "Dependency failed for /data"
原因: /etc/fstab 里挂了一块已不存在的盘
处理:
1.emergency shell 下: journalctl -xb | grep -i mount
2. mount -o remount,rw /
3. vim /etc/fstab → 注释掉那行坏盘
4. mount -a → 验证无报错
5. reboot → 顺利进入系统
这就是启动流程知识的实战价值:每一层失败都有对应入口与工具。
小结
| 阶段 | 关键组件 | 排障工具 |
|---|---|---|
| 固件 | BIOS/UEFI + 启动项 | Setup / efibootmgr |
| 引导 | GRUB2 | 按 e 编辑 / grub2-mkconfig |
| 内核 | vmlinuz + initramfs | dmesg / dracut -f |
| 初始化 | systemd | journalctl -b / systemd-analyze |
| 登录 | getty/sshd | systemctl status |
本文是「Linux 基础」系列第 8 篇。