1 同样是qcow2,为什么有的能跑有的不能?一文讲透EVE-NG镜像识别的底层机制
1.1 现象引入
把一个qcow2文件扔进EVE-NG目录,重启服务——设备列表里没有它。换个目录名再试,出现了,但启动后黑屏。再改一下文件名,终于能跑。同样的文件,三个结果。
这不是玄学。EVE-NG识别镜像从来不是"有文件就行",背后是一套严格的链式校验:目录前缀匹配模板→磁盘文件名映射控制器→启动时创建差分盘→权限校验通过。任何一环断开,镜像要么不可见,要么启动失败。
这篇文章把这条链路拆干净。
1.2 概念拆解:三层识别机制
1.2.1 第一层:目录前缀匹配(门牌号)
快递送到楼栋,门牌号对不上就不送。EVE-NG的模板扫描逻辑同理。
镜像目录必须放在 /opt/unetlab/addons/qemu/ 下,且目录名格式严格为 {模板前缀}-{版本}。前缀必须与 /opt/unetlab/html/templates/intel/(或 amd/)下的YML模板文件名一致。
举个例子:
- 模板文件
asav.yml → 镜像目录名必须以 asav- 开头,如 asav-9.20.1
- 模板文件
fortinet-FGT.yml → 镜像目录名必须以 fortinet-FGT- 开头,如 fortinet-FGT-7.0.5
如果目录前缀与任何模板文件名不匹配,EVE-NG会根据 config.php 中的 TEMPLATE_DISABLED 常量决定行为:
.hided(默认):设备下拉列表中直接隐藏该模板
.missing:显示在列表中,但名称后追加 .missing 标记
源码层面,init.php:148-152 在页面加载时扫描 addon 目录,将匹配结果与模板名前缀比对,不匹配的直接标记为不可用。
注意:模板YML文件并不预设磁盘控制器类型——控制器完全由镜像目录中的磁盘文件名在运行时自动检测决定(见第二层)。
1.2.2 第二层:磁盘文件名→控制器映射(钥匙)
同一把锁,钥匙型号不对插不进去。磁盘文件名不是随便取的——它决定了QEMU用哪种控制器加载这块盘。
EVE-NG支持8种磁盘控制器格式,每种文件名前缀对应不同的QEMU启动参数:
| 磁盘文件名 |
控制器类型 |
典型设备 |
| virtioa.qcow2 |
VirtIO(半虚拟化) |
华为/思科/F5/Juniper等主流设备 |
| hda.qcow2 |
IDE |
旧型号设备(ACS、CheckPoint等) |
| scsia.qcow2 |
SCSI |
部分存储类设备 |
| sataa.qcow2 |
SATA |
VMware vCenter等 |
| lsia.qcow2 |
LSI SCSI |
部分老旧镜像 |
| megasasa.qcow2 |
MegaSAS |
Cisco vWLC等 |
| virtidea.qcow2 |
VirtIO-IDE |
Nokia Timos 19等 |
| cdrom.iso |
CDROM |
Arista vEOS启动盘等 |
多盘场景下,文件名末尾字母按字母序递增:virtioa、virtiob、virtioc...
关键点:控制器类型由磁盘文件名自动检测(而非模板预设),用户在Web界面添加节点时不可更改。运行时 __node.php:990-1069 扫描镜像目录,通过正则匹配文件名前缀来决定QEMU启动参数——virtioa.qcow2 对应 -drive if=virtio,hda.qcow2 对应 -hd[a](IDE),以此类推。如果镜像文件名与设备预期的控制器类型不匹配(例如设备需要VirtIO但文件名为 hda.qcow2),QEMU启动命令会传入错误的 -drive if=xxx 或 -hd 参数,虚拟机内核无法识别启动盘——表现就是黑屏。
源码证据:__node.php:990-1069 通过正则匹配8种控制器前缀 + .qcow2$ 后缀来识别磁盘文件。
1.2.3 第三层:差分盘与权限(引擎点火)
模板是蓝图,差分盘是施工图,权限是施工许可证。三层缺一不可。
差分盘机制:当你在实验中启动一个QEMU节点时,EVE-NG不会直接读写模板镜像。而是通过 qemu-img create -b {模板路径}/virtioa.qcow2 -f qcow2 {运行路径}/virtioa.qcow2 创建一个Copy-On-Write(COW)叠加层。所有运行时变更写入差分盘,模板文件保持不变。
差分盘生成位置:/opt/unetlab/tmp/{tenant_id}/{lab_id}/{node_id}/virtioa.qcow2
这意味着:
- 同一个模板镜像可以被多个节点同时使用,互不干扰
- Wipe节点 = 删除差分盘,下次启动时重新从模板创建干净的叠加层
- 差分盘损坏不影响模板,Wipe即可恢复
权限校验:上传镜像后必须执行 /opt/unetlab/wrappers/unl_wrapper -a fixpermissions 修复权限。这条命令不只是简单的chown——它按照EVE-NG内部的权限规范设置文件属主、属组和特殊权限位。手动执行 chown 会破坏特殊权限,导致QEMU无法读取磁盘文件,节点启动失败。
源码证据:cli.php:755-830 的 prepareNode() 函数依次执行创建运行目录、复制skeleton、创建差分盘、创建TAP接口、桥接虚拟网络。整个流程无原子性保证——任何一步失败,已创建的差分盘、TAP接口、目录不会自动回滚,需手动清理或Wipe。
1.3 原理图解:镜像从上传到启动的完整链路
用户上传qcow2文件
|
v
放入 /opt/unetlab/addons/qemu/{前缀}-{版本}/
|
v
init.php 扫描:目录前缀 <--> YML模板文件名 匹配?
|-- 不匹配 --> TEMPLATE_DISABLED 控制显示:
| .hided = 隐藏 / .missing = 标记缺失
|
v 匹配
设备下拉列表显示该镜像,用户拖拽节点到画布
|
v 点击启动
apiStartLabNode()
|
v
unl_wrapper -a start
|
v
prepareNode() 执行:
1. MkHomeDir() --> 创建 /opt/unetlab/tmp/{tid}/{lid}/{nid}/
2. cp -ar skeleton/* --> 复制skeleton到jail/
3. mount -B -o ro --> 只读挂载jail和qemu目录
4. qemu-img create -b ... --> 从模板创建差分盘(已存在则跳过)
5. addTap() --> 创建TAP接口 vunl{t}_{id}_{if}
6. connectInterface() --> TAP接入bridge(vnet{t}_{net_id})
|
v
getCommand() 生成 QEMU 启动命令行:
/opt/qemu/bin/qemu-system-x86_64
-drive file=/opt/unetlab/tmp/.../virtioa.qcow2,if=virtio <-- 控制器类型由文件名决定
-m {RAM} -smp {CPU}
-serial telnet:...:{console_port}
...
|
v
QEMU进程启动 --> 加载差分盘 --> 虚拟机识别磁盘 --> 启动OS
四个常见卡点:
| 卡点 |
阶段 |
现象 |
根因 |
| 目录前缀不匹配 |
模板扫描 |
设备列表不可见 |
目录名前缀与YML模板文件名不一致 |
| 磁盘控制器选错 |
QEMU参数生成 |
启动后黑屏 |
文件名与设备预期控制器不匹配(如设备需VirtIO但文件名为hda.qcow2),QEMU传了错误的if=参数 |
| 权限未修复 |
磁盘加载 |
启动失败/报IO错误 |
未执行fixpermissions,QEMU无法读取磁盘 |
| 差分盘残留损坏 |
差分盘创建 |
启动异常/配置残留 |
之前prepareNode()失败未回滚,差分盘存在但损坏 |
1.4 实战案例:三个"同样qcow2"不同命运的真实场景
1.4.1 场景A:文件名对了,目录名错了
操作:假如把FortiGate镜像放进 /opt/unetlab/addons/qemu/fortigate-7.0.5/
结果:设备列表不显示。如果EVE-NG的模板文件名是 fortinet-FGT.yml,而目录前缀 fortigate- 与之不匹配,init.php扫描时直接跳过。
修正:
mv /opt/unetlab/addons/qemu/fortigate-7.0.5 /opt/unetlab/addons/qemu/fortinet-FGT-7.0.5
规律:不确定前缀时,去 /opt/unetlab/html/templates/intel/ 目录ls一下,YML文件名(去掉.yml)就是你要的前缀。
1.4.2 场景B:目录名对了,磁盘控制器选错了
操作:把华为AR1000v的qcow2文件命名为 hda.qcow2
结果:设备列表显示了,但启动后黑屏。因为华为AR1000v的设备内核期望VirtIO控制器,而文件名 hda.qcow2 使 __node.php 自动匹配为IDE控制器,QEMU按 -hd[a] 加载,华为VRP系统无法识别IDE盘。
修正:
mv /opt/unetlab/addons/qemu/huawei-AR1000v-5.170/hda.qcow2 /opt/unetlab/addons/qemu/huawei-AR1000v-5.170/virtioa.qcow2
/opt/unetlab/wrappers/unl_wrapper -a fixpermissions
规律:不确定该用哪种控制器时,参考官方Qemu image namings文档的映射表,确认设备内核期望的控制器类型后,用对应的文件名命名。或者自行尝试几个不同控制器类型,注意wipe后启动
1.4.3 场景C:一切正确,但忘了修权限
操作:通过SFTP上传完镜像,直接去Web界面添加节点
结果:节点启动失败,QEMU无法读写磁盘文件。
修正:
/opt/unetlab/wrappers/unl_wrapper -a fixpermissions
规律:每次上传镜像后,这条命令必须执行。不是可选项。而且绝对不能用 chown -R 替代——手动chown会破坏EVE-NG依赖的特殊权限位。
1.5 延伸思考
理解了三层识别机制,你就拥有了"不查教程也能自己造镜像"的能力。流程就四步:
- 对照
/opt/unetlab/html/templates/intel/ 找到对应模板,确认目录前缀
- 查官方Qemu image namings映射表,确认设备期望的磁盘控制器类型,用对应文件名命名(virtioa 还是 hda)
- 上传qcow2到正确目录,命名为正确的磁盘文件名
- 执行 fixpermissions
任何KVM镜像,只要宿主机CPU支持且资源足够,这套流程都能跑通。
本文为AI辅助生成草稿,技术细节请以实际环境验证为准。
1.6 内容来源
本文素材来自以下EVE-NG知识库文档,按章节索引:
1.6.1 现象引入
- 镜像文件导入后无法使用?——EVE-NG亚太代理中文区独家合作伙伴:7项检查要点,印证"同样的文件不同结果"的常见现象
1.6.2 第一层:目录前缀匹配
- 04.3 镜像管理.md 1.1节:目录命名规则
{前缀}-{版本};2.2节:模板文件名与镜像文件夹前缀的对应关系;3.2节:TEMPLATE_DISABLED机制(.hided/.missing)
- 04.3 镜像管理.md R1校验记录:init.php:121-123 扫描 /opt/unetlab/addons/ 目录;init.php:148-152 模板名前缀匹配逻辑
1.6.3 第二层:磁盘文件名→控制器映射
- Qemu image namings——EVE-NG官方文档:完整的前缀-厂商-磁盘文件名映射表,8种HDD格式说明
- 04.3 镜像管理.md 1.3节:源码验证的8种磁盘控制器格式(含megasas和cdrom.iso,旧文档遗漏的2种已修正);Step 5陷阱扫描:扩展名错误(.qcow应为.qcow2)、缺失格式(megasas/cdrom.iso)
- 03.3 节点与网络配置.md 3.1-3.2节:QEMU镜像目录命名前缀表、磁盘文件名与控制器对应表
1.6.4 第三层:差分盘与权限
- T-STARTNODE 启动节点.md 维度5:prepareNode()完整流程(MkHomeDir→skeleton→mount→qemu-img create→addTap→connectInterface);差分盘路径映射;幂等性(已存在则跳过);无回滚机制
- T-STARTNODE 启动节点.md 关键发现:差分盘"跳过已存在"特性、Wipe=删除差分盘、prepareNode失败残留不自动清理
- EVE-NG制作镜像常用命令:fixpermissions命令、qemu-img commit提交、qemu-img convert压缩
- 镜像文件导入后无法使用? 第5项:fixpermissions修复权限;第6项:节点资源配置
1.6.5 原理图解
- T-STARTNODE 启动节点.md 维度5:从apiStartLabNode到QEMU进程启动的完整调用链(api→unl_wrapper→start()→prepareNode→getCommand→qemu_wrapper)
- T-STARTNODE 启动节点.md 维度4:控制台端口计算公式、skeleton目录结构
1.6.6 实战案例
- 镜像文件导入后无法使用? 第1项:扩展名检查(Dynamips=.image / IOL=.bin / QEMU=.qcow2);第2项:目录及文件名规范
- Qemu image namings:fortinet-FGT前缀、huawei前缀、virtioa/hda映射关系
- Huawei AR1000v 镜像导入教程:重命名为virtioa.qcow2 + fixpermissions的完整步骤
1.6.7 延伸思考
- EVE-NG制作镜像常用命令:qemu-img create创建系统盘、qemu-img commit提交镜像、qemu-img convert -c压缩
- 03.3 节点与网络配置.md 4.1-4.2节:镜像格式(QCOW2/RAW/VMDK)及转换命令