你刚升级完内核,重启。ssh 连不上,终端静得像死人。
第一反应是去控制台点开VNC,看到系统早过了grub菜单,卡在dracut shell那个提示符下——dracut:/#。敲ip a,空空荡荡,连lo都没有。dmesg翻几页,没有eth0,没有enp0s3,跟网卡从未存在过一样。
这种时候你多半会想:完蛋,内核崩了?其实八成不是内核的问题,是网卡驱动压根没被塞进initramfs。
升级完内核,网卡人间蒸发
症状很统一:刚才还活着的云服务器,重启后网络彻底瘫痪。ip a只回一个lo,ethtool报设备不存在,倒是通的——证明协议栈还在,是物理层没认出来。
查/var/log/messages或journalctl,十有八九能看到类似的日志,或者干脆啥都没有。
根因其实不复杂。你新内核的.ko模块文件已经装到/lib/modules/$(uname -r)/底下了,但dracut在构建initramfs时用的旧内核配置,没把新网卡驱动打进去。等内核启动到mount rootfs之前,它想加载驱动却找不到文件,网卡自然就失踪了。
这个问题在CentOS 7/8、Anolis 8这类用dracut做initramfs的发行版上特别常见——尤其是当你用yum update kernel升级之后,手一抖没跑dracut -f,或者跑的时候内核版本号对不上。
还有一类场景更隐蔽:你换了底层虚拟化平台,或云服务商迁移了宿主机,导致虚拟网卡型号变了(比如从virtio切到e1000e),而旧initramfs里只打包了老的驱动。新内核虽然自带驱动,但initramfs里没有,启动到一半就掉进dracut shell。

用GRUB埋个“断点”,进dracut shell翻东西
重启不是乱按的。你需要在GRUB引导菜单出现时,立刻按e进入编辑模式——别等它自动加载旧内核,否则又回到那个空荡荡的dracut提示符。找到以linux16或linux开头的那一行,在行尾加上rd.break参数。按Ctrl+X或F10启动。
rd.break是dracut提供的核心钩子,它会在initramfs加载完基本模块后、挂载真正的根文件系统之前,把执行权交给你。这时候你看到的提示符还是dracut:/#,但跟之前卡住不一样——这次是你主动停下来的,系统其实已经加载了一部分内核模块,只是还没切根。
如果你更激进一点,可以直接用rd.shell参数代替rd.break。两者的区别是:rd.break在指定阶段暂停,等你敲Ctrl+D才继续;rd.shell则在模块加载失败时自动弹出交互环境。对于网卡驱动丢失这种场景,我更倾向先用rd.shell——它能让你看到驱动加载失败的明确报错,而不是在黑屏里瞎猜。
注意
进到shell后第一件事:ls /lib/modules/$(uname -r)/kernel/drivers/net。如果这个目录不存在,或者里面找不到你的网卡驱动(比如e1000e.ko、igb.ko),那就坐实了——initramfs根本没打包新驱动。
再跑lspci -v | grep Ethernet确认网卡PCI ID,然后去/lib/modules/$(uname -r)/底下全局搜一下对应的.ko文件。搜到了?说明驱动文件本身是装了的,只是没被打包。搜不到?那你得先解决内核模块安装的问题,可能是新内核的kernel-devel没装全,或者yum update只更新了内核本体没更新firmware包。碰到这种情况,别在dracut shell里死磕,直接挂载ISO进救援模式更省事。

