2、Linux启动流程详解:BIOS/UEFI、Bootloader、内核初始化、init进程、systemd启动

Linux启动,说白了就是一段从按下电源键到出现登录提示符的旅程。很多运维新手觉得这过程黑盒一样,出了问题只会重启。其实搞懂它,你排查启动故障的能力会上一个台阶。

我个人习惯把启动流程拆成五个阶段:固件→引导加载→内核初始化→init进程→用户空间服务。下面我们逐个拆开看。

核心观点:启动日志分析的核心,就是在这五个阶段中找到“断点”。哪个阶段卡住了,日志就停在哪儿。

2.1 第一阶段:BIOS vs UEFI

按下电源键,CPU先执行的是固件代码。传统BIOS和现代UEFI,两者差别不小。

对比项 BIOS UEFI
引导方式 读取MBR(主引导记录) 读取EFI系统分区(ESP)
磁盘分区 MBR分区表(最大2TB) GPT分区表(支持大容量)
启动速度 较慢,实模式 较快,保护模式
日志输出 屏幕显示,无日志文件 可记录到EFI事件日志

嗯,这里要注意:UEFI模式下,启动日志里会出现“EFI stub”或“EFI framebuffer”字样。如果你看到“Booting from Hard Disk...”这种老式提示,那大概率是BIOS。

实战小技巧:排查“开机黑屏无响应”时,先看主板有没有自检通过(蜂鸣器或指示灯)。如果自检过了,问题才轮到操作系统。

2.2 第二阶段:Bootloader(GRUB2)

固件加载完,控制权交给Bootloader。Linux世界最常用的是GRUB2。

GRUB2的核心任务就两个:加载内核到内存,传递启动参数。它的配置文件在 /boot/grub/grub.cfg,但你别直接改它——改 /etc/default/grub 然后运行 update-grub 才是正解。

我曾经遇到一个案例:服务器重启后卡在GRUB提示符,手动输入 linux 和 initrd 命令才能启动。查了半天,发现是 /boot 分区空间满了,update-grub 没生成完整配置。清理旧内核后问题解决。

避坑指南:我曾经在升级内核后忘记运行 update-grub,结果新内核根本没被加入启动菜单。重启后系统还是老内核。记住:安装新内核后一定要更新GRUB配置。

GRUB2的启动参数里,quiet 和 splash 会隐藏大部分启动信息。排查问题时,我建议在GRUB菜单按 e 编辑启动项,去掉这两个参数,改成 loglevel=7 或 debug,这样内核会输出更详细的日志。

2.3 第三阶段:内核初始化

GRUB把内核和initramfs加载到内存后,内核开始初始化。这个过程分为两步:

  1. 内核解压并初始化硬件:CPU、内存、中断控制器、块设备驱动等。
  2. 挂载根文件系统:从initramfs中加载必要驱动,然后切换到真正的根分区。

内核日志可以通过 dmesg 查看,或者直接看 /var/log/kern.log。我排查启动慢的问题时,经常用 dmesg | grep -i "error\|fail\|warn" 快速定位异常。

关键日志位置:内核初始化阶段的日志,在 dmesg 中通常以 [ 0.000000] 开头的时间戳。如果某个驱动加载失败,你会看到类似 [ 3.456789] scsi: ... ERROR 的条目。

你想想看,如果内核找不到根文件系统,它会打印 Kernel panic - not syncing: VFS: Unable to mount root fs。这时候别慌,检查 root= 参数是否正确,或者initramfs里有没有对应的文件系统驱动。

2.4 第四阶段:init进程(PID 1)

内核初始化完成后,启动第一个用户空间进程——init。传统SysV init用 /etc/inittab 定义运行级别,现在基本被systemd取代了。

不过你仍然可能在旧系统或容器里遇到SysV init。它的日志输出比较原始,直接打印到控制台。而systemd则提供了 journalctl 这个强大的日志工具。

特性 SysV init systemd
启动方式 串行启动脚本 并行启动单元
依赖管理 手动排序 自动解析依赖
日志系统 无统一日志 journald
排查命令 dmesg + 脚本日志 journalctl -b

实用命令:用 journalctl -b -p err 只看本次启动的错误级别日志,比翻 /var/log/messages 快多了。

2.5 第五阶段:systemd启动与单元管理

systemd作为PID 1,负责启动所有用户空间服务。它的核心概念是单元(unit),每个服务、挂载点、套接字都是一个单元。

启动顺序由依赖关系决定。比如 network.target 必须在 sshd.service 之前启动。如果某个服务启动失败,systemd会尝试重启(取决于 Restart= 策略)。

我记得有一次排查“SSH连不上”的问题,用 systemctl status sshd 看到状态是 failed,再用 journalctl -u sshd.service -b 看到是 Permission denied——原来是 /etc/ssh/sshd_config 权限被改成了777。修复后重启服务就好了。

避坑指南:我曾经手贱改了 /lib/systemd/system/ 下的单元文件,结果系统更新时被覆盖了。正确的做法是:自定义修改放到 /etc/systemd/system/ 目录,它会覆盖默认配置。

systemd的启动分析工具 systemd-analyze 非常实用:

# 查看总启动时间
systemd-analyze

# 查看每个服务的启动耗时
systemd-analyze blame

# 生成启动流程图(SVG格式)
systemd-analyze plot > boot.svg

说白了,systemd-analyze blame 能告诉你哪个服务是启动慢的“罪魁祸首”。我见过一个案例,NetworkManager-wait-online.service 耗时30秒,禁用后启动时间从90秒降到60秒。

2.6 启动流程全景图

下面这张图把整个流程串起来了。你可以对照着看,每个阶段对应哪些日志输出。

Linux启动流程全景图 Linux 启动流程全景图 BIOS / UEFI 固件自检 → 选择启动设备 GRUB2 加载内核 + initramfs 内核初始化 硬件驱动 → 挂载根文件系统 init (PID 1) systemd 启动 用户空间服务 sshd / nginx / docker 等 各阶段日志查看方法: • BIOS/UEFI:屏幕输出 / EFI事件日志(efibootmgr -v) • GRUB2:按 e 编辑启动项,查看内核参数 • 内核初始化:dmesg 或 /var/log/kern.log • init进程:journalctl -b 查看本次启动所有日志 • 用户空间服务:journalctl -u <服务名>.service -b 💡 排查口诀:先看固件自检,再看内核恐慌,最后查服务状态。 日志时间戳从 0.000000 开始,越早越靠近硬件层。

2.7 启动日志分析实战思路

搞清楚了流程,分析日志就有方向了。我总结了一个简单的排查思路:

  1. 看启动是否完成:用 uptime 或 last reboot 确认系统是否正常启动。
  2. 定位卡住阶段:如果启动卡住,看屏幕最后一行输出。比如卡在 Started Network Manager,那就是网络服务的问题。
  3. 查看对应日志:用 journalctl -b -p err 看错误,或者 dmesg -T 看内核日志。
  4. 对比正常启动:如果系统能启动但很慢,用 systemd-analyze blame 找出耗时服务。

我的习惯:每次部署新系统,我都会保存一份 dmesg 和 journalctl -b 的输出作为基线。出问题时对比一下,能快速发现异常。