服务器按开机键到出现登录提示符,中间不过几十秒,但这几十秒里发生的事情,往往决定了它能不能正常起来。很多运维新手遇到"服务器卡在某个界面不动了""开机进了紧急模式""改了个内核参数结果起不来了",第一反应是重装系统,其实只要理解启动链路,绝大多数问题都能在几分钟内定位并修复。
这篇文章把 Linux 从按下电源到服务跑起来的完整路径拆开讲:固件(UEFI 或传统 BIOS)如何找到引导程序,GRUB2 如何加载内核和 initramfs,内核如何挂载根文件系统并把控制权交给 systemd,systemd 又是如何拉起一个个服务的。中间会给出 GRUB 配置、救援模式进入方法,以及用 systemd-analyze 分析启动耗时的实操。看完你应该能读懂启动日志,知道每一步失败时该看哪里、改哪个文件。
启动链路全景
一台 x86 服务器的启动顺序,可以归纳成下面这条链路,任何一环出问题,表现都不一样:
| 阶段 | 执行者 | 主要动作 | 出问题的典型现象 |
|---|---|---|---|
| 固件自检 | UEFI 或 BIOS | 硬件初始化、POST 自检 | 无显示、蜂鸣、找不到启动设备 |
| 引导加载 | GRUB2 | 读取配置,加载内核与 initramfs | 出现 grub> 提示符、菜单不见 |
| 内核初始化 | 内核 + initramfs | 探测硬件、挂载根文件系统 | 卡在 Loading initial ramdisk、报找不到根设备 |
| 根切换 | initramfs 的 init | switch_root 到真实根 | 报 Cannot open root device |
| 系统初始化 | systemd(PID 1) | 按 target 启动服务 | 进 emergency/rescue 模式、服务失败 |
| 登录 | getty 或 sshd | 提供登录界面 | 能 ping 通但没有登录提示符 |
理解这条链的关键是:每一步都在为下一步准备条件。固件的工作是找到引导程序,GRUB 的工作是找到内核,内核的工作是找到根文件系统,systemd 的工作是按依赖关系启动服务。排查时只要知道现象落在哪一段,就缩小了范围。
固件:UEFI 与传统 BIOS
固件是主板上电后运行的第一段程序。传统 BIOS 和现代的 UEFI 差别很大:
- 传统 BIOS(Legacy) 从磁盘第一个扇区读取 512 字节的 MBR,再跳转到 GRUB 的第一阶段,容量极其受限,于是有了多阶段引导的设计。分区表最多识别 2TB,且只能用 MBR。
- UEFI 从 EFI 系统分区(ESP,通常是 FAT32 格式,挂在
/boot/efi)读取.efi可执行文件,典型路径是/boot/efi/EFI/centos/grubx64.efi、/boot/efi/EFI/rocky/grubx64.efi或/boot/efi/EFI/ubuntu/grubx64.efi。UEFI 支持 GPT 分区表(突破 2TB 限制),启动过程更标准。
判断当前机器用的是哪种模式,最简单的一条命令:
ls /sys/firmware/efi
# 目录存在 => UEFI 启动
# 提示 No such file or directory => Legacy BIOS 启动
也可以查看是否挂载了 ESP:
mount | grep -i efi
df -hT /boot/efi
为什么要在意这个:GRUB 的安装命令在两种模式下完全不同。UEFI 模式下,重装引导要用 grub2-install --target=x86_64-efi(Debian 系为 grub-install --target=x86_64-efi);Legacy 模式下则针对具体的磁盘设备如 /dev/sda。装错目标会导致机器开不了机,所以动引导之前务必先确认模式。
固件阶段的常见故障:设置了错误的启动顺序导致找不到系统盘;UEFI 安全启动(Secure Boot)把未签名的第三方驱动拦下;CMOS 电池没电导致 BIOS 设置丢失。这类问题的处理入口在服务器的带外管理(IPMI、iDRAC、iLO)里,可以远程进入固件设置界面调整。
GRUB2:引导加载程序
GRUB2 是现在绝大多数发行版默认的引导程序。它要完成三件事:显示启动菜单、加载内核(vmlinuz)和初始内存盘(initramfs 或 initrd)、把内核命令行参数传给内核。
关键配置文件位置
这里有个新手最容易踩的坑:GRUB 的主配置 /boot/grub2/grub.cfg 是自动生成的,不要手改,因为它会被覆盖。要改的是这些源文件:
# RHEL / CentOS / Rocky:全局默认参数
/etc/default/grub
# RHEL / CentOS / Rocky:菜单项与内核相关的定制脚本
/etc/grub.d/40_custom
# Debian / Ubuntu:同样是这两个位置
/etc/default/grub
/etc/grub.d/40_custom
/etc/default/grub 里最常改的两行:
GRUB_TIMEOUT=5
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=vg0/root rd.lvm.lv=vg0/swap rhgb quiet"
GRUB_TIMEOUT是菜单停留秒数。调试时改成 10 或 30,方便手动选择。GRUB_CMDLINE_LINUX是会传给内核的参数,比如console=ttyS0开启串口输出(物理机远程调试很有用)、rd.lvm.lv=指定 LVM 根卷、quiet减少内核打印。
修改后的生效命令
改完 /etc/default/grub 后,必须重新生成 grub.cfg,两个发行版系命令不同:
# RHEL / CentOS / Rocky(BIOS 与 UEFI 通用)
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
# RHEL / CentOS / Rocky,UEFI 环境通常也会生成到 EFI 分区
sudo grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
# Debian / Ubuntu
sudo update-grub
# 等价于:sudo grub-mkconfig -o /boot/grub/grub.cfg
风险提示:重新生成 grub.cfg 前,建议先备份 /boot/grub2/grub.cfg(或 /boot/grub/grub.cfg)。如果生成过程报错而原文件已被覆盖,机器可能无法启动。备份命令:
sudo cp /boot/grub2/grub.cfg /boot/grub2/grub.cfg.bak
进入 GRUB 命令行与编辑模式
开机时在菜单界面按 e 可以临时编辑启动项,按 c 进入 GRUB 命令行。这些改动只在本次启动生效,不会写盘,是排查问题的安全手段。比如忘记了 root 密码,就可以在启动项的内核行末尾加上 rd.break(RHEL 系)或 init=/bin/bash(通用),进系统后重置密码。
内核与 initramfs
GRUB 把内核(/boot/vmlinuz-*)和 initramfs(/boot/initramfs-*.img 或 /boot/initrd.img-*)加载进内存后,内核开始执行。它要做的最关键一步是挂载根文件系统。
问题在于:根文件系统可能位于 LVM 逻辑卷、LUKS 加密卷、软 RAID 或网络存储上,内核本身并不包含这些复杂存储所需的所有驱动。为了不把内核做得臃肿,Linux 引入了 initramfs——一个包含了必要驱动和工具的小型内存文件系统,先被内核加载,再由它来把真正的根挂起来,最后通过 switch_root 切换到真实根。
# 查看当前使用的内核
uname -r
# 查看 initramfs 与内核文件
ls -lh /boot/vmlinuz-* /boot/initramfs-*
# 重新生成 initramfs(硬件或存储配置变化后常用)
# RHEL / CentOS / Rocky
sudo dracut -f
# Debian / Ubuntu
sudo update-initramfs -u -k all
什么时候必须重建 initramfs:更换了存储控制器、调整了 LVM 结构、给根卷加了加密、或者升级内核之后。如果 initramfs 里缺少新硬件的驱动,内核就会报 Cannot open root device 或 Unable to mount root fs,然后掉进 initramfs 的救援 shell(通常是 (initramfs) 提示符)。
内核启动早期的日志不会写入磁盘,而是输出到控制台和环形缓冲区。排查启动早期问题可以用:
dmesg | head -n 60
journalctl -k -b # 本次启动的内核日志
journalctl -k -b -1 # 上一次启动的内核日志
-b 参数指定启动次数,-b -1 表示上一次启动,这对分析"上次为什么没起来"特别有用。
systemd:PID 1 与 target
内核挂载根文件系统后,会启动第一个用户态进程,也就是 PID 1。在几乎所有现代发行版上,这个进程就是 systemd。你可以验证:
ps -p 1 -o comm=
# 输出 systemd
systemd 的启动模型和传统的 SysV init 完全不同。传统 init 是按顺序一条条执行 rc 脚本,慢且难以并行;systemd 用单元(unit)来描述资源,用依赖关系来决定启动顺序,能并行的尽量并行。
systemd 用 target 来表示"系统的状态"。传统运行级别和 target 的对应关系如下:
| 传统运行级 | 对应 target | 含义 |
|---|---|---|
| 0 | poweroff.target | 关机 |
| 1 | rescue.target | 单用户救援模式 |
| 3 | multi-user.target | 多用户、命令行、无图形 |
| 5 | graphical.target | 多用户、带图形界面 |
| 6 | reboot.target | 重启 |
服务器最常见的目标是 multi-user.target。查看和切换:
systemctl get-default # 查看默认 target
sudo systemctl set-default multi-user.target # 设为命令行启动
systemctl list-units --type=target # 列出当前激活的 target
系统从 default.target 出发,根据依赖把需要的服务一个个拉起。想直观看到这棵依赖树:
systemctl list-dependencies multi-user.target | head -n 40
systemd-analyze critical-chain # 只看关键路径
启动耗时分析:systemd-analyze
这是 systemd 相比传统 init 最实用的诊断能力之一。三条命令就能把启动过程量化:
systemd-analyze
# Startup finished in 2.318s (firmware) + 3.912s (loader) + 4.021s (kernel) + 21.766s (userspace) = 32.018s
输出把时间拆成了固件、引导加载、内核、用户空间四段。如果用户空间占了大头,就往下看服务级耗时:
systemd-analyze blame | head -n 20
blame 按耗时从高到低列出每个服务的初始化时间。常见耗时大户有 NetworkManager-wait-online.service(等待网络就绪,开了 DHCP 的机器可能等几十秒)、plymouth-quit-wait.service(等待开机动画)、cloud-init 相关服务等。
systemd-analyze critical-chain
critical-chain 显示的是关键路径——真正决定总耗时的那条依赖链,用 @ 标出每个服务的激活时刻。如果某个服务很耗时但不在关键路径上,说明它和其他服务并行执行了,不影响总时间,优化它是白费功夫。想看图形化瀑布图还可以生成 SVG:
systemd-analyze plot > boot.svg
救援模式:进不去系统怎么办
当根文件系统被改坏、GRUB 配置错误、fstab 写错导致挂载失败时,系统会掉进 emergency 或 rescue 模式,或者干脆卡住。几种进入救援的方式:
- GRUB 菜单加
rd.break(RHEL 系):在菜单里按e编辑启动项,在内核行末尾加rd.break,按Ctrl+X启动,会进入 initramfs 的 shell,此时真实根挂载在/sysroot。 - 加单用户参数:在内核行末尾加
single或1,进入 rescue.target。 - 加
systemd.unit=emergency.target:进入最小化模式,只挂载根文件系统为只读。
以 RHEL 系重置 root 密码为例(物理或带外控制台操作):
# 1. GRUB 菜单按 e,内核行末尾加 rd.break,Ctrl+X 启动
# 2. 进入 initramfs shell 后
mount -o remount,rw /sysroot
chroot /sysroot
passwd root
touch /.autorelabel # 若开启了 SELinux,必须执行,否则改密后登录不了
exit
exit # 或 reboot
注意 touch /.autorelabel:开启了 SELinux 的系统,改完密码后文件上下文可能不对,重启时让系统重新打标签,否则会出现密码正确却登不进去的怪事。
如果连 GRUB 菜单都进不去(比如 grub.cfg 损坏),可以用发行版安装盘启动,选择"救援模式"(Rescue a CentOS/Rocky Linux System),挂载现有系统后 chroot 进去修复。
# 在救援 shell 里
mkdir -p /mnt/sysroot
mount /dev/mapper/vg0-root /mnt/sysroot
mount /dev/sda1 /mnt/sysroot/boot # 视分区而定
chroot /mnt/sysroot
# 在此修复 grub、fstab 等
常见问题
修改 grub 后重启进了 grub> 提示符,怎么救?
这说明 GRUB 找不到 grub.cfg 或根分区。先别慌,在 grub> 里手动引导、确认设备,再用救援盘启动进 chroot,重新执行 grub2-mkconfig 和 grub2-install。所以改引导配置前一定要备份,并且最好留一个能进救援的带外通道。
改了 /etc/fstab 重启后卡在 emergency 模式?
多半是 fstab 里的 UUID 或设备名写错、或者被挂载的分区不存在。救援模式下以读写方式重挂根分区(mount -o remount,rw /),修正 fstab。建议在 fstab 中给非关键挂载加 nofail 选项,避免一个挂载失败拖垮整个启动。
systemd-analyze blame 里某项特别慢,能直接禁掉吗?
要先确认它是否在 critical-chain 的关键路径上。不在关键路径上的耗时项禁掉不会加速启动;在关键路径上的服务要搞清它的作用再决定,盲目 systemctl disable 可能导致网络、存储等基础设施起不来。
内核升级后多了几个启动项,怎么清理?
旧内核会占用 /boot 空间,满了会导致新内核装不进、更新失败。RHEL 系可用 package-cleanup --oldkernels --count=2(需 yum-utils)保留最近两个;Debian 系用 apt autoremove 清理旧内核。清理前确认当前内核版本,别把正在用的删了。
UEFI 和 Legacy 能在同一台机器上混用吗?
可以,但每个磁盘只能选一种模式引导,混用容易乱。安装系统时就要定好模式,之后的救援盘、GRUB 安装命令都要对应。判断方法前面给过:ls /sys/firmware/efi。
总结
- 启动链路是"固件找引导 → 引导找内核 → 内核找根 → systemd 拉服务",排查时先按现象定位到哪一段,再看对应的日志。
- 改 GRUB 要改
/etc/default/grub这类源文件,再用grub2-mkconfig -o ...(RHEL 系)或update-grub(Debian 系)生成,动之前先备份 grub.cfg。 - 存储结构或内核变化后要重建 initramfs,否则可能报找不到根设备;
dmesg和journalctl -k -b -1是排查内核期问题的关键工具。 - 用
systemd-analyze、blame、critical-chain量化启动耗时,只优化关键路径上的服务才有效。 - 进不去系统时优先用
rd.break、single或安装盘救援模式修复;改完密码记得处理 SELinux 标签,fstab 里的非关键挂载加nofail防拖垮启动。
企业QQ咨询




