☰
Linux启动过程全解:从固件到systemd的接力赛排障指南
2026/10/21 21:15:09 网站建设 项目流程

2. 引言:启动只是一场接力赛

我第一次真正搞懂Linux启动过程,不是靠读源码,也不是靠背启动图,而是靠一个特别朴素的比喻:整个开机过程就是一场四人接力赛。第一棒是固件,把系统唤醒;第二棒是引导加载器,把内核请上场;第三棒是内核自己,完成硬件到软件的初始化;最后一棒是init系统,也就是systemd,负责把所有用户态服务跑起来。每一棒接力的那一刻,都是最容易掉棒的地方,也是我们排查启动故障时的核心发力点。

这个思路对谁最有用?两类人。一类是刚接触Linux运维、天天在虚拟机里折腾、却搞不明白“开机卡住到底卡在哪一步”的新手;另一类是已经会用一些命令、但对启动流程的因果链没有整体认知、遇到内核 panic 或者挂载失败就到处乱试的进阶用户。这篇文章不会像教科书那样按时间线把所有细节铺开,而是沿着接力棒递进的顺序,把每一棒是什么、它们之间怎么衔接、每一棒最容易掉链子的点在哪里讲透,再附上我踩过的坑和排查套路。

2. 四棒接力:先看整张流程图再逐个拆解

2.1 启动全程的五个关键节点

为了后续讨论方便,先把整条链路用“接力棒”的方式标记出来:

  • 接力点0:按下电源键,CPU 从固定地址取指令,固件(BIOS 或 UEFI)开始运行。
  • 接力点1:固件完成硬件自检,把控制权交给 Bootloader(绝大多数场景下是 GRUB2)。
  • 接力点2:GRUB 加载内核镜像 vmlinuz 和 initramfs,并把控制权交给内核。
  • 接力点3:内核解压、初始化核心子系统,挂载 initramfs 中的临时根文件系统,然后切换到真正的根文件系统。
  • 接力点4:内核执行 PID=1 的 init 程序(即 systemd),systemd 按依赖关系启动所有用户态服务。

每一棒都有自己的“跑道”和“交接区”。排查启动问题,本质上就是在确认“当前这一棒到底有没有跑完,交接失败到底是哪一方的问题”。

2.2 为什么用接力赛来类比最贴切

接力赛的妙处在于:每一棒运动员各司其职,但最终成绩取决于交接是否顺畅。Linux 启动也一样——固件把控制权交给 GRUB 的时候,GRUB 如果找不到配置文件,或者磁盘路径变了,就直接掉棒;GRUB 把控制权交给内核的时候,如果 initramfs 里缺了磁盘驱动,内核连根分区都挂不上;内核把控制权交给 systemd 时,如果默认 target 损坏,系统会掉进 rescue 模式而不是正常进入多用户环境。

这个类比还有一个实用价值:它帮我们建立“分段定位”的排查思路。启动卡住时,不用慌,先判断卡在哪一个接力区——是在 GRUB 菜单之前,还是内核日志停止输出之后,还是 systemd 的某个服务超时。分段定位比从头到尾瞎查快十倍。

2.3 我建议每个想搞懂启动过程的人都跑一遍的验证方法

光看文章不如动手做一次实验。准备一台虚拟机(我用的是某开源虚拟化平台的默认配置),按以下步骤走一遍,整个过程大概半小时:

  1. 开机进入 GRUB 菜单(如果是双系统或者有 GRUB 的机器,开机时按 Shift 或 Esc 调出菜单)。
  2. 在 GRUB 菜单界面按e编辑启动项,在 linux 那一行末尾加上systemd.log_level=debug,然后按 Ctrl+X 启动。
  3. 开机后查看journalctl -b输出,重点看 systemd 启动阶段的服务顺序和耗时。
  4. 再正常重启一次,对比两次启动日志的差异。

这一套操作下来,你对“启动过程是分阶段的”这个感知会非常强烈,比看十篇文章都管用。

3. 第一棒:固件阶段——从按下电源键到 GRUB 出场

3.1 BIOS 和 UEFI 的分工

固件这一棒的核心任务就两个:自检和找引导程序。传统 BIOS 的工作方式非常直接——先执行 POST(加电自检),然后按照 CMOS 里配置的启动顺序,逐个扫描磁盘的 MBR 区域,如果发现 MBR 的最后两个字节是0x55AA,就把这一段 512 字节的代码加载到内存并跳转执行。

