☰
Linux启动过程与故障排除:从引导到systemd的实战排障路径
2026/10/5 7:36:36 网站建设 项目流程

简介:《Linux系统启动过程与故障排除》是一份面向Linux系统管理员、运维人员及初学者的实用PDF文档。内容系统梳理了从BIOS自检、MBR引导、GRUB加载到内核启动与系统服务初始化的完整链路,并紧扣启动失败场景给出可落地的排查路径。文档重点讲解了GRUB编辑模式下的临时参数调整,包括进入single单用户模式、emergency紧急模式、troubleshooting维护模式,以及忘记root密码后的init=/bin/sh恢复方法;同时覆盖GRUB加密配置、/etc/default/grub与grub2-mkconfig的修改流程,以及借助troubleshooting模式重新安装GRUB、恢复/boot目录、修正/etc/fstab中UUID错误、还原/etc/passwd等关键文件的具体操作。全篇以步骤化说明为主,便于读者按图索骥,适合作为日常运维排错的参考手册,是系统管理员快速恢复业务的实用指南。压缩包内为单独的PDF文档,共1个文件,大小225KB,已有115人学习;轻量易存,可随时查阅。

1. Linux 系统启动过程与故障排除:一份 PDF 背后的实战逻辑

看到「Linux 系统启动过程与故障排除.pdf」这个标题,很多刚接触 Linux 的运维或嵌入式开发人员会下意识把它当成一本“手册”来读。但实际工作中你会发现,真正值钱的不是那几十页流程图,而是当你面对一台黑屏、无响应、卡在某个阶段的服务器时,能根据启动进度快速定位“卡在哪一步、问题出在哪个子系统”。系统的启动过程是从按下电源键到登录提示符出现的完整链路,涉及固件、引导加载程序、内核初始化、systemd 服务编排等多个层次。对运维、嵌入式工程师和自学 Linux 的开发者来说,掌握这条链路等于拿到故障排查的路线图——至少能节约一半以上的排障时间。本文不打算复述 PDF 的目录,而是按一条可复现的排障路径展开:先建立启动链路的整体认知,再逐层拆解日志与排查方法,最后落到几个高频故障的具体处置手段。

2. 启动链路拆解:从按下电源键到 systemd 接管,每一步都在干什么

2.1 固件与引导加载程序:BIOS/UEFI 到 GRUB 的交接细节

Linux 启动的第一阶段发生在操作系统“看不见”的地方。按下电源键后,CPU 首先执行固件代码,传统 BIOS 会按照 CMOS 里的启动顺序扫描磁盘,而现代 UEFI 固件则会读取 ESP(EFI System Partition)中的 .efi 引导文件。这里最容易出现的故障是“开机直接进固件设置界面”或“黑屏左上角光标闪烁”,前者多是因为启动顺序里没有可引导设备,后者常见于 GPT 分区表与 Legacy 引导模式不匹配。

GRUB 是 Linux 世界使用最广的引导加载程序,它负责加载内核和 initramfs。GRUB 的配置文件通常位于 /boot/grub2/grub.cfg(RHEL 系)或 /boot/grub/grub.cfg(Debian 系),但你不应该直接编辑它,而是修改 /etc/default/grub 后重新生成。一个常见需求是临时进入单用户模式修改密码,此时需要在 GRUB 菜单上按 e 编辑启动项,在 linux 那一行末尾追加 rd.break(RHEL/CentOS)或 single(Debian/Ubuntu),然后按 Ctrl+X 启动。这个操作经常被新手误用,需要特别注意:rd.break 是进入 dracut 的紧急 shell,此时根文件系统尚未挂载,需要手动执行 mount -o remount,rw /sysroot 才能修改密码,而不是直接 passwd。

2.2 内核初始化与 initramfs:为什么启动早期挂载不了根分区

内核被 GRUB 加载后,首先解压自身并初始化核心子系统,包括中断、内存管理、块设备驱动等。但此时内核还没有能力挂载真正的根文件系统——因为根分区所在的磁盘驱动可能是外置存储控制器、NVMe 或者 LVM 逻辑卷,这些驱动本身需要从文件系统加载。于是引入了 initramfs(初始 RAM 文件系统),它是一份打包了必要驱动和启动脚本的小型根文件系统,被 GRUB 加载到内存中,由内核解压后作为临时根使用。

