你用云镜像(cloud image)建了一台虚拟机,平台里网络配置写得清清楚楚,可机器起来后网卡就是不工作,网络配不上、SSH 连不上。你去看客户机里网卡的名字,发现它根本不叫平台配置里写的那个名字。
现象
典型表现是:虚拟机启动后,平台下发的网络配置没有作用在正确的网卡上。客户机里 ip link 看到的是类似 ens18、enp1s0、eno1 这样的名字,而平台的网络配置是按 eth0 写的。名字对不上,配置就落空,网卡自然起不来。
根因
关键在于现代 Linux 的网卡命名规则。
老派 Linux 按探测顺序给网卡起名 eth0、eth1……但这种命名很不稳定:加块网卡、换个插槽,名字就可能全变,配置随之失效。
为了稳定,现代 Linux 改成了 Predictable Network Interface Names(可预测网卡命名),名字基于固件信息、PCI 位置、MAC 等生成,于是就出现了 ens18、enp1s0 这种名字。
而很多云镜像和虚拟化平台依赖 eth0 这个名字:平台的 cloud-init 网络配置里写的是 eth0,镜像里的脚本也可能引用 eth0。一方要 eth0,另一方给了 ens18,就对不上了。
怎么让网卡还叫 eth0?靠一个内核参数:
net.ifnames=0
它会关闭可预测命名,让内核退回到传统的 eth0/eth1 命名。云镜像往往是靠这个参数才把网卡命名为 eth0 的;如果不加,它就会按固件命名,和平台的配置对不上。
解决
在镜像或启动参数里加上 net.ifnames=0。几种常见做法:
做法一:如果这是台虚拟机,在启动时的内核命令行里加。
在 Proxmox VE 里,可以尝试通过虚拟机配置设置内核参数(不同版本支持情况不同),或借助 GRUB 编辑启动项加上参数。更稳妥的是下面两种。
做法二:在客户机里改 GRUB 配置。
进系统(或救援模式)后:
# 编辑 GRUB 默认参数
sudo vi /etc/default/grub
# 找到 GRUB_CMDLINE_LINUX,追加 net.ifnames=0
# 例如:GRUB_CMDLINE_LINUX="... net.ifnames=0"
# 重新生成 GRUB 配置
sudo update-grub # Debian/Ubuntu
# 或
sudo grub2-mkconfig -o /boot/grub2/grub.cfg # RHEL 系
# 重建 initramfs(部分发行版需要)
sudo update-initramfs -u # Debian/Ubuntu
# 或
sudo dracut -f # RHEL 系
做法三:建镜像/模板时就写进去。
如果你想做一台"一建好网卡就是 eth0"的模板机,就在打包镜像时把 net.ifnames=0 写进内核参数和 initramfs,后续从模板克隆的机器都自带这个行为,不用逐台改。
改完重启验证:
ip -br link
# 现在应该能看到 eth0
延伸与预防
这条坑的根本,是**"现代 Linux 的网卡命名由内核参数决定,配置文件和它必须对齐"**。
由此能引出两条实用经验:
- 命名和配置是一对,改一边要检查另一边。 不管你要
eth0还是ens18,标准是"网卡实际叫什么,配置就写什么"。两处不一致,网络就起不来。 - 云镜像/模板尽量在制作阶段就把命名规则定死。 依赖"建好之后手动改"意味着每台新机器都要救一次,批量化时是灾难。
顺带一提,排查这类"网卡名不对"的问题时,有两个命令特别好用:
# 看网卡当前叫什么、状态如何
ip -br link
# 看网卡名的来源(固件/PCI 位置/槽位等)
sudo udevadm test-builtin net_id /sys/class/net/ens18 2>/dev/null
后者能告诉你这个名字是怎么算出来的,对理解"为什么它不叫 eth0"很有帮助。