UEFI 则是另一种玩法了。它不自找磁盘上的引导代码,而是直接读取 ESP(EFI 系统分区)里的.efi文件,比如/EFI/BOOT/BOOTX64.EFI。UEFI 固件实际上是一个小型操作系统,它提供了更完善的运行时服务,也让启动过程更快、更安全(安全启动 Secure Boot 可以校验引导程序的签名)。

从运维排障的角度,固件阶段最容易遇到的问题有三类:

  • 开机直接黑屏,连品牌 Logo 都不出现,这是硬件级问题,和系统无关。
  • 能看到固件界面但 GRUB 菜单不出现,大概率是引导顺序不对,或者 GRUB 装到了别的磁盘。
  • 开启 Secure Boot 后 GRUB 提示签名无效,需要到 UEFI 设置里关闭 Secure Boot 或给 GRUB 签名。

3.2 GRUB 接棒时到底做了什么

GRUB2 目前是绝大多数 Linux 发行版默认的 Bootloader,它的完整工作流程可以拆成两级:

第一级是引导镜像(boot.img),它被装在 MBR 或 GPT 的保护性 MBR 里。这个镜像很小,只有一个任务:找到核心镜像core.img。第二级core.img通常装在 MBR 和第一个分区之间的空隙里,它比 boot.img 大得多,包含文件系统驱动。有了它,GRUB 才可以真正去识别分区、读取/boot/grub/grub.cfg配置文件。

这里有一个很常见的误解:有人以为 GRUB 是直接读取内核文件去启动的。其实不是,GRUB 是先去读配置文件,根据配置里定义的菜单项,再去找vmlinuz-xxx内核文件和initramfs-xxx.img镜像文件。

grub.cfg里最关键的一条命令是menuentry,它定义了菜单项,在这个块内部,有两行是灵魂:

linux /vmlinuz-6.5.0-generic root=/dev/mapper/vg-root ro quiet initrd /initramfs-6.5.0-generic.img

linux这一行不仅指明内核文件路径,还通过root=参数告诉内核真正的根分区在哪。如果系统使用 LVM 或加密盘,GRUB 还得额外加载对应的模块,这就引出了升级内核后必须执行update-grub或grub2-mkconfig的原因——你不更新配置,GRUB 就不知道新内核的存在。

3.3 实战:修复一个“进不去 GRUB 菜单”的机器

有一次我拿到一台旧服务器,开机直接卡在固件界面,提示找不到启动设备。第一反应不是重装系统,而是进 UEFI 设置看启动顺序。结果发现启动优先级列表里,第一项是 U 盘,第二项是另一块没有系统的盘,真正的系统盘排到了第三位。调整顺序之后重启,GRUB 菜单就回来了。

如果连 GRUB 都彻底坏了(比如 MBR 被覆盖),正确的做法是用发行版安装 U 盘进入救援模式:

  1. 用安装 U 盘启动,选择“试用/救援”(不同发行版叫法不同)。
  2. 打开终端,执行lsblk找到系统盘符,比如/dev/sda。
  3. 在救援模式下用grub-install /dev/sda重新安装引导程序。
  4. 再执行update-grub重新扫描内核并更新配置。

需要注意,如果根分区是 LVM 或 LUKS 加密盘,在救援环境里要先vgchange -ay激活卷组、或cryptsetup luksOpen解锁加密分区,否则grub-install之后还是起不来,因为 GRUB 找不到它该找的分区。

注意:grub-install是写到磁盘引导区域,不是写某个分区。目标参数一般写整块磁盘(如/dev/sda),而不是/dev/sda1。

4. 第二棒交接:GRUB 把内核交给 initramfs——启动排障的核心战场

4.1 内核启动到底做了什么

GRUB 把内核镜像加载到内存后,会跳转过去执行。此时内核处于一个非常尴尬的状态:它自身只包含基于 x86 的通用代码,但系统的磁盘控制器、文件系统驱动、LVM 映射关系都还没加载。内核想挂载真正的根分区,但可能连硬盘都识别不了。

这就是 initramfs(初始内存文件系统)存在的意义。它是一个打包成 cpio 格式的小型根文件系统,里面包含了内核在挂载真正根分区前所需要的一切——磁盘驱动、SCSI 控制器驱动、文件系统模块、LVM 工具、加密解密工具。

启动流程的顺序是这样的:内核先解压自身,然后解压 initramfs 到内存中的临时根目录,执行里面的/init脚本(或者 systemd 作为 init),由它去识别根分区、挂载真正的根,然后通过switch_root把根目录切换到真正的根文件系统上,释放 initramfs 占用的内存。

4.2 怎样快速判断 initramfs 出了问题

