作为长期和Linux服务器打交道的系统管理员我觉得启动过程控制是整个系统管理知识链里最容易被轻视、但实际价值极高的一块。很多同学对开机的理解停留在按下电源键、看到桌面或登录提示符这一步一旦遇到服务器重启后起不来、误改启动参数导致卡死、或者GRUB菜单丢失这类故障就完全不知道从哪里下手。这篇文章把RH134课程第10章控制启动过程的重点整理一遍从开机加电到systemd完成初始化把整个启动链路的每个环节、各环节之间的交接逻辑、以及常见故障的处理思路讲清楚。文章适合准备考RHCSA认证的读者、刚接手服务器运维的新人以及那些想系统补全Linux启动机制这块拼图的开发者。1. 启动流程全览从加电到登录界面的完整链路1.1 固件层BIOS与UEFI的初始化很多人以为按下电源键后第一个干活的是内核实际上真正的第一棒交给固件程序。传统BIOS和现代UEFI在这个阶段做的事情高度相似初始化CPU、内存、芯片组等核心硬件执行Power-On Self-Test自检然后按照Boot Order去搜索可引导设备。RHEL 7之后的Linux发行版基本都默认使用UEFI引导方式但兼容模式下仍然会走BIOS风格的MBR引导流程所以两种路径都得理解。BIOS MBR路径固件从磁盘的第一个扇区读取主引导记录GRUB2的第一阶段引导代码通常安装在这里然后这条链逐步把控制权交给真正的Bootloader主体。UEFI EFI路径固件直接读取EFI系统分区ESP分区通常是/boot/efi下的.efi文件比如grubx64.efi跳过了传统MBR的限制加载速度和灵活性都有提升。实际运维中区分这两种路径非常重要。比如你在基于UEFI引导的系统上尝试用旧式grub-install /dev/sda的方式修复引导很可能失败因为UEFI固件根本不会理睬磁盘MBR区域的代码。反过来老旧的BIOS固件也读不懂EFI分区。理解这一点后再看启动故障的报错信息很多线索就清晰了。1.2 GRUB2引导加载阶段准备内核运行环境固件把控制权交给GRUB2后GRUB2要做的事情并不是直接启动内核这么简单。它需要读取配置文件/boot/grub2/grub.cfgUEFI路径下通常是/boot/efi/EFI/redhat/grub.cfg然后按菜单项找到内核镜像vmlinuz-*和初始RAM磁盘镜像initramfs-*.img。这里有个关键概念为什么不能直接加载vmlinuz后就让内核挂载硬盘上的根文件系统原因在于内核自身只包含基本的存储驱动代码而根文件系统可能位于LVM逻辑卷、软件RAID阵列或者加密设备上这些设备需要额外的驱动模块才能被识别。initramfs就是解决这个问题的小型临时根文件系统它先把必要的驱动模块加载进内存让内核有能力挂载真实根分区然后完成交接。实际运维时可以这样验证在GRUB2菜单界面按e键编辑启动项你会看到linux开头的一长串参数其中包含了root/dev/mapper/rhel-root之类的根设备指定方式以及rd.lvm.lv...这类与initramfs相关的参数。改错这些字段系统就会在启动过程中报Failed to mount /sysroot之类的错误最常见的根因就是根设备标识写错、LVM卷名不匹配或者SELinux 标签异常。1.3 内核初始化与PID 1的交接内核镜像被加载到内存并解压后内核初始化所有必须的核心子系统比如内存管理、进程调度器、中断处理、网络协议栈等。等到内核把这些基础服务准备好了它会挂载真正的根文件系统然后启动系统的第一个用户空间进程——PID 1。在RHEL 7以上版本中这个PID 1就是systemd。内核与systemd的交接有一个容易被忽略的细节systemd启动后并不是马上并行拉起所有服务而是先执行一个基础初始化流程包括设置主机名、挂载/proc、/sys、/dev等虚拟文件系统、应用内核参数、启动systemd-journald日志服务等。这一阶段完成的动作是后续所有服务启动的前提。如果这里的某个环节出问题比如/etc/fstab中某个挂载点配置错误systemd会尝试多次挂载最终超时后继续启动别的单元但你会在日志里看到大量异常报错。这也是为什么启动故障排查时第一个动作永远是查看日志。1.4 启动目标与用户空间的建立当systemd完成了基础初始化后它读取默认的启动目标target。所谓的target可以理解为一组服务的集合和依赖关系的编排单元。默认target可能是multi-user.target多用户命令行界面对应传统运行级别3也可能是graphical.target图形登录界面对应运行级别5。systemd会解析这个target的全部依赖并行激活所有需要的服务单元最终把系统带到可登录状态。整个链路用一句话概括固件找引导程序引导程序加载内核内核挂载根文件系统systemd拉起用户空间服务。任何一个环节的故障表现可能天差地别固件层问题表现为无显示输出或找不到引导设备GRUB2问题表现为停在引导菜单或直接黑屏内核问题表现为内核恐慌Kernel Panicsystemd阶段问题则表现为启动卡在某处或部分服务失败。后续所有排查技巧本质上都是在定位你当前到底卡在链路的哪一环。2. systemd目标机制启动过程的路线图2.1 target与runlevel的对应关系RHEL 7之前的SysVinit用运行级别runlevel来区分系统状态数字0到6各有含义。systemd用target抽象出了更灵活的单元组织方式但为兼容旧习惯两者之间有明确的对应关系。实际使用中这些知识直接决定了你能否通过切换target进入恢复环境。runleveltarget单元用途0poweroff.target关机1rescue.target单用户模式适用于修复系统2multi-user.target命令行多用户模式老系统中2级不带网络服务新systemd统一用multi-user3multi-user.target命令行多用户模式4multi-user.target命令行多用户模式5graphical.target图形界面模式6reboot.target重启生产环境中最常用的切换命令就是systemctl isolate multi-user.target或systemctl isolate graphical.target。isolate表示立即停止当前target下所有非依赖项服务切换到新的target。如果你把它理解成运行级别切换的现代替代方案很多操作逻辑就顺理成章了。2.2 查看与修改默认启动目标服务器重装后最常见的需求就是确认当前系统默认进什么模式。用两个命令就能搞定# 查看当前默认target systemctl get-default # 修改默认target systemctl set-default multi-user.target需要注意systemctl set-default修改的只是默认启动目标它不会影响当前正在运行的目标必须重启后才生效。如果你想立刻切换到目标模式需要用systemctl isolate multi-user.target。我有一次在某台测试服务器上执行了systemctl set-default graphical.target但当时系统已经处于多用户模式我以为操作失败反复执行了几次才发现需要重启才能看到效果这种细节在考试和实际环境里都很容易踩坑。此外systemctl list-units --typetarget可以列出当前活动的target单元systemctl list-dependencies multi-user.target则能查看该target依赖的所有服务单元。这些命令在排查为什么某个服务没有启动时非常有用因为你可以顺着依赖树逆推看是哪个上游单元拖住了整个链。2.3 救援目标与紧急目标的使用场景target机制真正厉害的地方在于内置了rescue.target和emergency.target两个恢复环境。两者听起来类似但差别很大。rescue.target传统意义上的单用户模式。它会挂载根文件系统启动基础系统服务但不启动网络服务、不启动多用户环境。适合修复/etc/fstab错误、重置密码、重新生成GRUB配置等场景。emergency.target最小的紧急Shell连根文件系统在最初都不会完整挂载。它在你连rescue模式都无法正常进入时兜底。适合处理根文件系统损坏、关键配置严重损坏等极端的场景。在GRUB菜单中你可以在选中的启动条目上按e进入编辑模式找到linux起始的那一行在行尾追加systemd.unitrescue.target或systemd.unitemergency.target然后按Ctrlx启动。这个操作是RHCSA考试里的重点也是真实运维中进入救援环境的快捷方式。有人会误以为必须在GRUB菜单按某个隐藏键才能进入单用户模式其实通过修改内核命令行参数来指定目标是systemd时代最干净可靠的方式。2.4 生产环境中修改target的真实案例之前我接手一台启动后卡在黑屏、只显示光标闪烁的服务器远程终端里完全无法操作。通过带外管理控制台进入GRUB菜单给内核追加了systemd.unitrescue.target后系统直接进入了root Shell。排查后发现是某次更新后默认target从multi-user.target变成了不存在的自定义target导致systemd无法解析。用systemctl set-default multi-user.target恢复默认值后重启一切正常。这种问题的根源在于systemctl set-default虽然会校验target文件是否存在但如果有人手动修改了/etc/systemd/system/default.target的软链接指向了一个被误删的target文件系统启动时就会卡在寻找默认目标的阶段。善用rescue.target通常十分钟内就能把这类问题解决掉。3. GRUB2引导配置启动菜单的前世今生3.1 GRUB2的层次结构与配置文件关系GRUB2采用两级配置设计。vi /etc/default/grub编辑的是核心变量文件它并不直接控制启动菜单真正被GRUB2读取的是编译生成的/boot/grub2/grub.cfg。每次修改/etc/default/grub之后都需要运行grub2-mkconfig -o /boot/grub2/grub.cfg重新生成配置文件修改才能生效。这里有一个新手常犯的错误直接去手动编辑grub.cfg结果系统升级内核或重装GRUB时所有手动修改都被覆盖。正确的做法永远是把改动写在/etc/default/grub中然后通过生成命令同步到实际配置。如果系统是UEFI引导方式生成的输出路径需要用-o /boot/efi/EFI/redhat/grub.cfg很多人在这一步混淆了路径导致改了配置但引导完全没变化。3.2 修改默认启动项与菜单超时时间最常用的GRUB变量有三个# 默认启动项可以是数字也可以是菜单项名称 GRUB_DEFAULT0 # 菜单显示时间 GRUB_TIMEOUT5 # 额外传递给内核的参数 GRUB_CMDLINE_LINUXcrashkernelauto rhgb quietGRUB_DEFAULT0表示默认启动第一个菜单项。但系统安装多内核或双系统后菜单项顺序变化频繁依赖数字编号并不可靠。更稳定的做法是使用grub2-set-default命令设置指定的菜单项名称或者用grub2-editenv list查看当前引导记录中记录的saved_entry值# 查看当前保存的默认启动项 grub2-editenv list # 设置某个菜单项为默认启动 grub2-set-default Red Hat Enterprise Linux (3.10.0-1160.el7.x86_64) 7.9 (Maipo) # 再生成一次grub.cfg确保设置持久化 grub2-mkconfig -o /boot/grub2/grub.cfg修改GRUB_TIMEOUT时也要注意生产服务器通常建议设置成5秒以上但如果你把超时时间改成0开机后GRUB会立即按默认项启动用户根本没有机会按e进入编辑模式一旦默认项有问题就只能靠安装介质救援了。内部测试机可以这样操作生产机千万别省这两秒。3.3 单系统GRUB修复的无坑操作最常见的一种故障是根文件系统本身完好但GRUB阶段一数据损坏开机后提示GRUB或者Unknown filesystem。这种情况不需要重装系统通过安装介质或者救援光盘进入救援模式即可修复。如果系统能进入rescue模式但GRUB损坏场景较复杂常规操作是chroot到硬盘根文件系统后重新生成GRUB配置并安装到磁盘# 假设已经进入rescue环境并定位到真实根目录 mount -o remount,rw /sysroot chroot /sysroot # 重新生成GRUB配置 grub2-mkconfig -o /boot/grub2/grub.cfg # 重新安装GRUB到磁盘BIOS引导 grub2-install /dev/sda # UEFI引导系统则执行 grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg注意以上命令的执行环境必须和真实系统完全对应。用chroot进入/sysroot之前需要确认根分区和/boot分区已经挂载到正确位置。有些同学在chroot后看不到/boot/grub2目录就是因为/boot可能是独立分区没有提前挂载。这一步看似简单却是修复失败的头号原因。3.4 修改内核启动参数的临时手段在GRUB菜单按e编辑启动项时可以直接修改linux行的内核参数比如临时加上rdbreak在initramfs阶段中断、selinux0临时关闭SELinux、systemd.unitemergency.target等。这种修改只在本次启动有效重启后自动恢复。这个临时修改手段非常实用。比如你配置了错误的GRUB_CMDLINE_LINUX内核在加载根设备时崩溃你可以通过编辑启动项把那条参数临时删掉先进系统把配置改回来再正常重启。比如rhgb图形化启动和quiet隐藏启动日志这两个参数在排障时最好临时去掉因为完整的启动日志直接显示在屏幕上比事后翻journal更快定位卡点。4. 启动故障排查与修复把命令变成肌肉记忆4.1 启动失败后的第一屏日志侦察系统启动进入systemd阶段后如果出现异常最直观的表现是启动过程卡顿、服务反复重启或者直接黑屏。此时第一个排查动作就是查看日志# 查看本次启动的所有错误级别的日志 journalctl -b -p err # 查看本次启动从哪个时间点开始 journalctl -b --no-pager | head -50 # 列出启动失败的服务单元 systemctl list-units --failedjournalctl -b中的-b表示读取本次启动的日志如果想查看上一次启动的记录可以用journalctl -b -1。这个功能在系统反复重启但问题只出现在某一次启动中时特别有用。实际使用中我最推荐的组合是systemctl list-units --failedjournalctl -b -p err。前者告诉你哪个服务没起来后者告诉你为什么没起来。有一次我在某台服务器上看到systemd-networkd反复失败前者只报了服务名后者的日志里明确指出是网卡配置文件里的MACAddress字段和实际网卡不符十分钟内就定位了问题。4.2 进入救援模式完成根文件系统修复当内核已经启动但根文件系统挂载失败时通常的表现是启动过程跳出一堆Failed to mount /sysroot或You might want to fix this problem之类的错误然后自动进入emergency shell。这时需要手动确认LVM卷、分区和文件系统状态。# 查看磁盘和LVM状态 lvs vgs # 手动尝试挂载根卷 mount /dev/mapper/rhel-root /mnt # 如果文件系统有错误修复根卷 xfs_repair /dev/mapper/rhel-root需要注意RHEL 7及以后版本默认文件系统是XFS损坏后的修复方式不是fsck而是xfs_repair而且目标卷必须先卸载或只读挂载。在emergency target中根文件系统本来就未完整挂载执行修复的时机比较理想。等文件系统修好后再重新启动系统通常会恢复正常。整个过程的关键是不要慌先确认挂载信息再动手修。4.3 重置root密码的全流程忘记root密码是几乎每个管理员都会遇到的场景控制启动过程的知识在这里直接派上用场。整体思路是通过GRUB临时修改启动参数进入rescue target把根文件系统重新挂载为读写然后用passwd命令重置密码。操作步骤如下。在GRUB菜单选中启动项按e进入编辑模式。找到linux开头的行在行尾追加systemd.unitrescue.target如果文件系统是SELinux启用的还需要追加rd.break来提前断开但更保守的方式是直接进rescue。按Ctrlx启动进入rescue shell。挂载根文件系统可写mount -o remount,rw /sysroot切换到真实根目录chroot /sysroot执行passwd root设置新密码。关键额外操作修改密码后如果系统启用了SELinux需要执行touch /.autorelabel让下次启动时自动重新标记文件系统标签。否则SELinux可能阻止带新标签的/etc/shadow文件被读取造成密码修改无效或登录异常。退出chroot重启系统。这里有三个容易翻车的地方第一忘记mount -o remount,rw /sysroot直接chroot进去会发现文件系统是只读状态passwd命令报错第二忘记touch /.autorelabel重启后因为SELinux上下文错误无法正常启动第三在UEFI系统上多次编辑GRUB参数时不小心删掉了linuxefi行中的必要参数导致内核无法加载。这些细节在我实际带的团队新人身上都已经出现不止一次了。4.4 通过内核命令行参数绕过故障有些故障并不需要进入救援环境直接通过临时修改内核参数就能绕过。比如系统卡在某个挂载点无法启动而/etc/fstab里确实有一条错误配置你可以在GRUB编辑界面给内核追加emergency或systemd.unitrescue.target启动然后修改/etc/fstab。更精细的绕过方式是用参数systemd.mask服务名屏蔽掉某个故障服务或者systemd.wants服务名临时追加依赖。虽然这些手段在日常运维中用得不算频繁但在RHCSA考试里出现过类似场景某个服务导致图形界面无法启动要求考生临时屏蔽该服务以恢复系统。我们要知道屏蔽操作并不是彻底删除服务文件而是创建指向/dev/null的软链接恢复时可以systemctl unmask取消屏蔽。这套逻辑在启动过程中同样适用。5. 常见问题与排查技巧实录5.1 修改GRUB配置后立即重启却毫无变化这个问题出现频率极高。原因基本只有一个修改/etc/default/grub后没有运行grub2-mkconfig -o /boot/grub2/grub.cfg。有些同学改了文件以为保存就生效但GRUB2并不实时读取/etc/default/grub它只认编译出的grub.cfg。另外还需要确认当前系统到底是BIOS引导还是UEFI引导生成配置的目标路径不能搞混。可以在系统里执行ls /sys/firmware/efi来确认是否存在EFI运行时变量如果目录存在就是UEFI引导。如果确认路径没错、配置也重新生成了还是没有效果再检查GRUB_DEFAULT的设置值。有些菜单项名称包含空格和版本号你用grub2-set-default设置时输入的名称必须与grub.cfg中的menuentry标题完全一致差一个空格都会导致参数无效。5.2 默认target被更名后系统无限重启我在某次练习中手动把/etc/systemd/system/default.target这个软链接指向了一个自己创建的无效target文件重启后系统在启动早期阶段就报错并自动进入紧急模式。排查方式很简单在紧急模式下执行ls -l /etc/systemd/system/default.target检查链接指向然后用systemctl set-default multi-user.target重建软链接最后重启恢复。更隐蔽的情况是target依赖链里有服务单元缺失。此时系统虽然能进入某个target但启动过程会反复报Failed to start 服务名而且systemctl list-units --failed里能看到多个失败项。排查时先看失败的单元再顺着systemctl list-dependencies找到依赖源通常都是某个服务文件被误删或配置错误导致的连锁反应。5.3 SELinux与启动过程的相互作用启动过程控制中很少人意识到但SELinux安全策略异常本身就是启动失败的高频诱因。常见症状包括一切系统文件看起来都正常但服务启动时无法读写某些文件或者重启后直接卡在SELinux相关的错误提示。这种情况下进入救援模式或使用GRUB编辑追加selinux0临时关闭SELinux启动系统然后重新标记文件系统# 进入rescue环境后 mount -o remount,rw /sysroot touch /sysroot/.autorelabel # 退出并重启让系统在下次启动时重新生成SELinux标签autorelabel的过程可能比较耗时尤其是在文件很多的生产服务器上但这是保证SELinux策略正常应用的正确方式。考试里如果出现“修改过SELinux上下文重启后系统无法登录”这类题目十有八九是要用到.autorelabel这个文件。5.4 启动配置文件的备份与回滚习惯控制启动过程的所有操作都涉及系统关键配置文件一个低级的配置错误可能导致整机起不来。我在实际运维中给自己定了一个规矩修改/etc/default/grub、/etc/fstab、以及任何target相关配置之前先复制一份备份文件。cp /etc/default/grub /etc/default/grub.bak.$(date %F) cp /etc/fstab /etc/fstab.bak.$(date %F)这些备份文件体积小、成本低一旦操作失误可以迅速用grub2-mkconfig -o ...配合备份内容恢复配置而不需要进救援模式手动改回。尤其是fstab它是启动过程中极易出错的位置一个错误的UUID挂载配置足以让系统彻底卡死在挂载阶段。养成改前备份的习惯可以省下大量排障时间。5.5 我踩过的几个关键坑位最后分享几条从实际操作中总结的经验不一定写在教科书里但非常实用。第一不要在GRUB_CMDLINE_LINUX里随便追加关闭驱动的参数比如modprobe.blacklistxxxx设置容易、排查艰难。这类参数一旦出错网卡、磁盘控制器可能找不到系统会以非常诡异的方式启动失败日志里又没有直接报错指向该参数。排障时首先要想到把最近追加过的参数全部临时移除再逐个确认。第二使用systemctl set-default之前一定要确认target名称拼写。系统不会因为你输错了名字就友好提示它会在下次启动时找不到目标而进入紧急模式。排障时可以通过systemctl list-units --typetarget --all查看所有可用的target。第三在UEFI环境中修复GRUB的顺序非常重要。重新生成grub.cfg后如果仍然提示找不到引导文件先确认ESP分区是否挂载在/boot/efi再用efibootmgr -v查看固件中的引导项是否指向正确文件。有时候问题不在GRUB本身而是固件启动项丢失或顺序混乱需要重新创建引导项才彻底解决。启动过程控制这块知识平时安安静静躺在系统里但每次真出故障时它就是整个运维安全网的最后一根绳子。把这套流程想明白、练熟练比记住一两条孤立的命令有用得多。我自己的习惯是每周挑一台测试机故意制造一种启动故障然后强制自己用救援模式恢复反复几次之后遇到生产环境出问题手速和思路都会稳很多。