开机报错、网络不通------ESXi 克隆虚拟机的那些坑我帮你踩完了
上周在实验室搭环境,需要快速复制一台 Oracle Linux 10 的虚拟机出来。原本以为三分钟的事,结果搞了快一个小时------开机报"在当前状况下不允许执行此操作",开机后网络全挂,克隆完发现两台虚拟机 MAC 地址一模一样......
踩了一圈坑之后,我把整个流程彻底捋清楚了。今天写下来,希望你能比我少花点时间。
先说清楚这是什么情况
很多人第一次在 ESXi 上克隆虚拟机,下意识会去找 Web 界面的"克隆"按钮。找了一圈才发现:免费版的 ESXi 没有这个功能,那是 vCenter 才有的能力。
但其实不买 vCenter 照样能克隆,而且一点都不复杂------SSH 连上去,几条命令搞定。核心工具就一个:vmkfstools,ESXi 自带的磁盘操作命令,专门用来做这种事。
我这次的场景:
- 源虚拟机:
oel10-192.168.26.13,已经装好了Oracle Linux 10,配置好了基础环境 - 目标:快速复制出一台
oel10-192.168.26.15,改个 IP 就能用 - 存储路径:
/vmfs/volumes/data

整个流程只有六步
第一步:先把源虚拟机关掉
这步不能省。虚拟机运行状态下直接复制文件,轻则数据不一致,重则克隆出来的系统启动就崩。
bash
# 先查 VMID
vim-cmd vmsvc/getallvms | grep 26.13
# 关机,假设 VMID 是 1
vim-cmd vmsvc/power.off 1
# 确认已关机
vim-cmd vmsvc/get.state 1
当然,直接去 ESXi Web 界面右键关机也行,看你习惯。

第二步:建目录,把配置文件复制过去
bash
cd /vmfs/volumes/data
# 建目标虚拟机的目录
mkdir oel10-192.168.26.15
# 复制配置文件(注意不是复制磁盘,磁盘要用专用命令)
cp oel10-192.168.26.13/oel10-192.168.26.13.vmx oel10-192.168.26.15/oel10-192.168.26.15.vmx
cp oel10-192.168.26.13/oel10-192.168.26.13.nvram oel10-192.168.26.15/oel10-192.168.26.15.nvram
这里复制的是 .vmx(虚拟机配置文件)和 .nvram(BIOS 固件存储)。磁盘文件要单独处理。

第三步:克隆磁盘------这步最慢,但最关键
不能直接 cp 复制 vmdk 文件。 直接 cp 会把磁盘的 UUID 也一并复制过去,两台虚拟机磁盘 UUID 相同,ESXi 会疯掉。必须用 vmkfstools:
bash
vmkfstools -i /vmfs/volumes/data/oel10-192.168.26.13/oel10-192.168.26.13.vmdk \
/vmfs/volumes/data/oel10-192.168.26.15/oel10-192.168.26.15.vmdk \
-d thin
-d thin 是精简置备,磁盘文件只占实际使用量,不会一下子把空间吃满。如果你需要厚置备(比如追求稳定的 I/O 性能),用 -d eagerzeroedthick。
这一步耗时取决于磁盘大小,通常几十 GB 的盘大概需要几分钟到十几分钟,有进度条,等着就行。

第四步:改 vmx 配置------坑最集中的地方
这步是整个流程里最容易出问题的。很多人把文件复制完就直接注册虚拟机,然后就开始了一系列诡异报错。
克隆之后必须重新生成 UUID 和 MAC 地址,否则两台虚拟机会互相冲突。
bash
cd /vmfs/volumes/data/oel10-192.168.26.15
# 把所有文件里的旧虚拟机名批量替换
sed -i 's/oel10-192.168.26.13/oel10-192.168.26.15/g' oel10-192.168.26.15.vmx
# 删掉旧的 UUID,重新生成
sed -i '/^uuid.bios/d' oel10-192.168.26.15.vmx
sed -i '/^uuid.location/d' oel10-192.168.26.15.vmx
echo "uuid.bios = \"$(uuidgen)\"" >> oel10-192.168.26.15.vmx
echo "uuid.location = \"$(uuidgen)\"" >> oel10-192.168.26.15.vmx
# 删掉旧的 MAC 地址,让 ESXi 开机时自动生成新的
sed -i '/ethernet0.generatedAddress/d' oel10-192.168.26.15.vmx
sed -i '/ethernet0.addressType/d' oel10-192.168.26.15.vmx
echo 'ethernet0.addressType = "generated"' >> oel10-192.168.26.15.vmx

改完之后验证一下,确认 displayName 和 uuid 都正确:
bash
grep -E "displayName|uuid\.|ethernet0" oel10-192.168.26.15.vmx

第五步:注册虚拟机
bash
vim-cmd solo/registervm /vmfs/volumes/data/oel10-192.168.26.15/oel10-192.168.26.15.vmx
执行成功后会返回一个数字,这是新虚拟机的 VMID,记下来后面要用。
bash
[root@bogon:/vmfs/volumes/68d7222b-5832bf30-789b-d0946685487f/oel10-192.168.26.15] vim-cmd solo/registervm /vmfs/volumes/da
ta/oel10-192.168.26.15/oel10-192.168.26.15.vmx
55
[root@bogon:/vmfs/volumes/68d7222b-5832bf30-789b-d0946685487f/oel10-192.168.26.15]
第六步:启动虚拟机
bash
# 先确认主机不在维护模式(这是我踩的第一个坑)
esxcli system maintenanceMode get
# 如果返回 true,先退出维护模式
esxcli system maintenanceMode set --enable false
# 启动(VMID 换成上一步的返回值)
vim-cmd vmsvc/power.on <VMID>