initramfs 的生成工具在 RHEL 系是 dracut,在 Debian 系是 mkinitramfs。当你更换了磁盘控制器、修改了根分区类型、或者从 IDE 迁移到 virtio 后,系统无法启动,大概率就是 initramfs 里缺少对应驱动。这时候需要从救援模式或 LiveCD 启动,chroot 到原系统后重新生成 initramfs。以 RHEL 系为例:

# 挂载原系统根分区到 /mnt,并绑定必要的系统目录 mount /dev/sda2 /mnt mount --bind /dev /mnt/dev mount --bind /proc /mnt/proc mount --bind /sys /mnt/sys # chroot 进入原系统 chroot /mnt /bin/bash # 重新生成 initramfs,指定当前内核版本 dracut -f /boot/initramfs-$(uname -r).img $(uname -r)

这段命令的核心是 dracut -f 强制覆盖生成当前内核版本的 initramfs。uname -r 获取的是 chroot 环境里 /lib/modules 下实际存在的内核版本号,如果此版本号对应的模块目录缺失,dracut 会报错。在重新生成之前,建议先检查 /lib/modules 下目录名和 /boot 下 vmlinuz-* 文件名是否一致。Debian/Ubuntu 系则用 update-initramfs -u -k all 一键更新所有内核的 initramfs,无需手动指定版本。

2.3 systemd 启动序列:如何看懂 Target 依赖而不是背命令

内核完成初始化后,会执行 initramfs 中的 /init 脚本,该脚本最终会把控制权移交给真正的根文件系统上的 /sbin/init。在现代 Linux 发行版中,这个 init 通常是 systemd。systemd 的启动过程不是线性的一堆脚本按顺序跑,而是一个由 Target 组成的依赖图。默认启动目标在 RHEL 系是 graphical.target(图形界面),在服务器最小化安装时是 multi-user.target(多用户字符界面)。

排查 systemd 启动慢或卡死的问题,不要盯着 /var/log/messages 里的滚动日志,而应该用 systemd-analyze 系列命令。systemd-analyze 可以显示内核、initrd 和用户空间各阶段耗时;systemd-analyze blame 会列出每个单元启动耗时从大到小排序;systemd-analyze critical-chain 显示关键链路上最耗时的单元。这三条命令是定位“开机慢”的黄金组合。例如 critical-chain 输出中显示某个 network-online.target 等了 90 秒,那多半是 NetworkManager 在等待 DHCP 超时,此时需要调整网络配置让其快速失败或者改为静态 IP。

另一个高频场景是服务启动顺序错误,导致依赖服务起不来。比如你在某台机器上把 nginx 设置成了开机自启,但 nginx 依赖的磁盘挂载点还没就绪,最终 nginx 启动失败。此时不要急着 enable 服务,先用 systemctl list-dependencies nginx.service 查看它的依赖关系,确认它是否 RequiredBy 了正确的 mount 单元。如果确实存在挂载依赖,可以在 nginx.service 的 [Unit] 段添加 RequiresMountsFor=/data 声明,让 systemd 在启动 nginx 前先确保 /data 已完成挂载。

3. 启动日志与故障定位:在哪看日志、怎么把日志时间对齐到启动阶段

3.1 dmesg、journalctl 与 /var/log/boot.log 的职责划分

排查启动故障的首要技能是知道每条日志从哪里来。内核日志由 dmesg 或 journalctl -k 查看,记录的是从内核解压开始到驱动初始化完成的全过程,包括硬件识别、PCI 设备枚举、文件系统挂载等。用户空间日志则由 systemd-journald 收集,可以用 journalctl -b 查看本次启动的所有日志,-b -1 查看上一次启动的日志,这在“当前系统能起来但上次起不来”的场景里尤其有用。

/var/log/boot.log 在 systemd 时代已经很少由发行版默认写入,很多教程还在教人去 cat 这个文件,实际上是过时做法。正确的做法是优先使用 journalctl,因为 journald 会把内核日志和用户空间日志统一收集并按时间排序。如果你需要把内核日志和 systemd 日志时间对齐,可以分别执行 journalctl -k -b 和 journalctl -u 某个服务 -b,通过内核时间戳(秒级)来对应启动的哪个阶段。

