2、Linux启动流程详解:BIOS/UEFI阶段、Bootloader(GRUB)阶段、内核初始化、systemd启动、用户空间初始化
说实话,搞了这么多年系统运维,我见过太多启动失败的案例。有一次凌晨三点被叫起来,说某台核心数据库服务器起不来了。我远程一看,屏幕停在GRUB界面,死活进不去系统。后来发现是/boot分区写满了,内核更新后旧内核没清理,GRUB配置直接崩了。
从那以后,我养成了一个习惯:每次排查启动问题,先在心里过一遍完整的启动流程。你想想看,如果连系统是怎么从按下电源键到出现登录提示符的都不清楚,那分析启动日志基本就是瞎蒙。
这一章,我就带你把这五个阶段彻底捋一遍。嗯,咱们从最开始的硬件自检说起。
2.1 BIOS/UEFI阶段:硬件自检与启动设备选择
按下电源键,CPU通电,第一件事就是去执行固化在主板ROM里的固件代码。这个固件,要么是传统的BIOS,要么是现代的UEFI。
核心区别一句话概括:BIOS用16位实模式,只能读MBR(主引导记录),最大支持2TB磁盘;UEFI用32/64位保护模式,能读GPT分区表,支持2TB以上磁盘,而且自带文件系统驱动(FAT32)。
我个人建议,现在新部署的服务器,能用UEFI就别用BIOS。为什么?因为UEFI的启动速度更快,安全性更高(Secure Boot),而且日志更详细。我在项目中遇到过一台老机器,BIOS下挂载了4块4TB硬盘做RAID,结果BIOS自检阶段就花了将近3分钟,换成UEFI后直接缩短到30秒。
| 特性 | BIOS | UEFI |
|---|---|---|
| 运行模式 | 16位实模式 | 32/64位保护模式 |
| 磁盘分区表 | MBR(最多4个主分区) | GPT(最多128个分区) |
| 磁盘容量限制 | 2TB | 9.4ZB(理论值) |
| 启动管理器 | 无,直接读MBR | 有,EFI系统分区(ESP) |
| 安全启动 | 不支持 | 支持(Secure Boot) |
| 日志输出 | 屏幕显示,无持久化 | 可写入UEFI变量或日志文件 |
这个阶段的关键日志,其实你平时不太容易直接抓到。BIOS阶段的输出通常只显示在屏幕上,一闪而过。但UEFI阶段,有些固件会把POST(Power-On Self-Test)日志写入NVRAM,你可以通过efibootmgr命令查看启动顺序和变量。
小技巧:如果你怀疑是硬件自检阶段的问题,可以试试在GRUB启动时按Esc或F2进入固件设置,把POST的详细输出模式打开。有些服务器(比如Dell PowerEdge)的iDRAC里也能抓到完整的POST日志。
2.2 Bootloader(GRUB)阶段:引导加载与内核选择
固件自检通过后,它会根据配置的启动顺序,去读取启动设备上的引导加载程序。在Linux世界里,GRUB(GRand Unified Bootloader)是绝对的主流。
GRUB的核心任务就两个:加载内核到内存,然后跳转执行。但这个过程其实分了好几步。
- 第一阶段(boot.img): 写在MBR或GPT的专用分区里,很小(512字节)。它的唯一任务就是加载下一阶段的core.img。
- 第二阶段(core.img): 包含文件系统驱动,能识别/boot分区。它去读取/boot/grub/grub.cfg配置文件。
- 第三阶段(grub.cfg解析): 显示菜单,等待用户选择(或超时自动选择),然后加载指定的内核(vmlinuz)和initramfs(初始内存文件系统)。
我曾经踩过的坑:有一次升级内核后,忘了运行grub2-mkconfig,结果重启后GRUB菜单里还是旧内核。更惨的是,旧内核因为某个驱动不兼容,直接panic了。所以,每次更新内核后,务必执行:grub2-mkconfig -o /boot/grub2/grub.cfg(CentOS/RHEL)或update-grub(Debian/Ubuntu)。
GRUB阶段的日志,你可以在启动时按e键编辑启动项,然后删掉quiet和rhgb参数,加上verbose。这样GRUB会把加载内核的详细过程打印到屏幕上。不过这些日志不会持久化,所以你得眼疾手快,或者用手机拍下来。
2.3 内核初始化阶段:从压缩内核到进程1
GRUB把内核和initramfs加载到内存后,就把控制权交给了内核。内核开始自解压,然后进行一系列硬件初始化。
这个阶段,说白了就是内核在“认亲”——它要识别CPU、内存、磁盘、网卡、中断控制器……所有硬件。内核会调用各个子系统的初始化函数,比如:
- 中断控制器初始化: 设置IDT(中断描述符表)
- 内存管理初始化: 建立页表,初始化伙伴系统
- 调度器初始化: 创建idle进程和init进程
- 设备驱动初始化: 枚举PCI设备,加载驱动
- 文件系统初始化: 挂载根文件系统(从initramfs切换到真正的根)
这里有个关键点:initramfs。它是一个小型的根文件系统,包含了必要的驱动和工具,用来挂载真正的根文件系统。为什么需要它?因为内核本身不包含所有文件系统驱动(比如ext4、xfs、btrfs),这些驱动通常以模块形式存在。initramfs就是用来加载这些模块的。
查看内核启动日志的命令:
# 查看当前启动的日志(最常用)
dmesg
# 查看上一次启动的日志(如果系统还能起来)
journalctl -k -b -1
# 查看特定阶段的日志(比如PCI设备枚举)
dmesg | grep -i pci
我个人习惯,在排查内核初始化问题时,会重点关注dmesg输出里的这几个关键词:Kernel panic、Oops、BUG、Unable to handle kernel、Call Trace。一旦出现这些,基本就是内核崩溃了,得从驱动或硬件兼容性上找原因。
2.4 systemd启动阶段:并行化服务启动
内核初始化完成后,会启动第一个用户空间进程——PID 1。在现代Linux发行版里,这个PID 1就是systemd。
systemd的启动逻辑,和传统的SysV init完全不同。SysV是串行启动,一个接一个跑脚本;systemd是并行启动,能同时拉起多个服务,速度飞快。
systemd启动的核心流程:
- 执行默认目标(default.target): 通常是一个符号链接,指向
graphical.target(图形界面)或multi-user.target(命令行)。 - 解析依赖关系: systemd读取所有
.service、.socket、.target等单元文件,构建依赖树。 - 并行启动服务: 按照依赖关系,能同时启动的就同时启动。比如网络服务和SSH服务没有依赖关系,就可以一起启动。
- 记录启动日志: systemd把所有的启动日志都记录在journal里,你可以用
journalctl查看。
分析systemd启动瓶颈的命令:
# 查看每个服务的启动耗时
systemd-analyze blame
# 查看启动过程的依赖图(生成SVG)
systemd-analyze dot | dot -Tsvg > boot_graph.svg
# 查看关键链路上的耗时
systemd-analyze critical-chain
我记得有一次,某台服务器启动特别慢,用systemd-analyze blame一看,有个NetworkManager-wait-online.service竟然花了45秒。说白了,这个服务在等网络完全就绪,但我们的服务器是静态IP,根本不需要等。直接把它mask掉,启动时间从2分钟降到了30秒。
2.5 用户空间初始化阶段:登录提示符与图形界面
systemd启动完所有系统服务后,最后一步就是启动用户空间的服务。这包括:
- getty服务: 在虚拟终端(tty1-tty6)上启动登录提示符。
- 显示管理器(如GDM、SDDM、LightDM): 如果默认目标是
graphical.target,就会启动图形登录界面。 - 用户会话启动: 用户登录后,启动用户级别的systemd实例(
systemd --user),然后加载用户环境变量、启动桌面环境或窗口管理器。
这个阶段的日志,主要看journalctl -u加上服务名。比如:
# 查看SSH服务的启动日志
journalctl -u sshd.service
# 查看显示管理器的启动日志
journalctl -u gdm.service
# 查看用户会话的日志(以用户ID 1000为例)
journalctl _UID=1000
嗯,这里要注意:用户空间初始化失败,通常不会导致系统崩溃,但会导致你无法登录。比如有一次,我遇到/etc/fstab里挂载了一个不存在的NFS共享,结果remote-fs.target一直等待超时,导致所有依赖它的服务(包括SSH)都启动不了。最后只能进单用户模式修复。
2.6 完整启动流程SVG图
下面这张图,把整个启动流程串起来了。你可以对照着看,每个阶段对应哪些日志来源。
2.7 本章小结
好了,这一章我们把Linux启动的五个阶段完整过了一遍。你想想看,从按下电源键到出现登录提示符,中间经历了硬件自检、引导加载、内核初始化、systemd并行启动、用户空间初始化。每个阶段都有自己独特的日志输出方式。
我个人觉得,理解这个流程最大的价值在于:当系统启动失败时,你能快速定位到是哪个阶段出了问题。比如:
- 屏幕黑屏、无任何输出 → 硬件或BIOS/UEFI阶段
- 停在GRUB菜单或报错 → Bootloader阶段
- 内核panic或挂起 → 内核初始化阶段
- 服务启动超时或失败 → systemd阶段
- 能登录但图形界面起不来 → 用户空间初始化阶段