凌晨三点,手机震醒。屏幕上跳出一条告警——服务器失联了。你翻身坐起,打开笔记本,SSH 连不上,VNC 进去只看到一个冷冰冰的提示符:dracut:/#。所有重启操作都把你拉回这个 shell,救援模式根本进不去。
凌晨三点,云服务器卡在dracut shell
这类场景其实挺常见的,但发生在云服务器上就特别棘手。你没有物理机箱可插 U 盘,没有 IPMI 能挂载 ISO,甚至云厂商提供的救援模式都在启动过程中自己就挂了。我碰到过两次,一次是自己搭的 CentOS 7 测试机在迁移磁盘后崩了,另一次是客户的 Anolis OS 8 生产实例,因为 kernel 升级时 initramfs 没重新生成,重启就再也起不来了。
你面对的就是这样一个局面:内核已经加载了,但根文件系统挂不上——要么是 GRUB 配置把 root 指向了错的磁盘 UUID,要么是 initramfs 里缺了必要的存储驱动。云厂商的串行控制台或 VNC 是你唯一的眼睛和手。没有救援盘,没有 live CD,你得在这个 dracut shell 里从零搭出一条路,把 GRUB 修回来。
先别急着敲命令,把现场信息抓到手里
现在你坐在 dracut 那个简陋的提示符前面,别急着敲命令重启。先把呼吸放稳,我们只需要做几件很小的事,把现场信息抓到手。很多时候,问题并不复杂——只是 kernel 拿到的 root= 参数对不上真实的磁盘布局,或者是 initramfs 里少了某个存储驱动,导致它认不出这片云上的块设备。
看一眼内核命令行
第一件事,读一读当前内核是怎么起的。执行 ,你会看到一串由空格分隔的参数,其中最关键的就是 root= 指向的设备。把它抄下来:是 /dev/vda1 还是 UUID=...?有时你会发现它指向了一个不存在的分区,或是 LVM 逻辑卷名对不上。记住这几个参数,它们会被后面的 GRUB 配置和 initramfs 生成逻辑反复引用。
让盘和分区说话
接着,让设备开口。运行 lsblk -f 列出所有块设备及其挂载点、文件系统类型;再用 blkid 核对每个分区的 UUID 与 /dev/disk/by-uuid/ 下的符号链接是否一致。如果你的云盘做了加密或多路径,留意设备名是否会在重启后发生变化——这直接解释了为什么上一次还能起,这一次就起不来。
有时候你会发现自己多了一个 sda 或者 nvme0n1,但原来的 /boot 却在 /dev/vda 上。这种情况多半是云平台给你热挂了额外磁盘,或者你的块设备被重新枚举了。把这些记下来,后面要用。
把最近的报错翻出来
如果现场还能联网,试着把日志抓回来:dmesg | tail -200 会把内核环缓冲里最近的消息打出来,关注那些带着 error、failed、timeout 的行;再配上 journalctl -xb | grep -i "error\|failed"(有些 minimal initramfs 没有 journalctl,那就跳过)。你会看到类似 “cannot find device”、“volume group not found”、“mount: wrong fs type” 这样的线索,它们会直接把你带到下一章该重建 initramfs,还是该修正 GRUB 配置这两个方向之一。
翻日志时别只看 kernel 的,也看看 udev 是不是报了什么设备超时。我遇到过一次情况是 virtio-blk 模块没加载,导致 vda 整个不出现,最后靠手动 modprobe 才找到根分区。
手动挂载根文件系统,从dracut shell进入chroot环境
现在你手上有了一份诊断报告——知道了设备名、UUID,也大概猜到了是 initramfs 里缺驱动还是 GRUB 配置错了。但不管哪一种,你都得先「进去」你的原系统,才能动手修东西。dracut 给你留了个 /sysroot 目录,它就是设计好让你挂载根分区用的。我们来把这个动作做完。
先确认根分区设备。假设它就是 /dev/vda1(如果你的不一样,换成 lsblk 看到的那个)。
如果这一步出错——比如提示 wrong fs type、bad superblock——那问题就多了一层:文件系统可能已经坏了。别慌,先试试修复。XFS 用 ,ext4 用 。跑完后再次尝试挂载。修文件系统这件事,说简单也简单,就是跑一把修复工具,但坑在于云盘的根分区在 dracut shell 里通常不是以只读方式挂载的,所以你可以直接修,不用先 umount。
挂载成功后,把虚拟文件系统也挂进去,这样才能让 chroot 后的环境有进程信息、设备节点和内核接口。
这一套动作做完,你的 /sysroot 目录就已经是一个活的根文件系统了。验证一下:ls /sysroot/bin 应该能看到 bash、ls 这些;ls /sysroot/sbin 里应该有 grub2-install 或 grub-install。如果 bin 和 sbin 是空的——说明你很可能挂错了分区,或者这个分区根本不是根。
然后就是最后一步:切进去。
你会发现提示符变了,你现在已经在原来的系统里了。dracut 那个简陋的 shell 已经被你甩在身后。这时候你就拥有了完整的系统工具链——yum、grub2-mkconfig、dracut 本体都在手边,想重建 initramfs、重装 GRUB 还是改 /etc/default/grub,都随你了。
但万一你发现 chroot 之后连 ls 都用不了,或者报 chroot: failed to run command '/bin/bash': No such file or directory,那通常说明你挂载的根分区里 /lib64 下缺动态链接库——或者根本就不是标准 Linux 发行版的根。这时候回头检查一下挂载点是不是对的,或者用 file /sysroot/bin/bash 看看它是不是 ELF 文件。
一条经验:云厂商的救援模式(如果他们给你留了的话)往往自动帮你做了这套挂载动作。但你现在是自己动手,每一步都得自己确认。进了 chroot 之后,先跑个 df -h 看一眼分区挂载情况,再跑个 mount 看看虚拟文件系统有没有漏掉。少一个 /proc,后面跑 grub2-install 就会报奇怪的权限错误。别问我怎么知道的。
重建initramfs:从零生成正确的initramfs
进到 chroot 之后,第一件事就是确认你到底要给哪个内核生成 initramfs。云上常见的尴尬是:主机商把旧内核留在 /boot,但默认启动的却是另一个,结果 rescue 环境里 uname -r 和 ls /boot 对不上。先看一眼实物:ls /boot/vmlinuz*,再核对当前运行的 uname -r。别偷懒,这一步决定你后面是不是白忙活。
先把命令跑起来
最直接的两条:
若 dracut 报 command not found,就手动指定一条:dracut -f /boot/initramfs-$(uname -r).img $(uname -r)
--regenerate-all 会扫 /boot 把所有 vmlinuz* 对应的 initramfs 都重跑一遍;-f 则是强覆盖。云厂商的黑科技(virtio、xfs、网络根)都在 initramfs 里,不重跑,后面重启还是卡 dracut shell。
缺包与模块的坑
dracut 本体不在 rescue 镜像里很常见,尤其是 Anolis OS 或精简过的 CentOS 救援模式。解决办法有两个:要么从网络源装 dracut,要么用 host 里现成的 /usr/bin/dracut。我一般选择后者,省得救一半断网。记得把 /etc/ld.so.cache 也挂上,不然 dracut 可能找不到新装的库。
生成时盯着屏幕,看到 “Building image…” 那一行才算稳。中间如果报 “Missing module xfs”,说明你没装 xfs 驱动;云盘常用 virtio_blk、virtio_scsi、virtio_net,一个都不能少。把它们写到配置文件里最省心:echo "add_drivers+=' virtio virtio_blk virtio_scsi virtio_net xfs '" > /etc/dracut.conf.d/99-cloud.conf,然后再跑一遍 。
看一眼里面是不是真的有料
别急着 reboot,先用 file /boot/initramfs-$(uname -r).img 确认它是 gzip cpio 格式;再用 lsinitrd /boot/initramfs-$(uname -r).img | grep -E 'virtio|xfs' 检查关键模块在不在。lsinitrd 比手工解压快得多,也更直观。看到 lib/modules/$(uname -r)/kernel/drivers/block/virtio_blk.ko 存在,心里就踏实一半。
第一次在阿里云翻车,就栽在 initramfs 里缺了 virtio_net。root 挂在 NFS 上,系统直接卡死在 dracut shell——那会儿还不懂怎么手动 rescue,只能干瞪眼。后来学乖了,重跑完 initramfs 顺手敲个 lsinitrd 扫一眼,十秒钟的事,比摸着黑重启半小时舒服太多。
全部搞定后再执行 ,让引导菜单也跟上节奏。做完这些,exit 退出 chroot,umount /sysroot 那些临时挂载点,reboot 就能看见熟悉的登录提示符——而不是永远停在 dracut sh#。
修复GRUB引导:从chroot内重建GRUB配置和引导加载器
initramfs 能跑起来,只能说救回了一半,真正的大活儿还在 GRUB 这边。不少人以为切进 chroot 就稳了,老实说,每次看到有人这么想我都替他捏把汗——chroot 里一个路径写歪,reboot 就直接砸进 grub rescue>,第二阶段核心文件根本不在它该待的地方,这我可见过不止一次。
先跑 。注意,这步不能省,也别指望 BIOS 能自己猜出内核路径。输出的 grub.cfg 里,重点检查每个 menuentry 下的 root= 参数——它指向的 UUID 必须跟 blkid 显示的一致。云盘有时候会被重新枚举,比如从 /dev/vda 变成 /dev/vdb,UUID 才是唯一靠谱的锚点。如果发现 UUID 不对,别偷懒,手动改回来,不然下次启动又卡在 dracut:/#。
UEFI 和 BIOS 的 grub2-install 不是一回事
这一步最容易翻车。不是每台云服务器都是传统 BIOS 引导,阿里云 2019 年后的实例、腾讯云的标准型 S5 都默认走 UEFI。你得先确认:[ -d /sys/firmware/efi ] 返回真,那就跑:
grub2-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=grub
别漏掉 --efi-directory,它指向 ESP 分区挂载点。如果你之前没挂 /boot/efi,赶紧补上:(vda1 得看你实际的 ESP 分区号)。装完用 看一眼,应该能看到 grub 的条目排在第一位。
传统 BIOS 就简单些: 直接写 MBR。但有个坑——云盘的扇区大小有时是 4K 物理扇区,grub2-install 可能会报 grub2-install: warning: Sector 32 is already in use by the program 'FlexNet',这时候加个 --force 参数能绕过去,但前提是你确认磁盘分区表是 GPT 且有 BIOS boot partition(通常 1MB 大小)。没有的话,老老实实 parted 划一个出来再装。
grub.cfg 里藏着最后的防线
装完引导器,别忘了再检查一遍 /boot/grub2/grub.cfg。我习惯 grep 一下 linux 开头的行,看 root= 后面跟的是 UUID 还是 /dev/vda 这种设备名。设备名在云环境里很脆弱——热迁移或换盘后设备号可能变,UUID 则稳如狗。另外确认 rd.lvm.lv= 这些参数没被 grub2-mkconfig 吃掉。之前有个案例:Anolis OS 8 的 grub2-mkconfig 自动去掉了 rd.lvm.lv,导致 LVM root 起不来,手动补回去才救活。
完事后 exit 退出 chroot,umount -a 清干净临时挂载,然后 reboot。祈祷吧——但,只要 initramfs 模块齐全、grub.cfg 里的 UUID 没跑偏、grub2-install 没报错,基本不会出幺蛾子。看到 GRUB 菜单弹出来的那一刻,你就能松口气了。
重启验证与预防:避免下次再卡dracut
退出 chroot 之前,先把临时挂载清干净,尤其是 /dev、/proc、/sys、/run 这些 bind 挂载点,否则 reboot 会抱怨“忙设备”。我习惯按这个顺序收尾:先 exit 离开 chroot,再依次 (如果有 ESP)、umount /dev、、umount /sys、umount /mnt,最后才 reboot -f 强制起跳。云厂商的实例有时会把控制台输出吞掉,重启后屏幕可能仍停在 dracut shell;这时别慌,多半是 initramfs 里缺模块或 grub.cfg 里的 root=UUID 指歪了。真遇上了,把本系列准备的自定义 initramfs 再用一次,进救援模式比盲猜省事得多。
预防永远比救火便宜。/boot 分区一旦被删,系统立刻退化成砖;每周 rsync 一次 /boot,或者干脆给快照策略加一条“包含 /boot”,就能避开九成灾难。每次升级内核后,顺手跑 重建 initramfs,再调用 生成最新 menuentry;这两个动作加起来不到十秒,却能把“更新完就起不来”的经典坑填平。
如果业务机器分布在多家云商,记得把 serial console 写进 defaults:在 grub.cfg 的每个 menuentry 里补上 console=ttyS0,115200n8,并在 kernel 行保留 earlyprintk=serial,0x3f8,115200,这样启动异常时能通过串口拿到第一手日志,而不用守着机房 KVM 发呆。
下次再撞上引导炸了、屏幕飘满 panic 的场景,你大概率不会像我第一次那样手忙脚乱翻两天文档——备好脚本和笔记,这事儿其实就几个命令的事。
评论