服务器重启之后不起来了。屏幕上要么是 grub rescue>,要么是刷一堆 dracut 报错后掉进 emergency shell。这种时候最忌讳的就是乱试命令——搞清楚卡在启动的哪一步,问题就解决一半了。
启动的四个阶段
定位的第一步是判断停在哪:
- 固件/硬件 — 加电、POST、找启动设备。表现为黑屏、找不到启动盘、RAID 卡报错。
- GRUB(引导加载器) — 加载内核和 initramfs。表现为
grub>或grub rescue>提示符。 - 内核 + initramfs — 内核启动,initramfs 里加载驱动、挂载根文件系统。表现为卡在
dracut、找不到根设备、掉进emergency/initramfsshell。 - 用户态(systemd) — 挂载 fstab、起服务。表现为能进 emergency 模式、某个服务卡住、文件系统只读。
每一阶段的现象和修法完全不同,先对号入座。
阶段二:GRUB 挂了
grub rescue>
长这样:
error: unknown filesystem
grub rescue>
通常是因为 GRUB 找不到它的配置文件或模块目录(/boot/grub2 丢了、分区号变了、或者磁盘顺序变了)。
先摸清有哪些盘和分区:
ls # 列出类似 (hd0) (hd0,msdos1) 的设备
ls (hd0,msdos1)/ # 逐个试,找哪个里面有 boot/ 或 grub2/
找到 /boot 所在分区后,手动引导:
set root=(hd0,msdos1)
set prefix=(hd0,msdos1)/grub2 # 注意路径,有的系统是 /boot/grub2
insmod normal
normal
如果能进系统了,进去之后必须重装 GRUB,否则下次重启还是一样:
# BIOS 引导
grub2-install /dev/sda
grub2-mkconfig -o /boot/grub2/grub.cfg
# UEFI 引导(EFI 分区挂在 /boot/efi)
grub2-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=centos
grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
重装前确认 grub2-install 的目标是整块盘(/dev/sda)不是分区(/dev/sda1)。写错位置可能把分区表搞坏。
用救援环境重装
如果手动引导也进不去,用安装盘/ISO 进救援模式(Troubleshooting → Rescue a CentOS system),它会自动把原系统挂到 /mnt/sysimage:
chroot /mnt/sysimage
grub2-install /dev/sda
grub2-mkconfig -o /boot/grub2/grub.cfg
exit
reboot
chroot 是关键——不切进去的话,grub2-install 会用救援环境的内核和模块,装出来的东西对不上。
阶段三:内核与 initramfs
卡在 dracut,找不到根设备
典型报错:
dracut: Warning: /dev/mapper/centos-root does not exist
几种常见原因:
1. initramfs 里缺存储驱动
典型场景:换了 RAID 卡、或者在 A 机器上做的系统盘插到 B 机器上,initramfs 里没有新机器的磁盘驱动。
修法:进救援环境,chroot 之后重建 initramfs:
chroot /mnt/sysimage
# 先备份
cp /boot/initramfs-$(uname -r).img /root/initramfs.bak
dracut -f /boot/initramfs-$(uname -r).img $(uname -r)
如果是为了加特定驱动(比如某 RAID 卡):
dracut --add-drivers "megaraid_sas" -f /boot/initramfs-$(uname -r).img $(uname -r)
2. 根设备路径变了
GRUB 配置里写的是 root=/dev/sda2,但磁盘顺序变了,sda 变成了 sdb。这种情况改用 UUID 最稳:
blkid # 看根分区的 UUID
然后编辑 /etc/default/grub:
GRUB_CMDLINE_LINUX="... root=UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ..."
再 grub2-mkconfig -o /boot/grub2/grub.cfg。用 UUID 而不是设备名,是避免这类问题的根本办法。
临时救急也可以在 GRUB 启动界面按 e 编辑内核参数,改完 Ctrl+X 启动,但那是临时的,进去后要改配置文件。
3. LVM 卷没激活
# 在 initramfs/emergency shell 里
lvm vgscan
lvm vgchange -ay # 激活所有卷组
exit # 继续启动
阶段四:用户态
fstab 写错
能进系统但掉进 emergency mode,屏幕上提示输入 root 密码。最常见的原因是 /etc/fstab 里有一项挂载失败(UUID 写错、设备不存在、NFS 服务器连不上)。
# 输入 root 密码后
mount -o remount,rw / # 根分区可能是只读的,先改成可写
vi /etc/fstab
# 把出错的那行注释掉或修正
mount -a # 测试能不能全部挂载成功
关键经验:给非关键的挂载项加 nofail,这样它挂不上也不会阻断启动:
UUID=xxxx /data ext4 defaults,nofail,x-systemd.device-timeout=10s 0 2
NFS/CIFS 这类网络挂载尤其要加,否则网络不通就起不来。x-systemd.device-timeout 限制等待时间,避免卡 90 秒的默认超时。
文件系统损坏
# 在 emergency 或救援环境下,先卸载再修
umount /dev/sdb1
fsck -y /dev/sdb1
# XFS 用 xfs_repair(xfs 不能 fsck)
xfs_repair /dev/sdb1
# 损坏严重时先 -L 清空日志(会丢最后一点数据,不得已才用)
xfs_repair -L /dev/sdb1
fsck 一定要在卸载状态下跑,对已挂载的文件系统做检查会把数据搞得更糟。XFS 的 -L 会丢弃日志,可能丢数据,用之前先确认有没有别的办法(比如从备份恢复)。
某个服务卡住启动
systemctl list-jobs # 看卡在哪个 job
systemctl status <服务名>
journalctl -xb # 看本次启动的日志
systemctl disable <问题服务> # 先禁掉,让系统起来再说
systemctl reset-failed
也可以临时用内核参数跳过:systemd.unit=rescue.target 或 emergency,或者 systemd.mask=xxx.service。
诊断信息的获取
进了 emergency 之后,最有用的几条:
journalctl -xb # 本次启动日志,-x 带解释,-b 本次
journalctl -k # 只看内核日志(等同 dmesg)
systemctl --failed # 失败的单元
dmesg | grep -i error # 硬件/驱动层错误
如果系统完全起不来、日志也看不到,就得靠安装盘的救援模式,进去之后日志在 /mnt/sysimage/var/log/ 下。
防患于未然
几件成本很低但关键的事:
- fstab 用 UUID,别用
/dev/sdX,并给非关键项加nofail - 改 fstab 之后必跑
mount -a验证,确认没问题再重启 - 动 GRUB 配置前备份
grub.cfg;改完用grub2-mkconfig而不是手改grub.cfg(后者会被覆盖) - 重大变更(换 RAID 卡、迁移硬盘、改分区)之后,先在救援环境验证能启动,别等到真需要重启时才发现
- 保留一份可启动的 ISO/救援盘,云主机要确认有没有 VNC/串行控制台可用——没有控制台的话,grub rescue 基本只能靠重装
最后这条是血的教训:云主机如果连不上控制台,很多启动故障你是没法救的,只能重装。所以备份比救援技术重要。