3.2 卡住不动时:用启动参数让系统告诉你卡在哪

当系统卡在黑屏或滚动日志停止时,第一反应不应该是重启然后碰运气,而是主动给内核传参来暴露问题。在 GRUB 界面按 e 编辑启动项,在内核命令行(linux 开头的那一行)末尾追加两个参数后启动:systemd.log_level=debug 和 systemd.log_target=console。这样 systemd 的调试日志会直接输出到控制台,你能看到每个单元的启动状态,卡在哪个单元一目了然。

如果连内核阶段都过不去,则追加 nomodeset 参数禁用内核显卡驱动模式设置,或 rd.shell 进入 initramfs 的紧急 shell。常见的“黑屏但系统实际活着”的场景,多半是显卡驱动(如 nouveau)与 framebuffer 冲突,此时用 nomodeset 启动后再安装专有驱动,属于基本操作。另一个参数是 single,进入单用户模式跳过大部分服务,适合修复因第三方服务导致的循环崩溃。

3.3 一个实战案例:日志时间轴与硬件驱动的对应分析

假设你遇到一台服务器开机非常慢,从按电源键到 SSH 可用需要 8 分钟。用 journalctl --list-boots 查看历史启动记录,发现上一次启动也是 8 分钟,说明不是偶发。再用 systemd-analyze blame 排序,发现 dev-sda1.device 耗时 300 秒。于是用 journalctl -b -u dev-sda1.device 查看该设备单元的日志,发现内核在反复尝试读取某个扇区并超时,进一步 dmesg | grep -i error 看到大量 I/O 错误——这基本可以判断是磁盘坏道或者 SATA 线缆接触不良。整条链路用三条命令就完成了定位,而如果只看 /var/log/messages 几乎没法快速建立这种因果。

4. 高频启动故障的排查手册:8 个你能直接落地的处置手段

4.1 现象一:开机进入 GRUB 命令行而不是菜单

现象:系统重启后直接停留在 grub> 提示符,没有显示菜单。原因:grub.cfg 丢失、损坏,或者 /boot 分区未被正确识别。解决:如果 grub.cfg 只是损坏但内核还在,可以在 grub> 提示符下手工引导。先执行 ls 列出可用设备,找到 /boot 所在分区,假设是 (hd0,msdos1),再执行:

# 在 grub> 提示符下手工设置根设备和内核路径 set root=(hd0,msdos1) linux /vmlinuz-5.14.0-362.el9.x86_64 root=/dev/sda2 initrd /initramfs-5.14.0-362.el9.x86_64.img boot

这里的 vmlinuz 和 initramfs 文件名必须和 /boot 目录下实际存在的文件一致,可以用 ls /boot 先查看。如果 boot 成功,进入系统后立即执行 grub2-mkconfig -o /boot/grub2/grub.cfg 重新生成配置文件,否则下次还会卡在 grub 提示符。注意:如果你用的不是 RHEL 系而是 Debian/Ubuntu,命令是 update-grub。

4.2 现象二:内核 panic — not syncing: VFS: Unable to mount root fs

现象:启动过程中出现 VFS: Unable to mount root fs on unknown-block 错误,随后内核 panic。原因:根分区设备名错误、根文件系统驱动缺失、或 initramfs 内没有对应文件系统模块。解决:确认 GRUB 菜单里 root= 参数指向的设备真实存在。常见翻车点是使用 /dev/sda1 这样的设备名,但系统存在多块磁盘且 BIOS 识别顺序变化,导致 sda 变成 sdb。此时 root 应该用 UUID。在 GRUB 菜单按 e 查看 linux 行,把 root=/dev/sdaX 改为 root=UUID=xxxx,UUID 值可以从 grub 命令行用 ls -l /dev/disk/by-uuid 查得。如果确认 UUID 没错但依旧报错,则按 2.2 节方法重新生成 initramfs。

4.3 现象三:启动卡在 A start job is running for /dev/mapper/xxx