最常见的一个表现是:GRUB 菜单正常,选择内核后卡了很久,然后跳出一个Kernel panic - not syncing: VFS: Unable to mount root fs...或者在类似弹出提示框。这个信息直接说明了一件事——内核找不到根分区。

原因不外乎几个:

  • root=参数指定的设备路径变了。比如原来用的是/dev/sda1,但你加了一块硬盘后设备名变成了/dev/sdb1。
  • initramfs 里缺少必要的驱动模块。比如根分区在 NVMe 固态上,但旧 initramfs 没有 nvme 驱动。
  • 根分区本身损坏,或者 LVM 卷组因异常关机失活。

排查并修复的思路如下:

第一步,在 GRUB 菜单按e编辑启动项,去掉quiet和splash参数,加上rd.shell(如果基于 dracut)或break=pre-mount(如果基于 initramfs-tools)。这样启动过程中会直接给你丢一个 shell,里面可以做手工排查。

第二步,在 initramfs 的 shell 里执行lsblk查看磁盘设备名,对比/boot/grub/grub.cfg里的root=参数是否一致。

第三步,如果设备名变了,直接在 GRUB 编辑界面改root=参数,临时启动进入系统后再持久化修改。

以 Debian/Ubuntu 系为例,内核更新后重建 initramfs 的命令是:

sudo update-initramfs -u -k all

如果是基于 RHEL/Fedora 的 dracut 体系:

sudo dracut --force

4.3 一个典型的 LVM 根分区修复案例

我印象最深的一次故障是这样的:某台虚拟机根分区用的是 LVM,某天异常断电后,重启时一直提示找不到根卷。通过break=pre-mount进入 initramfs shell,执行lvm vgscan,发现卷组显示VG not found,再用lvm vgchange -ay强制激活,系统就能识别了。

原因也不复杂:LVM 的元数据和磁盘设备名高度绑定,异常断电可能导致设备路径变化,卷组处于 inactive 状态。解决之后,我在系统里做了两个永久性修复——一个是把根分区的root=参数改成使用 UUID 而不是设备名,另一个是把 LVM 相关工具自动激活配置确认一下。

说到这里,强烈建议所有人把启动参数里的设备路径改成 UUID。查看 UUID 的方式:

blkid

例如输出PARTUUID="xxxx"或UUID="xxxx",在 GRUB 的linux行里写root=UUID=那个值。UUID 是唯一的,和设备名无关,不管磁盘顺序怎么变,它都不会变,这是我从多次磁盘顺序变动事故中总结出来的最实用的经验。

5. 第三棒:systemd 接管——从内核态跨入用户态的过程

5.1 PID 1 的真正职责:不只是跑服务

内核完成根分区挂载后,会启动/sbin/init,它会用 symlink 指向/lib/systemd/systemd。对于 systemd 来说,它接管之后要做的事情比“启动服务”多得多。它要按依赖顺序拉起 sockets、挂载点、交换分区、系统日志、多用户目标。

理解 systemd 的启动机制,必须先理解 target 的概念。target是 systemd 里的一种单元,代表一组服务的集合,可以类比为跑道上的“计时点”。我们最常接触的三个 target:

  • poweroff.target:关机。
  • rescue.target:单用户模式,只有基础系统,相当于 Windows 的安全模式。
  • multi-user.target:正常的命令行多用户模式。
  • graphical.target:带桌面环境的目标,一般依赖 multi-user.target。

默认启动到哪个 target,是通过软链接决定的:

ls -l /etc/systemd/system/default.target

如果这个软链接指向graphical.target,系统开机后就会进入图形界面,否则默认进 multi-user。

5.2 systemd 的并行化逻辑:为什么启动这么快

老派 init 是串行的,服务一个一个按顺序跑,遇到网络等待就全卡住。systemd 的核心优势在于它并行处理相互独立的服务,并且通过 socket 激活和 D-Bus 激活,把服务真正需要的时候才拉起来。

但这引出一个问题:并行启动会导致日志顺序看起来“不规律”。比如网络服务和登录管理器可能同时启动,日志里看不出严格的先后关系。初学者如果试图从journalctl -b里找“启动顺序”,会很容易陷入混乱。

实际上 systemd 的启动链分几个阶段:

  1. 第一阶段:启动systemd-udevd等设备管理服务,等待所有硬件设备被 udev 接管。
  2. 第二阶段:挂载文件系统(local-fs.target),包括根分区、交换分区、以及/etc/fstab里声明的挂载点。
  3. 第三阶段:启动基础服务(sysinit.target、basic.target),包括系统日志、D-Bus、用户工具等。
  4. 第四阶段:进入 multi-user.target,按需启动网络、SSH、cron 等服务。