开机后还有几步收尾
虚拟机起来了,但现在它和源机器除了 MAC 地址不同,其他配置都一样------主机名、IP、machine-id,这些都得改。
改主机名:
bash
hostnamectl set-hostname oel10-192.168.26.15
改 IP 地址:
bash
# 先看一下当前的连接名
nmcli connection show
# 修改 IP(连接名换成实际的,比如 ens34)
nmcli connection modify ens34 ipv4.addresses 192.168.26.15/22
nmcli connection modify ens34 ipv4.gateway 192.168.27.254
nmcli connection modify ens34 ipv4.dns "114.114.114.114"
nmcli connection up ens34

改 /etc/hosts:
bash
sed -i 's/192.168.26.13/192.168.26.15/g' /etc/hosts
重新生成 machine-id,然后重启:
bash
rm -f /etc/machine-id
dbus-uuidgen --ensure=/etc/machine-id
reboot
machine-id 这个很多人忽略。如果你的环境里有 DHCP、Kerberos 或者某些依赖 systemd 机器唯一性的服务,两台机器 machine-id 相同会出各种奇怪问题,最好养成习惯每次克隆都改掉。

嫌步骤多?有一键脚本
把上面所有步骤打包成一个脚本,改三个变量直接粘贴到 SSH 终端跑:
bash
SRC_VM="oel10-192.168.26.13"
DST_VM="oel10-192.168.26.15"
DATASTORE="/vmfs/volumes/data"
# 关闭源虚拟机
SRC_ID=$(vim-cmd vmsvc/getallvms | grep "$SRC_VM" | awk '{print $1}')
echo "源 VMID: $SRC_ID"
vim-cmd vmsvc/power.off $SRC_ID
sleep 10
# 复制文件
mkdir -p $DATASTORE/$DST_VM
cp $DATASTORE/$SRC_VM/$SRC_VM.vmx $DATASTORE/$DST_VM/$DST_VM.vmx
cp $DATASTORE/$SRC_VM/$SRC_VM.nvram $DATASTORE/$DST_VM/$DST_VM.nvram
# 克隆磁盘
vmkfstools -i $DATASTORE/$SRC_VM/$SRC_VM.vmdk $DATASTORE/$DST_VM/$DST_VM.vmdk -d thin
# 改 vmx
cd $DATASTORE/$DST_VM
sed -i "s/$SRC_VM/$DST_VM/g" $DST_VM.vmx
sed -i '/^uuid.bios/d' $DST_VM.vmx
sed -i '/^uuid.location/d' $DST_VM.vmx
echo "uuid.bios = \"$(uuidgen)\"" >> $DST_VM.vmx
echo "uuid.location = \"$(uuidgen)\"" >> $DST_VM.vmx
sed -i '/ethernet0.generatedAddress/d' $DST_VM.vmx
sed -i '/ethernet0.addressType/d' $DST_VM.vmx
echo 'ethernet0.addressType = "generated"' >> $DST_VM.vmx
# 注册并启动
NEW_ID=$(vim-cmd solo/registervm $DATASTORE/$DST_VM/$DST_VM.vmx)
echo "新 VMID: $NEW_ID"
esxcli system maintenanceMode set --enable false
vim-cmd vmsvc/power.on $NEW_ID
echo "完成,登录后记得改主机名和 IP"
脚本执行完,去虚拟机里改一下主机名和 IP 就行了。
踩过的那几个坑
坑1:开机报"在当前状况下不允许执行此操作"
大概率是主机在维护模式。执行这条退出来:
bash
esxcli system maintenanceMode set --enable false
坑2:开机后网络完全不通
有两种可能。第一,vmx 里 MAC 地址没改干净------按照上面第四步重新检查一遍。第二,虚拟机内 IP 还是旧的------进系统用 nmcli 改掉。
检查方法:
bash
# 在 ESXi 上看虚拟机的 MAC
vim-cmd vmsvc/get.guestinfo <VMID> | grep -i mac
# 在虚拟机内确认 IP
ip addr show
坑3:注册虚拟机失败
一般是路径写错了,或者文件没复制成功。检查一下:
bash
ls -la /vmfs/volumes/data/oel10-192.168.26.15/
看看 vmx 和 vmdk 文件是不是都在。

小结
整个流程回顾一下:
- 关源虚拟机
- 建目录,复制 vmx 和 nvram
- 用
vmkfstools克隆磁盘 - 修改 vmx 里的 UUID 和 MAC 地址
- 注册虚拟机
- 退出维护模式,开机
- 进系统改主机名、IP、machine-id
绕过 vCenter,全程 SSH,不依赖任何付费功能。一个字:稳。
如果你也在折腾 ESXi 实验环境,或者遇到了其他奇怪的克隆问题,欢迎评论区聊聊------说不定你的坑我也踩过。