现象:屏幕长时间显示 A start job is running for dev-mapper-xxx.device 并计时,直到 90 秒超时后失败。原因:systemd 等待某个设备单元超时,通常是 LVM 逻辑卷、加密分区或网络块设备未就绪。解决:首先确认 /etc/fstab 里是否引用了不存在的设备。常见做法是把 fstab 中的设备名改为 UUID,并添加 nofail 选项(针对非关键分区),这样即使设备缺失也能跳过。命令如下:

# 查看当前系统所有块设备的 UUID blkid # 修改 fstab 中对应行,例如将 # /dev/mapper/data-data /data ext4 defaults 0 2 # 改为 # UUID=xxxx-yyyy-zzzz /data ext4 defaults,nofail 0 2

注意不要把根分区的 nofail 加上,否则根分区挂载失败时系统会进入 emergency mode 而不是跳过,反而掩盖问题。修改 fstab 后执行 systemctl daemon-reload 并重新挂载测试,不要直接重启,避免改错后起不来。

4.4 现象四:服务启动顺序导致依赖失败,进入 emergency mode

现象:开机进入 emergency mode,提示 Failed to mount /data 或某个服务启动失败。原因:systemd 严格按依赖启动,但 fstab 或 unit 文件没有声明好挂载关系。解决:如果是 fstab 中挂载点依赖,可以在对应 systemd 服务里添加 RequiresMountsFor=/data,这样 systemd 会保证挂载完成后再启动服务。如果只是某次启动中手动挂载导致 fstab 缺失,但业务又需要,建议用 systemctl edit nginx.service 添加片段而不是直接改 /usr/lib/systemd/system/nginx.service,因为更新软件包会覆盖原文件:

# 创建服务单元的追加配置 systemctl edit nginx.service # 在打开的编辑器中添加 [Unit] RequiresMountsFor=/data # 保存后重载配置 systemctl daemon-reload systemctl restart nginx.service

这种片段方式的好处是保留原服务文件不动,只覆盖新增配置,软件包升级也不会丢失你的修改。

4.5 现象五:开机后启动图形界面黑屏但 SSH 可连

现象:服务器能远程登录,但本地显示器黑屏或花屏,GUI 无法显示。原因:显卡驱动与内核 framebuffer 冲突。解决:先用 SSH 登录,检查 nouveau 驱动是否被加载(lsmod | grep nouveau),如果加载则禁用。在 /etc/modprobe.d/ 下创建 blacklist-nouveau.conf,内容为 blacklist nouveau 和 options nouveau modeset=0,然后重建 initramfs 并重启。如果是笔记本或 NUC 等混合显卡设备,可能还需要在内核参数里添加 acpi_osi=linux 或 video=LVDS-1:e 来修正显示输出。

4.6 现象六:密码忘记,需要进入单用户模式修改 root 密码

现象:忘了 root 密码,无法登录系统。解决:在 GRUB 菜单按 e 编辑,找到 linux 行末尾追加 rd.break(CentOS/RHEL 7+)或 single(早期 SysVinit)。以 CentOS 9 为例,启动后进入 switch_root:/# 提示符,执行以下命令:

# 重新挂载根文件系统为可写 mount -o remount,rw /sysroot # chroot 进入真正的根目录 chroot /sysroot # 修改 root 密码 passwd root # 退出 chroot 并重启 exit reboot -f

这里的关键是 mount -o remount,rw /sysroot,因为 rd.break 默认以只读方式挂载根文件系统,不执行这一步直接 passwd 会报错。修改密码后要确保 SELinux 上下文正确,执行 touch /.autorelabel 让系统在下次启动时自动重打 SELinux 标签,否则可能因为安全上下文错误导致无法登录。

4.7 现象七:启动内存不足 OOM 导致内核 panic

现象:启动过程中内核 panic,dmesg 显示 Out of memory。原因:内存过小或 initramfs 解压需要的内存超限。解决:如果是虚拟机或嵌入式设备,检查分配给内核的内存量。可以在启动参数里添加 mem=512M 来限制内核可用内存,看是否能正常启动,以验证是不是内存探测问题。如果确认是 initramfs 太大导致内存不足,可以精简 initramfs 内容,去掉不必要驱动模块。RHEL 系可以用 dracut --omit-drivers "floppy" 重新生成,减少体积。