5.3 用 systemd-analyze 给启动过程“掐表”

如果你想知道系统启动到底花了多少时间、到底哪一步浪费了时间,不需要猜,直接看数据:

systemd-analyze

会输出类似 “Kernel 12.3s, Userspace 5.1s” 的结果。其中内核部分是指从 GRUB 到内核切换到用户态的时间,用户空间部分是从 systemd 启动到达到默认 target 的时间。

进一步看每个服务的耗时:

systemd-analyze blame

它会按耗时从长到短列出所有服务的启动时间。我遇到过好几次启动慢的问题,都是通过这个命令定位的,比如某个服务启动没问题但 timeout 设置过长,导致失败后还要白白等 90 秒。

再看关键链路上的时间消耗:

systemd-analyze critical-chain

这条命令会展示一条从默认 target 反向回溯的依赖链,每一行的 @ 时间是相对上一层的偏移时间,+ 是服务本身的消耗时间。如果你发现某个服务在链条上被标记为@很久以前且+巨大,基本就能锁定是它拖慢了整个启动。

小技巧:某服务启动失败后 systemd 会等待一段时间再决定是否继续,这个时间默认是 90 秒(timeout)。如果某服务在 blam 列表里稳居第一,大概率不是因为它真的很慢,而是它挂了之后 systemd 在傻等超时。

5.4 卡在“却到哪里了”的日志解读法

启动过程中如果屏幕上没有出现图形界面或者登录提示符,很多人会慌。其实只需要灵活切换视角:

  • 先按 Ctrl + Alt + F2(或 F3 等)尝试切换到其他虚拟控制台。如果能看到登录提示,说明系统已经起来了,只是显示服务的问题。
  • 如果按了没反应,说明系统还在初始化阶段或已经损坏。
  • 用journalctl -b查看本次启动日志,配合-p err只看错误级别:
journalctl -b -p err --no-pager

这条命令会列出本次开机以来所有 error 级日志,绝大多数启动问题的关键线索都会在大概 10 行之内出现。

如果你的系统卡在 systemd 初始化某个服务,可以在 GRUB 里临时追加systemd.log_level=debug启动,日志会变得非常详细,但务必结合systemd-analyze critical-chain来对照,否则 debug 日志量大到会淹没有效信息。

6. 启动排查工具箱:常用命令、应急方案和经典故障速查

6.1 每次排查都少不了的命令清单

启动过程相关的问题,绕来绕去就那么几个工具,整理成速查表,建议收藏:

命令/操作用途使用时机
dmesg或journalctl -k -b查看内核日志内核阶段卡死、驱动报错
journalctl -b查看本次启动完整日志任何用户态启动问题
systemd-analyze blame统计服务耗时启动慢
systemd-analyze critical-chain查看关键链路定位依赖链阻塞
lsblk查看磁盘设备确认设备名和挂载点
blkid查看 UUID修改启动参数前必备
df -h查看磁盘空间/boot满了导致内核更新失败
update-grub/grub2-mkconfig重新生成 GRUB 配置安装新内核或修改配置后
update-initramfs -u/dracut --force重建 initramfs内核模块变动、根分区变多
systemctl rescue进入救援模式正常系统但想去排查依赖问题

6.2 启动卡在内核阶段的排查技巧

启动过程完全没有任何输出,屏幕一片黑,这时候要大胆怀疑是内核阶段卡住了。首先要做的是去掉quiet和splash启动参数,让内核把所有启动消息打印到屏幕上。GRUB 菜单按e进入编辑,把 quiet 和 splash 删掉,再加上loglevel=7(最高日志级别),然后 Ctrl+X 启动。

如果屏幕一直停在内核日志的某一行,注意这一行的最后内容。常见情况:

  • 停在task xxxxx blocked for more than 120 seconds.,说明某个内核线程在等待 IO,极大概率是磁盘出问题或 NFS 挂载卡死。
  • 停在BUG: soft lockup,说明 CPU 上某个内核线程死循环,优先怀疑驱动问题。
  • 停在Out of memory,说明内存不足,和启动参数或硬件配置有关。

6.3 根文件系统变成只读的典型场景与修复

启动过程中最让新手困惑的另一个问题是:系统能启动,但提示根文件系统变成只读(Read-only file system)。这通常是因为系统检测到文件系统异常,为了安全自动以只读方式挂载。

在只读环境下直接执行fsck可能不生效,因为文件系统是挂载状态。正确流程是:

  1. 重启,在 GRUB 菜单按e,在 linux 行末尾加single或1以进入单用户模式。
  2. 如果单用户模式和 multi-user 一样繁忙,可以再加一个emergency参数。
  3. 在紧急模式下,先以只读方式挂载根分区:
