
EVE-NG 这个模拟器玩网络的同行应该都不陌生它把 KVM、QEMU、Docker 这些底层能力包了一层还算友好的 Web 壳让我们能在浏览器里拖拖拽拽就搭出一个几十个节点的拓扑。官方和社区整理过一大堆现成的镜像包VyOS、各种 Linux、Windows、还有不少设备镜像都有人打包好了。但真正做过一段时间实验的人都会撞上一个尴尬想跑的那个版本社区包里面就是没有或者有但里面的配置和你的需求差得远。这份东西就是写给这群人的——已经会用 EVE-NG 加节点、连网络但被现成镜像不够用卡住想自己动手做一份专属镜像的人。不管你是刚入门的新手还是用了两三年的老手下面这套流程都能直接照着抄。1. 为什么还要自己动手做 EVE-NG 镜像1.1 现成镜像不够用的几个真实场景我第一次动自己做的念头是因为需要一个带特定内核模块的 Linux 节点来跑一段流量生成的脚本。社区里那几个 Linux 镜像都是很干净的发行版装模块要联网而实验环境里节点本身又没配外网通道来回折腾特别痛苦。后面又陆续碰到几类类似的麻烦事需要固定 IP、固定路由表的节点每次开实验都手配一遍太烦需要一个预装了抓包工具、Python 脚本、特定版本编译器的工具机需要把某个设备镜像换个磁盘大小默认的 8G 跑日志两天就满需要给学员发一套统一的实验环境希望他们打开就是配好的状态。这些需求靠下载是解决不了的只能自己动手。而且你会发现一旦做过一次后面再遇到类似情况就是十分钟的事边际成本极低。1.2 自己做和下载来的镜像本质差在哪很多人以为做镜像是个玄学事情其实拆开看就三件事准备一个干净的虚拟磁盘、把系统装进去并做好定制、放到 EVE-NG 认识的位置并告诉它怎么启动。下载来的镜像之所以开箱可用是因为打包的人已经帮你做完了这三件事而且踩平了所有的坑。你自己做无非是把这些坑再踩一遍——但踩完之后你对整套环境的掌控力会完全不一样。这个差别在维护阶段体现得特别明显。某个节点起不来了用现成镜像你只能去论坛翻帖子、靠猜自己做的镜像你清楚它从哪个 ISO 装的、GRUB 里写了什么参数、网卡是怎么配的排错路径完全可控。说白了这是一次性投入换长期省心。1.3 一个 EVE-NG 镜像到底由哪些东西组成先把概念理清楚。在 EVE-NG 语境里镜像其实是一个目录不是一个文件。目录名字决定它归哪一类模板管目录里面的文件决定它启动时挂什么盘。典型结构是这样/opt/unetlab/addons/qemu/linux-myrouter/ ├── hda.qcow2 # 系统盘 └── cdrom.iso # 可选装机时用的光盘命名规则是硬性的不是随便起的文件名含义说明hda.qcow2第一块 IDE 磁盘最常用绝大多数 Linux 镜像用它hdb.qcow2第二块 IDE 磁盘需要额外数据盘时用virtioa.qcow2第一块 VirtIO 磁盘性能更好但系统内需要 virtio 驱动cdrom.iso光驱安装阶段挂载装完可留可删目录名前缀同样有讲究。以linux-开头会走 Linux 模板dynamips-开头走 DynamIPSiol-走 IOLwin-走 Windows 模板。你自己做的 Linux 节点目录名老老实实以linux-开头能省掉一大堆模板调试的功夫。注意目录名和文件名都不能带空格、中文和特殊符号。EVE-NG 后台是用 shell 脚本调的一个空格就能让权限修复脚本直接崩掉而且报错信息非常不友好。2. 开工前的环境准备与目录规划2.1 宿主机资源与虚拟化能力确认EVE-NG 本身就跑在一台 Linux 宿主机上做镜像的过程实际上是在这台宿主机上再开一个临时虚拟机装完系统导出来。所以第一件事是确认宿主机的资源够不够以及虚拟化能力有没有开。# 确认 CPU 支持虚拟化且已启用 grep -E vmx|svm /proc/cpuinfo | head -1 # 确认 KVM 模块加载正常 lsmod | grep kvm # 看内存和磁盘余量 free -h df -h /opt如果 EVE-NG 本身是跑在别的虚拟化平台里面的还要在宿主机的虚拟机设置里勾上向客户机公开硬件虚拟化不同平台叫法不一样否则 KVM 起不来后面 virt-install 会直接报错说没有可用的加速器。这个坑我见过太多次了尤其是一些精简版的宿主环境默认就是关的。资源方面我的经验是临时装机的虚拟机给 1 到 2 核、1 到 2G 内存、8 到 16G 磁盘就够了。别一上来给 8 核 8G装完你还得把它缩回去缩的时候容易出问题。EVE-NG 里跑的节点一般也就 512M 到 1G 内存做镜像时按目标运行规格来不要按装机舒服来。磁盘空间要留足一个最小安装大概 2 到 3G加上定制内容、临时文件、转换时的中间文件最好留 30G 以上余量。2.2 工作目录与成品区的规划我强烈建议不要把工作目录直接放在/opt/unetlab/addons/qemu/下面。原因很简单EVE-NG 的界面会去扫描这个目录你装到一半的镜像会以半成品状态出现在节点列表里容易误点也容易让修复权限的脚本处理一堆没完成的东西。我的做法是分两个目录工作区/data/build成品区就是/opt/unetlab/addons/qemu/。流程是在工作区里装系统、瘦身、转格式转完先用qemu-system-x86_64裸起一次确认能进 console没问题再整个目录mv到成品区最后跑一次权限修复。这样做还有个隐性好处成品区里永远是干净的、能用的镜像。出问题直接删掉重来不会影响正在用的环境。还有一点工作区和成品区最好在同一个物理磁盘上。跨盘移动几个 G 的 qcow2 文件时间成本不低而且中途被打断还容易留下残缺文件。2.3 工具清单与安装需要的工具不多但少一个都会卡住工具用途安装方式qemu-kvm裸起镜像做验证apt install qemu-kvmqemu-utilsqemu-img 转换、扩容apt install qemu-utilsvirtinstvirt-install 装机apt install virtinstlibvirt-daemon-system虚拟机管理可选apt install libvirt-daemon-systemgenisoimage做 seed 盘apt install genisoimagelibguestfs-tools不启动系统就注入文件、瘦身apt install libguestfs-toolslibguestfs-tools这个包值得单独说一句。它让你能在不启动虚拟机的前提下直接读写 qcow2 里面的文件系统用来改 sshd_config、塞脚本、删日志特别方便比开机进去改快得多。缺点是第一次用会花点时间准备一个临时 appliance而且和某些内核版本偶有兼容问题遇到报错就老实开机进去改别在这上面死磕。提示EVE-NG 官方文档里常出现的手动 qemu 命令和 virt-install 是可以互相替代的。virt-install 更适合规范化装机手动 qemu 命令更适合临时验证。两个都掌握遇到问题好排查。3. 从零构建一个 Linux 节点镜像3.1 用 virt-install 装一个干净的系统第一步是装机。以 Ubuntu Server 为例cd /data/build mkdir -p linux-myrouter cd linux-myrouter # 准备安装盘用国内镜像站下载更快 wget -O ubuntu.iso https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/22.04/ubuntu-22.04.5-live-server-amd64.iso # 创建系统盘 qemu-img create -f qcow2 hda.qcow2 10G # 启动安装 virt-install \ --name build-myrouter \ --ram 2048 \ --vcpus 2 \ --disk path/data/build/linux-myrouter/hda.qcow2,formatqcow2,buside \ --cdrom /data/build/linux-myrouter/ubuntu.iso \ --graphics vnc,listen0.0.0.0,port5901 \ --network bridgevmbr0 \ --boot cdrom,hd \ --os-variant ubuntu22.04几个参数值得掰开说。--disk里的buside是有意选的。EVE-NG 里用 hda.qcow2 命名的镜像挂载走的就是 IDE 通道如果装机时用 virtio装完系统里可能缺少 virtio 驱动或者 initramfs 里没包含导过去起不来。IDE 慢一点但兼容性最好装镜像这件事上稳比快重要得多。--graphics vnc,port5901是给自己开一条后路。装机过程中有可能网络起不来这时候只能靠 VNC 进去操作用 VNC 客户端连宿主机IP:5901就行。--os-variant一定要写对它决定 virt-install 帮你预置哪些驱动和优化参数写错了不一定报错但可能装完启动有问题。装的过程中有个小细节Ubuntu Server 安装器在最后阶段会联网检查更新宿主机网络慢的话这一步会卡很久。安装时选择最小化安装、跳过 snap 更新装机时间能从二十分钟缩到七八分钟。3.2 系统内的必要改造装完重启进去做改造。这一节是整个流程里最重要的一节坑也最多。第一件事让串口控制台能用。EVE-NG 的节点控制台是通过 telnet 连到虚拟机串口ttyS0上的默认装出来的系统串口上没有 getty结果是你在 EVE-NG 里点节点看到一片黑屏。这个现象太常见了几乎每个第一次做镜像的人都会遇到。# 编辑 grub 配置 vi /etc/default/grub # 找到 GRUB_CMDLINE_LINUX_DEFAULT加上 console 参数 GRUB_CMDLINE_LINUX_DEFAULTconsolettyS0,115200n8 consoletty0 GRUB_TERMINALserial console update-grub # 启用串口 getty systemctl enable serial-gettyttyS0.service systemctl start serial-gettyttyS0.serviceconsoletty0保留在最后是为了让 VNC 里也能看到输出调试的时候方便。第二件事清理身份信息。镜像会被复制成很多份如果每份带着相同的 machine-id 和 SSH host key会有一堆麻烦。清理掉让系统首次启动时重新生成truncate -s 0 /etc/machine-id rm -f /var/lib/dbus/machine-id ln -s /etc/machine-id /var/lib/dbus/machine-id rm -f /etc/ssh/ssh_host_* rm -rf /var/log/* history -c cat /dev/null ~/.bash_history第三件事网卡配置要能自适应。EVE-NG 给节点分配网卡数量是动态的MAC 也是每次启动随机生成如果你在镜像里写死了网卡名和 IP基本一定会出问题。用 netplan 配成 DHCP、按名字通配符匹配比较稳妥network: version: 2 ethernets: all-en: match: name: en* dhcp4: true optional: truematch.name用通配符匹配所有以 en 开头的网卡不管插几张都能拿到地址。optional: true是防止没插线时启动卡在等网络超时上。注意Ubuntu 22.04 之后网卡命名规则经常变ens3、enp0s2、eth0 都可能出现。用通配符匹配比写具体名字可靠得多。3.3 瘦身与格式转换系统装完、定制做完关机然后做瘦身。目标是让镜像小、启动快、不带垃圾信息。apt clean rm -rf /var/cache/apt/archives/* rm -rf /tmp/* journalctl --vacuum-size10M poweroff关机之后在宿主机上做磁盘整理这一步能显著减小 qcow2 体积virt-sparsify --compress /data/build/linux-myrouter/hda.qcow2 /data/build/linux-myrouter/hda-slim.qcow2 mv hda-slim.qcow2 hda.qcow2如果你拿到的是别的格式比如 vmdk转换命令是qemu-img convert -f vmdk -O qcow2 source.vmdk hda.qcow2。需要扩容的话用qemu-img resize hda.qcow2 5G但扩容之后进去还得把分区撑开否则磁盘变大了分区没变等于白扩growpart /dev/sda 2 resize2fs /dev/sda2这一步很多教程都漏掉了结果新人扩容完发现还是没空间一头雾水。3.4 模板文件与目录命名EVE-NG 里节点类型是靠模板识别的模板文件在/opt/unetlab/html/templates/下面不同版本路径略有差异有的会再按 intel 和 amd 分子目录。以 linux 模板为例大致长这样type: linux name: Linux description: Linux host icon: Linux.png cpulimit: 1 cpu: 1 ram: 1024 ethernet: 4 console: telnet自己新建一个类型的话复制一份改改就行cd /opt/unetlab/html/templates/ cp linux.yml myrouter.yml关键字段是type它要和镜像目录名的前缀对应上。目录叫linux-myroutertype 就是linux。模板里的ethernet是默认网卡数ram是默认内存这两个值只是新建节点时的默认值用的时候随时可以调所以不用太纠结。3.5 导入、修权限与验证东西都准备好了导入mv /data/build/linux-myrouter /opt/unetlab/addons/qemu/ chown -R root:unl /opt/unetlab/addons/qemu/linux-myrouter chmod -R 755 /opt/unetlab/addons/qemu/linux-myrouter /opt/unetlab/wrappers/unl_wrapper -a fixpermissionsfixpermissions这个动作几乎所有教程都会提但很少有人说清楚它到底在修什么。它主要做两件事把镜像目录的属主属组调整成root:unl以及把目录权限收敛到 755。EVE-NG 前台跑在 www-data 下后台跑在 root 下两边都要能读到镜像权限不对就是节点起不来或者起得起来但 console 连不上。验证分两步。先在宿主机上裸起一次qemu-system-x86_64 \ -enable-kvm \ -m 1024 \ -smp 1 \ -drive file/opt/unetlab/addons/qemu/linux-myrouter/hda.qcow2,formatqcow2,ifide \ -nographic-nographic会把串口输出直接打到终端上能进登录提示符就说明串口配置对了。这时候按 CtrlA 再按 X 退出。然后再去 Web 界面里加一个节点选刚才的模板ping 一下验证网络。两步都过了这个镜像就算成了。4. 制作 Docker 类型的节点镜像4.1 Docker 镜像和 qcow2 镜像的本质差别EVE-NG 里除了虚拟机节点还有一类是容器节点两者差别很大容易混。qcow2 类型走的是完整虚拟化有自己的内核启动要几十秒资源占用高但什么系统都能跑。Docker 类型走的是容器共享宿主机内核启动一两秒占用极小适合跑一些轻量的工具比如流量生成器、简单的路由程序、抓包分析工具。选择标准很简单需要自定义内核模块、需要完整系统环境的用 qcow2只是跑一个用户态程序的用 Docker。我见过有人为了跑一个 iperf 客户端去做一个完整的 Ubuntu 虚拟机镜像纯属浪费——那种场景一个 alpine 容器两分钟就搞定了。4.2 写一个 EVE-NG 能识别的 DockerfileEVE-NG 的 Docker 节点对镜像有约定不是随便一个 docker 镜像扔进去就能跑。核心要求是容器启动后要提供一个可交互的 shell并且要能接收控制台连接。FROM alpine:3.18 RUN apk add --no-cache bash iproute2 iputils tcpdump # 保持容器运行并提供交互 shell CMD [/bin/bash]构建并保存成 EVE-NG 需要的 tar 包docker build -t mytool:1.0 . docker save mytool:1.0 -o /opt/unetlab/addons/docker/mytool.tar这里有个坑容器里的网络接口命名和虚拟机不一样宿主机给容器分配的接口名通常是 eth0、eth1而且没有 systemd 帮忙配管理需要自己在容器里用ip命令配或者在启动脚本里处理。这一点和 qcow2 镜像的思路完全不同别拿虚拟机的经验直接套。4.3 容器节点的验证与排错导入之后同样要修权限chown -R root:unl /opt/unetlab/addons/docker/ chmod -R 755 /opt/unetlab/addons/docker/ /opt/unetlab/wrappers/unl_wrapper -a fixpermissions验证的时候直接在宿主机上手动跑一次容器模拟 EVE-NG 的调用方式docker run -it --rm --privileged mytool:1.0 /bin/bash--privileged是为了让容器内能操作网络接口。EVE-NG 起容器节点时也会做类似授权因为容器节点常见的用途就是配路由、做 NAT、抓包没有网络管理权限基本干不了活。如果容器起来了但 Web 界面连不上 console八成是 CMD 写成了前台不阻塞的形式或者 bash 需要-i才会保持交互改成CMD [/bin/bash, -i]或者写个while true; do sleep 3600; done兜底就行。5. 常见问题排查实录5.1 启动黑屏和卡在 boot 的排查顺序这是最高频的问题占了所有报错的一多半。我整理了一个固定的排查顺序照着走基本都能定位。第一确认 GRUB 里有没有consolettyS0这一个原因就占到黑屏问题的六成以上。检查方法是用-nographic裸起一次如果终端能看到输出说明串口没问题问题在别处。第二看是不是卡在内核启动阶段裸起时如果 kernel 输出到某一行就不动了常见的是卡在Waiting for root device说明磁盘控制器类型不对。第三看是不是卡在文件系统检查非正常关机后系统会做 fsck多等一会儿。现象最可能原因处理方式完全黑屏无任何输出缺 consolettyS0改 grub 并 update-grub卡在 Waiting for root device磁盘总线类型不匹配统一用 IDE或补 virtio 驱动起来后卡在 fsck非正常关机裸起时让它跑完一次有输出但登录不了串口 getty 没启用enable serial-gettyttyS0登录后马上断开登录 shell 绑到了别的 tty检查 agetty 配置5.2 网卡对不上、接口数量不对EVE-NG 里给节点连了几根线就应该出几张网卡。如果连了 4 根线系统里只看到 1 张通常是模板里的 ethernet 数量写小了或者镜像里网卡驱动不全。另一个常见情况是接口名和预期不一样EVE-NG 分配网卡顺序和 QEMU 的 device 参数顺序有关一般是 eth0、eth1 递增但在某些发行版上会被重命名成 ens3、enp0s3配置文件里写 eth0 就找不到设备。我的处理习惯是镜像里一律用 netplan 的 name 通配符匹配或者用 systemd-networkd 的Nameen*不写死具体名字。这样不管系统怎么重命名都能配上。这个习惯帮我省了大量重复调试时间。5.3 权限与路径类报错速查这类错误的特点是 Web 界面里节点列表能看到但点了起不来或者起来了没有任何 console基本都是权限问题。报错或现象原因解决节点图标是灰的目录名不匹配任何模板 type检查目录名前缀点击启动无反应目录权限不是 755chmod -R 755启动后 console 黑屏属主不是 root:unlchown -R root:unlWeb 界面看不到镜像目录放错位置确认在 addons/qemu 下改了权限还是不行没跑 fixpermissions手动跑一次 wrapper有个细节很多人不注意unl_wrapper 修权限的时候会跳过软链接指向的目录如果你的镜像目录是软链过去的修权限会失效。做镜像老老实实用真实目录别图省事做软链。5.4 镜像体积与启动速度优化镜像大会带来两个直接后果占磁盘以及分发到别的机器上要等很久。我的经验是把最小的可用系统控制在 2G 以内。几个有效手段换成 VirtIO 总线能明显提升磁盘 IO但前提是系统里有驱动Ubuntu、Debian、CentOS 这些主流发行版默认都带。前面说装的时候用 IDE 是为了保险确认驱动齐全之后可以改成 virtio 再测一遍。关闭不需要的服务也能提速snapd、apt-daily、cloud-init 这几个如果不用可以禁用systemctl disable snapd.service snapd.socket systemctl disable apt-daily.timer apt-daily-upgrade.timer内存也要给合理。镜像本身不会记住内存大小内存是每次起节点时给的所以镜像做轻更重要配置里随时能加。一个只想跑 ping 和 traceroute 的节点给 512M 就绰绰有余。6. 我的几条实操心得6.1 关于瘦身的取舍瘦身这件事有个度。我早期做镜像追求极致小把 man 手册、文档、locale 全删了结果后面要用的时候发现连man都打不开还得重装。后来我的原则变成删缓存和日志不删文档删测试数据不删工具。具体来说apt 缓存、临时文件、journal 日志、bash history 这些必删收益大且没有副作用。语言包只保留 en_US能省几百兆也没副作用。但开发工具、调试工具这些只要镜像能控制在 3G 以内我建议留着。实验环境里临时装东西是很痛苦的事尤其是节点没外网的时候。6.2 版本管理与备份镜像做完一定要留一份原始的。我吃过亏一个做好的镜像用了半年里面加了很多脚本配置后来想基于它改个版本改崩了原来的也没备份。现在的做法是每次验证通过的镜像除了放进成品目录还在/data/images-backup/里留一份 tar.gzcd /opt/unetlab/addons/qemu/ tar czf /data/images-backup/linux-myrouter-$(date %Y%m%d).tar.gz linux-myrouter/版本号我用的是日期简单但不重复。如果你要管理多个变体可以在目录名后面加后缀比如linux-myrouter-base、linux-myrouter-full模板文件里分别对应不同的默认内存和网卡数。6.3 让镜像真正能复用的几个技巧镜像的价值在于复用三个技巧我觉得最实用。一是把常用配置写成脚本放在/root/setup.sh进系统后手动跑一下就能初始化好环境这比把配置写死在镜像里灵活因为有些实验需要干净的初始状态。二是在镜像里预留一个 cloud-init 的 hook新建节点时可以传一份 user-data 进去实现自动配 IP、自动下发脚本即便版本对 cloud-init 支持不完整把数据源挂在 cdrom 上手动挂载也是可行的。三是给镜像写一个 README 放在/root/下记录系统版本、装了什么、怎么用、有什么坑过三个月你自己回来都未必记得更别说分享给别人。最后说一个我踩过的坑不要在同一天里既做镜像又改 EVE-NG 本身的配置。两边都出问题时你根本分不清是谁的原因排查成本直接翻倍。做完一个再做下一个出问题好定位这是我用最笨的方法换来的经验。