4.8 现象八:重复循环重启或启动即崩溃

现象:系统启动一段时间后自动重启,或反复循环无法进入登录界面。原因:硬件不稳定、内核 oops 触发 panic 后自动重启,或者系统检测到关键服务失败后主动重启。解决:先检查 /proc/sys/kernel/panic 的值,如果为 0 则内核 panic 后不会自动重启。如果系统反复重启,需要抓 panic 现场。在 GRUB 菜单按 e 编辑,在 linux 行末尾添加 panic=5 和 oops=panic 参数,让 panic 或 oops 后 5 秒重启并记录日志到磁盘。如果无法抓取,用串口连接服务器,添加 console=ttyS0,115200 参数把日志输出到串口,这是内核调试的基本方法,尤其适用于没有显示器的嵌入式设备或云主机。

5. 启动故障排查的 5 个常见误区:别再把玄学当经验

这里讲的五个误区,是我在维护大量 Linux 服务器后总结的血泪经验。第一个误区是“重启能解决一切”。重启前一定要先记录当前状态,至少执行 journalctl -b -x 查看本次启动的日志并把关键行拍照或复制下来,否则重启后现场丢失,只能靠猜。第二个误区是“所有启动慢都看 dmesg”,实际上 dmesg 只涵盖内核阶段,systemd 用户空间的耗时要用 systemd-analyze blame 来看,两者是不同维度。第三个误区是“直接编辑 grub.cfg”,这样做很容易在下次 grub2-mkconfig 时被覆盖,应该修改 /etc/default/grub 后再生成。

第四个误区是“在 fstab 里写死设备名”。我知道很多老工程师习惯写 /dev/sda1,但现代机器上磁盘顺序变化太常见,一旦 BIOS 识别顺序变化,系统直接进 emergency mode。正确的做法是全部使用 UUID,用 blkid 获取后再写。第五个误区是“忘记 SELinux 的影响”。当你修改了 /etc/shadow 或系统文件后直接重启,如果 SELinux 处于 enforcing 模式,可能会出现诡异的“密码正确但登录失败”,此时在启动参数里加 enforcing=0 验证,然后重打标签 regular 解决。这五点看起来简单,但每一条我都见过实际生产环境翻车,希望你不要再踩。

6. 从日志数据到启动性能优化:三个能立刻用上的进阶技巧

进入正题的最后一步,我们聊点能直接提升启动效率和排障能力的手段。第一个技巧是给关键的启动单元添加超时控制。默认 systemd 等待设备和服务的时间是 90 秒,对于网络挂载等设备,这个时间太短,可以给对应 mount 单元设置 TimeoutSec=300,但对于不需要等待的设备,可以缩短到 30 秒,避免浪费。第二个技巧是建立启动性能基线。我习惯在系统初始化完成后,执行 systemd-analyze > /var/log/boot-baseline.txt,后续每次改动内核参数或服务,再生成一份并 diff,能够直观看到哪些改动影响了启动时间。

第三个技巧是学会使用 Trace 功能排查服务依赖卡顿。systemd 提供了 systemd-analyze verify 命令,可以静态检查 unit 文件的语法和依赖完整性,在部署前发现潜在问题。配合 systemctl list-units --state=failed 定期检查失败的单元,能提前规避很多故障。如果你管理的机器数量较多,建议把所有机器的 journald 日志集中收集到一台日志服务器,用 journalctl --merge 或 rsyslog 转发,这样即使机器起不来,也能从远端查看上一次启动的日志。

最后分享一个我自己的习惯:每次修改内核启动参数或 fstab 之前,先把原文件备份到 /root/boot-backup/ 目录,并记录修改时间和原因。这样即使改坏了,也能快速回滚,而不是手忙脚乱地敲 rescue 命令。启动过程的排查本质上是一项“时间轴对齐”的工作——把固件、内核、initramfs、systemd 四个阶段的日志按时间顺序拼起来,问题点会自然浮出水面。希望这篇笔记能帮你在面对 Linux 启动故障时少走弯路,让目标系统和日志数据成为你最可靠的排障伙伴。

本文还有配套的精品资源,点击获取

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

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

立即咨询