mount -o remount,ro /
  1. 然后再执行文件系统检查:
fsck /dev/mapper/你的根分区

这里有个我踩过的坑:如果根分区是 LVM,不能对/dev/mapper/vg-root直接执行fsck时跳过,它可能提示不认识 LVM 设备名,要看清楚实际物理分区路径。执行修复后,重启之前务必确认文件系统已经没有错误,否则修复不彻底会再次变成只读。

6.4 我常用的应急复盘法:一次起不来的经历

有一次我更新内核后,重启时卡在 GRUB 之后没有任何输出。我当时判断是 initramfs 受损,因为 update 过程被中断了。处理方式很朴素:

在 GRUB 菜单选择高级选项,进入旧内核(上一版内核)启动,然后重新执行:

sudo update-initramfs -u sudo update-grub

重启后新内核恢复正常。这里的关键经验是:更新内核之后,不要立刻删除旧内核,至少保留一个已知能用的版本。这就是行业里常说的“保留可回滚点”原则,它在启动排障中救过我至少三次。

6.5 如果一切方法都无效,最终兜底方案

万不得已时,可以用 Live CD 或安装 U 盘启动系统,挂载根分区来做修复。步骤:

  1. 从 Live 环境启动,lsblk找到根分区。
  2. 挂载根分区和 boot 分区(如果独立):
mount /dev/sda2 /mnt mount /dev/sda1 /mnt/boot
  1. 挂载必要的虚拟文件系统:
mount --bind /dev /mnt/dev mount --bind /proc /mnt/proc mount --bind /sys /mnt/sys
  1. chroot进入系统:
chroot /mnt /bin/bash
  1. 在 chroot 环境内重新安装 GRUB:
grub-install /dev/sda update-grub

这套流程几乎能解决 95% 的引导类故障,也是系统救援的标准姿势。

7. 实战侧写:从按下电源键到登录界面的完整时间线

前面讲的是阶段和原理,来串一遍完整的实战时间线,把前面的知识点串成一个完整闭环。

假设一台普通的 UEFI + systemd + LVM 根分区的机器:

  • 0.000s:按下电源键,CPU 跳转到 UEFI 固件代码。
  • 0.5s:UEFI 完成自检,加载 X64 引导器,扫描 ESP 分区。
  • 1.0s:GRUB2 加载,显示菜单(如果配置了等待时间)。
  • 1.5s:选择默认内核,GRUB 读取 vmlinuz 和 initramfs 到内存。
  • 2.0s:内核接管,硬件设备开始枚举,initramfs 被解压。
  • 3.0s:udev 加载存储驱动,LVM 卷组被激活,根分区准备挂载。
  • 3.5s:switch_root完成,真正的根文件系统挂载。
  • 4.0s:systemd 启动,进入 basic.target。
  • 4.5s:systemd-journald 启动,日志记录开始。
  • 6.0s:网络服务启动,DHCP 获取地址。
  • 7.0s:SSH 服务监听端口。
  • 8.0s:graphical.target 或 multi-user.target 达成,显示登录提示。

如果你用systemd-analyze去测量,会发现优秀配置的系统,从固件到 login 界面 10 秒内完成非常正常。这也说明了 systemd 并行化的效果确实是实打实的。

8. 我对启动过程的理解:一套固定的排查思路

搞懂 Linux 启动过程并不是为了背流程,而是为了在面对一台永远起不来的机器时,心里有一个清晰的“接力棒地图”。机器卡在哪一步、哪一步的信息源去哪查、错误特征的背后是什么,每一样都有对应方法,这比碎星式地搜索错误码效率高得多。

我个人在实际操作中最受益的一点,是戒掉了“重启大法”的瘾。以前遇到启动问题,第一反应是重装;现在第一反应是按 Esc/Shift 进 GRUB、看一眼引导参数、进一次 initramfs shell、查一遍 journal。绝大多数问题都能定位到某一棒上。也建议所有刚接触 Linux 的朋友,找一台不重要的虚拟机,故意破坏几次引导、改错几次启动参数,亲手把它救回来。把这个流程走通,你对 Linux 的掌控感会上一个台阶。

最后一次强调那个最容易被忽略但最重要的习惯:拿到一台新机器后,第一时间记录根分区的 UUID、确认 GRUB 配置里用的是 UUID 而非设备名、确保 initramfs 是完整且最新的。这三件事做好,你大概率永远不需要使用这篇文章里的应急手段。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询