手动塞驱动、重建initramfs,然后祈祷
确认驱动文件存在后,别急着reboot。dracut不会自动把你刚发现的e1000e.ko或igb.ko塞进initramfs——它只打包“被声明需要”的模块。
先看驱动到底认不认得上
在dracut shell里跑:lsmod | grep -E 'e1000e|igb|ixgbe|virtio_net'。空?说明没加载。再试,如果报ERROR: Module e1000e not found in directory /lib/modules/$(uname -r),那不是打包问题,是模块压根没装全——回去补kernel-devel和firmware-linux包。
精准塞进去,不是瞎force
回到宿主机(或chroot后),执行:
dracut --force --add-drivers "e1000e igb virtio_net" --regenerate-all
注意:模块名不带.ko,多个用空格分隔;--regenerate-all确保所有内核版本都重做,避免只修了当前启动项却漏掉备用内核。
GRUB得同步更新
CentOS/RHEL系:运行grub2-mkconfig -o /boot/grub2/grub.cfg;Anolis OS或新系用grub2-mkconfig -o /boot/efi/EFI/anolis/grub.cfg。别跳这步——initramfs更新了,GRUB还指着旧镜像,重启照样黑屏。
做完这些,再进GRUB按e,删掉rd.break,Ctrl+X启动。如果eth0出来了,ip a能看到IP,说明驱动真进去了。那个瞬间比ping通还要踏实一点。
在dracut shell里临时联网,硬拉驱动
好,假设你reboot了,结果又掉进了dracut shell。这次lsmod一看,e1000e、igb、virtio_net一个都没。不是模块没塞进去,是驱动文件压根就不在/lib/modules/$(uname -r)里——之前chroot补的kernel-devel只装了头文件,没装firmware和驱动本体。
真的走到那一步也未必就死定了。dracut shell 虽然寒碜得只剩个命令提示符,但之前加的 net.ifnames=0 已经把 Predictable Network Interface Names 那套命名规则毙掉了,不出意外的话网卡接口还是老熟人 eth0。现在就一个问题:你这台机器上,还能找到另一块能正常联网的网卡吗?
我在腾讯云CVM上碰到过,云厂商提供的virtio_net驱动在新内核里被标记为“未签名”抑或直接丢包了,物理机没别的网口。那怎么联网?其实dracut shell自带了ip、ifconfig、route和dhclient,虽然busybox版本很丐,但配个静态IP够用。先看一眼当前网络状态:
ip a
必然是空的。如果能DHCP,直接试试——很多云环境的内网DHCP响应极快,一句命令就拿到IP。但我的场景是VLAN隔离,DHCP不给租约。手动配:
配完,不通?八成是网关配错了,或者eth0没启用。先再配地址,顺序别反。
网络通了,下一步是搞到驱动。dracut shell里没有wget?那就curl -O http://your-mirror/kmod-e1000e-3.8.7-1.el8.x86_64.rpm。如果镜像在内网,配好IP后直接拉;如果在外网,先确认DNS能解析——echo nameserver 8.8.8.8 > /etc/resolv.conf再试。
下载到/tmp后,用rpm -ivh安装,或者解压拿.ko文件:
rpm2cpio kmod-e1000e-3.8.7-1.el8.x86_64.rpm | cpio -idmv ./lib/modules/$(uname -r)/
depmod -a
modprobe e1000e
modprobe不报错的话,lsmod | grep e1000e应该能看到模块了。然后重新打包initramfs:
dracut --force --add-drivers "e1000e" --regenerate-all
这里注意:如果驱动依赖firmware(比如e1000e需要e1000.fw),你还得把firmware放进/lib/firmware下,否则modprobe会报firmware缺失。我就在这卡过半小时——驱动模块加载了,但网卡还是down,dmesg一看。
firmware在哪?RHEL系叫linux-firmware,CentOS 8以上是kernel-firmware。摘包单独放:
find /lib/firmware -name "*e1000*" -exec cp {} /tmp/firmware/ \;
cp /tmp/firmware/* /lib/firmware/
depmod -a
modprobe -r e1000e && modprobe e1000e
确认eth0能拿到link状态后,再跑一遍dracut打包,然后reboot。这次启动时盯着屏幕——如果看到[ OK ] Started Network之类字样,说明驱动真在initramfs里自举成功了。
顺带说个很多人会踩的坑:dracut shell 里配好的网络,重启直接清零。但只要驱动已经塞进 initramfs,后续 systemd-networkd 或者 NetworkManager 会自己把网络拉起来。慌啥,能救一次就值了。
CentOS和Anolis的坑,不是一个level
Anolis OS 8.8默认用kernel-5.10.134-19.an8,比CentOS 8 Stream的4.18.0-477陡然高了一大截。e1000e驱动在5.10里已合并进主干,但某些云厂商定制的igb或ixgbevf模块还没同步进Anolis的kernel-modules-extra包——你rpm -ql kernel-modules-extra | grep igb,可能压根没结果。
network服务早就不一样了
CentOS 7/8还靠/etc/sysconfig/network-scripts/ifcfg-eth0和systemctl restart network启网;Anolis 8.8默认关掉,只认systemd-networkd + udev rule。dracut shell里systemctl restart network没用,得写/run/systemd/network/10-eth0.network才能被后续接管。别抄CentOS的旧配置,systemd-networkd会直接ignore。
Secure Boot不是摆设
阿里云Anolis镜像默认开启Secure Boot。你modprobe成功、dracut --force打包完,重启还是没网?dmesg | grep -i "signature"一查,八成是e1000e.ko未签名。CentOS下签个kmod就行,Anolis得用mokutil --import /path/to/MOK.der,再进BIOS确认MOK密钥——漏这步,initramfs里模块直接被内核拒载。
升级前花两分钟,省掉凌晨三点的手忙脚乱
升级内核前顺手看一眼 initramfs 里有没有网卡驱动,比半夜三点对着 dracut shell 发愣强太多了——那玩意儿真能把人治得死死的。两分钟看一眼的事。
先保命:/boot和/lib/modules必须打包存档
升级前执行:tar -czf /root/kernel-backup-$(uname -r).tgz /boot /lib/modules/$(uname -r)。Anolis 8.8的/lib/modules/5.10.134-19.an8目录若为空,dracut --force就会退向通用模块集,e1000e或ixgbevf都进不去initramfs。
再验证:dracut --force不是仪式,是预演
升级新内核后,立刻跑:dracut --force --regenerate-all,然后lsinitrd /boot/initramfs-$(uname -r).img | grep -E "(e1000e|igb|ixgbevf)"。没输出?说明驱动没进去,别急着reboot。
最后兜底:GRUB里留个旧内核不删
grubby --set-default /boot/vmlinuz-4.18.0-477.el8.x86_64 —— 这条命令在Anolis上照样生效。Secure Boot开着也别怕,MOK密钥已导入过一次,旧内核签名依旧有效。
真要是所有办法都试过了还是不行,那就老老实实挂载ISO进救援模式,把旧内核的initramfs拷过来先用着——总比对着黑屏抓瞎强。





评论