主题
transformqcow2 — VMware 虚拟机 → qcow2/libvirt 转换工具集
把 VMware 侧导出的虚拟机(.vmdk / .ova / OVF 目录 / .vmx / ESXi SSH / vCenter) 转成 qcow2 + libvirt XML,并按操作系统给出对应的驱动、引导、网络适配建议与检查清单。
支持的系统矩阵(本工具集的目标范围):
windows 2008/2012/2016/2019/2022
rhel 5/6/7/8/9
ubuntu 18.04/20.04/22.04/24.04/对应入口脚本共 14 个(scripts/convert-*.sh),公共逻辑集中在 scripts/lib/common.sh。
1. 目录结构与扩展点
transformqcow2/
├── readme.md # 本文档
└── scripts/
├── lib/common.sh # 公共库:参数解析、环境探测、源识别、转换、
│ # 校验、libvirt XML 生成、日志/报告、汇总
├── selftest.sh # 自检脚本(合成源 + 全矩阵 + 关键特性,可重复跑)
├── convert-rhel5.sh # RHEL/CentOS 5(含 Rocky/Alma 同代)
├── convert-rhel6.sh … convert-rhel9.sh
├── convert-ubuntu-1804.sh … convert-ubuntu-2404.sh
└── convert-windows-2008.sh … convert-windows-2022.sh每个 convert-*.sh 只做三件事:声明系统画像(默认值)→ 实现系统相关钩子 → 调用公共流水线。 新增一个系统 = 复制一个入口脚本,改画像与钩子即可,不需要动公共库。
钩子(均可选,公共库提供默认空实现):
| 钩子 | 用途 |
|---|---|
os_notes | 打印该系统转换前的注意事项清单 |
os_preflight_source | 源相关额外检查(驱动、固件、内核参数等) |
os_prepare | 组装 CUSTOMIZE_ARGS(virt-customize)/ V2V_EXTRA_ARGS(virt-v2v) |
os_manual_hints | img 模式下的手工适配清单 |
os_post_convert | 转换/启动后的检查清单 |
os_parse_arg | 该系统专属参数(如 Windows 的 --win-x86、--virtio-win-dir) |
画像变量(均可选,公共库有兜底默认值): MODE_DEFAULT、FIRMWARE_DEFAULT、DISK_BUS_DEFAULT、NET_MODEL_DEFAULT、 MACHINE_TYPE_DEFAULT、ARCH_DEFAULT、QCOW2_COMPAT_DEFAULT、GUEST_FIX_DEFAULT、 BLOCK_DRIVER_DEFAULT、VCPUS_DEFAULT、MEM_MB_DEFAULT、MEMSIZE_MB_DEFAULT、 ALLOW_MODE_FALLBACK、VIRTIO_WIN_DIR。
2. 前置依赖
必需
| 依赖 | 用途 |
|---|---|
bash ≥ 4.2 | 脚本运行环境(关联数组、${x^^} 等) |
qemu-img | --mode img 转换、镜像信息/容量/校验和 |
按功能可选(缺失时脚本会明确告警并给出安装命令,不会静默降级)
| 依赖 | 缺失时的影响 |
|---|---|
virt-v2v(+ libguestfs-tools、libvirt-daemon) | --mode v2v 不可用。Linux 脚本自动降级为 img 并告警;Windows 2012+ 直接报错退出(避免产出缺驱动、开机蓝屏的镜像);Windows 2008 因允许 ide/e1000 兜底才会降级 |
virt-customize / guestfish | --guest-fix(客户机内重建 initramfs、改主机名、重置 root 密码、SELinux relabel)不可用;脚本改为打印手工适配命令清单 |
OVMF / edk2-ovmf | 无法生成 UEFI/Secure Boot 的 <loader>/<nvram>;脚本明确告警(Secure Boot 需要带 MS 密钥的 *.ms.fd) |
virtio-win(ISO 或目录) | Windows 转换后缺 virtio 磁盘/网卡驱动;脚本告警并给出 --disk-bus sata --net-model e1000 兜底;指定 ISO 时会校验是否含对应系统目录(如 2k19) |
virsh | --define/--autostart 不可用(XML 仍会生成,可手工导入) |
fdisk / sfdisk | 无 libguestfs 时无法对裸盘源自动探测 ESP(UEFI) |
isoinfo / 7z | 无法校验 virtio-win ISO 内容(只提示「无法判定」,不猜) |
xmllint | 仅影响自检脚本对生成 XML 的合法性校验 |
tar(libarchive-tar-perl) | OVA 解包 |
Debian/Ubuntu 一次装齐(示例):
bash
apt install -y qemu-utils virt-v2v libguestfs-tools guestfsd supermin \
ovmf virtio-win libvirt-daemon-system libxml2-utils dosfstools genisoimageRHEL/Rocky/Alma:
bash
dnf install -y qemu-img virt-v2v libguestfs-tools-c edk2-ovmf virtio-win \
libvirt libxml2 util-linux环境变量
| 变量 | 作用 |
|---|---|
VIRTIO_WIN / VIRTIO_WIN_ISO | 覆盖 virtio-win 自动探测路径(等价于 --virtio-win) |
VIRT_V2V_TMPDIR / TMPDIR | virt-v2v overlay 临时目录(建议 ≥ 源实际占用 + 1G) |
LIBGUESTFS_BACKEND | libguestfs appliance 起不来时可试 direct |
NO_COLOR | 置任意值关闭彩色输出(重定向到日志/CI 时有用) |
3. 快速开始
bash
cd scripts
# 1) 本地 vmdk → qcow2 + libvirt XML(RHEL 8,默认走 virt-v2v)
./convert-rhel8.sh -s /data/export/rhel8-app01.vmdk -o /data/out -n rhel8-app01
# 2) 只做格式转换(不动客户机内部),并先预览命令、不落盘
./convert-ubuntu-2204.sh -s /data/export/u22.ova -o /data/out -n u22-web01 \
--mode img --dry-run
# 3) Windows Server 2019(UEFI + Secure Boot,需要 virtio-win 与 OVMF *.ms.fd)
./convert-windows-2019.sh -s /data/export/w2019.ova -o /data/out -n w2019-db01 \
--secure-boot --virtio-win /usr/share/virtio-win/virtio-win.iso
# 4) ESXi 上的 vmx 经 SSH 直接转换(不落本地全量拷贝)
./convert-rhel7.sh \
-s 'ssh://root@10.0.0.11/vmfs/volumes/datastore1/rhel7/rhel7.vmx' \
-o /data/out -n rhel7-app01 --password-file /root/.esxi-pass
# 5) vCenter 经 VDDK 拉取
./convert-rhel9.sh \
-s 'vpx://root@10.0.0.10/DC01/esxi01?no_verify=1' --remote-guest rhel9-app01 \
--transport vddk --vddk-libdir /opt/vmware-vix-disklib-distrib \
--vddk-thumbprint 'AA:BB:CC:DD:EE:FF:...' --password-file /root/.vc-pass \
-o /data/out -n rhel9-app01
# 6) 转换完成后直接注册到 libvirt 并设置自启
./convert-rhel8.sh -s /data/export/rhel8.vmdk -o /data/out -n rhel8-app01 \
--define --autostart任意脚本 -h 会打印「该系统示例 + 全部通用参数」。
4. 两种转换模式
--mode v2v(推荐) | --mode img | |
|---|---|---|
| 工具 | virt-v2v(-of qcow2) | qemu-img convert -O qcow2 |
| 客户机内部 | 会改:注入 virtio 驱动、改引导、--firstboot 脚本、virt-customize 适配 | 完全不改,只换磁盘格式 |
| 适用 | 生产迁移,尤其 Windows | 已经预装 virtio/免驱设备、或只想要 qcow2 文件 |
| 风险 | 依赖 libguestfs appliance 可用 | 客户机内驱动/网络配置需人工处理,否则可能开不了机 |
各系统的 MODE_DEFAULT:除 RHEL 5 默认 img(内核无原生 virtio,v2v 收益低、风险高)外, 其余 13 个系统都默认 v2v。
v2v 不可用时的降级策略(由各系统画像的 ALLOW_MODE_FALLBACK 决定):
- 降级为
img并告警:RHEL 6/7/8/9、Ubuntu 全部、Windows 2008(默认sata/e1000免驱兜底,降级后仍可开机); - 直接报错退出:Windows 2012 / 2016 / 2019 / 2022 —— 缺 virtio 驱动降级到 img 会产出 开机蓝屏(
0x0000007B)的镜像,属于「静默产出坏结果」,必须显式处理。 确要降级请加--allow-mode-fallback,并同时准备驱动方案 (客户机内预装 virtio-win,或用--disk-bus sata --net-model e1000)。
5. 参数速查
位置参数:convert-xxx.sh <源> [<输出目录>](等价于 -s/-o)。
源与目标
| 参数 | 说明 |
|---|---|
-s, --source <路径|URL> | .vmdk / .ova / OVF 目录 / .vmx / 裸盘 / ssh:// / vpx://;源类型自动识别(无 --format 开关,识别不出会告警并按目录/远程/扩展名兜底)。.vmx 在 img 模式会自动展开为它引用的 vmdk 再交给 qemu-img(qemu-img 不认识 .vmx,直接喂给它会被当 raw 读、产出几百字节的垃圾盘);展开不出本地磁盘时 ABORTED 退出并给对策,--mode v2v 则把 .vmx 原样交给 virt-v2v -i vmx |
-o, --out, --out-dir <目录> | 输出目录,默认 ./out |
-n, --name <虚拟机名> | 输出名,默认取源 basename |
--remote-guest <名> | 远程源上的虚拟机名(ssh://、vpx://) |
-it, --transport <vddk|nfc|ssh> | 远程输入传输方式 |
--vddk-libdir <目录> / --vddk-thumbprint <指纹> / --vddk-transports <列表> | VDDK 传输所需 |
--password-file, -ip <文件> | 远程口令文件(建议 0600、无尾换行) |
--remote-size <100G> | 远程源容量(用于空间估算) |
--luks-key <selector> | LUKS 解锁,如 all:key:PASS(对应 virt-v2v --key) |
-y, --yes | 免交互确认(脚本/批量场景) |
--overwrite | 允许覆盖已存在的输出文件(默认拒绝) |
--force-space | 空间估算不足时仍继续 |
--force-source | 跳过源合理性校验(见第 7 节) |
--keep-work | 保留 OVA 解包等临时工作目录(默认清理) |
转换与输出格式
| 参数 | 说明 |
|---|---|
--mode <v2v|img> | 见第 4 节 |
--compress | qcow2 压缩(qemu-img -c)。与 --prealloc 互斥:同用时告警并忽略 --prealloc |
--cluster-size <64k|128k|…> | qcow2 簇大小(Windows/大 IO 建议 128k) |
--compat <0.10|1.1> | qcow2 版本;RHEL5 默认 0.10,其余 1.1 |
--prealloc <off|metadata|falloc|full> | 预分配方式 |
--checksum | 生成 <名称>.sha256 |
--no-check | 跳过转换后的 qemu-img check |
--inspect | 校验阶段额外打印分区/文件系统视图 |
--compare | 校验阶段与源做逐块比对(慢) |
--guest-fix / --no-guest-fix | 是否用 virt-customize 改客户机内部(默认按系统画像,当前全部为 off) |
--selinux-relabel | SELinux 全量 relabel(RHEL 系,需 --guest-fix) |
--hostname <名> / --root-password <口令> | 客户机内改造内容(需 --guest-fix) |
lazy_refcounts无 CLI 开关:内部仅在compat=1.1时才可能启用,--compat 0.10下会告警并强制关闭。
引导 / 设备 / 网络
| 参数 | 说明 |
|---|---|
--firmware <bios|uefi> | 目标固件;未显式指定时才会尝试从源探测 ESP(见第 7 节) |
--uefi / --bios | --firmware 的快捷写法(显式指定后不再自动探测) |
--secure-boot / --no-secure-boot | Secure Boot(隐含 --uefi;XML 加 secure='yes' 与 <smm>,需 OVMF_CODE*.ms.fd + OVMF_VARS.ms.fd) |
--disk-bus <virtio|scsi|sata|ide> | 磁盘总线(默认见第 9 节矩阵) |
--block-driver <virtio-blk|virtio-scsi> | 仅 Windows + --mode v2v 生效 |
--net-model <virtio|e1000|e1000e|rtl8139> | 网卡型号 |
--libvirt-network <名> | XML 用 libvirt NAT 网络(否则走桥接) |
--bridge-name <名> | 桥名,默认 br0 |
--network-map <in:out> | virt-v2v 网络映射,可多次(如 "VM Network:br0") |
--net-style <bridge|network> | 上述映射写成 --bridge 还是 --network,默认 bridge |
--mac-map <mac:…> | virt-v2v --mac 精细映射,可多次 |
--mac <52:54:00:xx:xx:xx> | 在 libvirt XML 中固定 MAC(保留源 MAC);格式非法只告警并忽略,不写入 XML |
--arch <x86_64|i686> | 客户机架构(仅这两种,其他值直接报错);--i386 / --32bit / --i686 是快捷写法,会额外告警:内存 > 3.5G 可能超 32 位上限、32 位 UEFI 需专门 OVMF(建议 --bios) |
--machine-type <q35|pc|…> | libvirt XML 机型;默认 q35,RHEL5/6 与 Windows 2008 为 pc(不做取值校验,可写具体版本如 pc-i440fx-2.0) |
--vcpus <n> / --mem <MiB> | XML 中的 vCPU/内存;未指定时用系统画像默认(见第 9 节,不从 OVF/vmx 读取) |
--memsize <MiB> | 仅 v2v:给转换 appliance 的内存 |
--virtio-win <iso|目录> | 覆盖 virtio-win 自动探测路径 |
--no-xml / --define / --autostart | 不生成 XML / 转换后 virsh define / 设置自启 |
观测
| 参数 | 说明 |
|---|---|
--dry-run | 只预览将执行的命令与 XML,不落盘(见第 7 节) |
--log <文件> | 自定义运行日志路径(默认 <输出目录>/logs/<名称>-<时间戳>.log) |
--report <文件> | 自定义报告 TSV 路径(默认 <输出目录>/convert-report.tsv) |
-h, --help | 打印「该系统示例 + 全部通用参数」 |
没有 --verbose/--quiet 开关:进度信息始终打印到终端并写入日志文件。 未知参数会直接报错退出(未知参数: xxx(用 -h 查看用法)),不会静默忽略; 系统专属参数由各脚本的 os_parse_arg 钩子消费。
Windows 专属:--win-x86(2008,切 i686 + 2k8 驱动目录)、--win-nonr2(2012,切 2k12)、 --virtio-win-dir <名>(覆盖驱动目录名)。
6. 输出物
一次成功转换后,输出目录内包含:
<outdir>/
├── <名称>.qcow2 # 转换结果
├── <名称>-disk2.qcow2 … # 多盘源的第 2、3… 块盘
├── <名称>.libvirt.xml # libvirt 域定义(--no-xml 可关闭)
├── <名称>.sha256 # --checksum 时生成
├── logs/
│ └── <名称>-<时间戳>.log # 本次运行完整日志(含将执行/已执行的命令、环境快照、告警)
└── convert-report.tsv # 一行一机的报告,便于批量归档convert-report.tsv 列(Tab 分隔,含表头):
时间 系统 虚拟机 源 源类型 模式 虚拟容量 输出文件 输出大小 磁盘总线 固件 耗时(s) 状态状态取值:SUCCESS / FAILED / ABORTED(rc=N) / SKIPPED。即使中途报错退出也会写入一行, 方便批量转换后统计;异常时 qcow2 若已部分生成会被标记为 <未完成>。
libvirt XML 要点(实际样例见 logs/ 同目录的 <名称>.libvirt.xml):
<domain type='kvm'>,<type arch='…' machine='…'>hvm</type>,<cpu mode='host-passthrough'>;<loader readonly='yes' type='pflash'>+<nvram template=…>仅在固件为 UEFI 时写入; OVMF 按固定顺序探测:/usr/share/OVMF/OVMF_CODE.ms.fd→OVMF_CODE.secboot.fd→OVMF_CODE.fd→/usr/share/edk2/ovmf/*→/usr/share/qemu/OVMF.fd; 一个都没找到时写占位路径并告警(需手工修正);--secure-boot:<loader … secure='yes'>+<features>里补<smm state='on'/>。 若探测到的固件不是*.ms.fd/*secboot*,仍会写secure='yes'但告警 (缺 MS 密钥时 libvirt 会启动失败),需补装ovmf/edk2-ovmf或改用--uefi;--arch i686只影响arch属性与<emulator>(优先qemu-system-i386), 不会换成 32 位 OVMF —— 32 位客户机请配--bios;<mac address='…'/>仅在--mac通过格式校验时写入(非法只告警并忽略);- Windows 客户机额外写
<hyperv mode='custom'>特性集、<clock offset='localtime'>+rtc/pit/hpet计时器、<vmport state='off'/>;Linux 用<clock offset='utc'>; - 磁盘按
--disk-bus生成<target dev=…>(virtio→vda/vdb、ide→hda、sata/scsi→sda), 驱动统一cache='none' io='native' discard='unmap'; - 网络默认
<interface type='bridge'>+--bridge-name(默认br0), 指定--libvirt-network则改为<interface type='network'>。
7. 安全与可预期行为
--dry-run(严格只读)
- 只打印将要执行的命令与将要生成的 XML(预览到终端), 不创建输出目录、不写日志文件、不写 XML 文件、不写报告 TSV、不解包 OVA 到磁盘;
- 因此 dry-run 阶段无法读取 OVA/多盘目录内部的真实清单(日志里会说明);
- XML 预览先写入
mktemp临时文件再cat到当前 stdout(不写/dev/stdout:stdout 被重定向到 普通文件时重开会以O_TRUNC清空之前打印的预检输出),预览文件随即删除; 「已生成 XML / virsh define」提示给的是正式运行时的落盘路径,不是那个临时文件; - 日志里会明确写出「未执行转换」「未产出文件,跳过完整性校验」「XML 仅预览未落盘」, 不会让人误以为已经转好了;
- 空间检查在输出目录尚不存在时,会自动回退到最近的已存在父目录(避免因目录未创建而报错退出)。
源合理性校验(validate_source_sanity)
对每个已识别的磁盘检查,任一失败即 ABORTED 退出(可用 --force-source 跳过):
| 检查 | 拦截的问题 |
|---|---|
qemu-img info 能读到格式 | 文件损坏、权限不足、不是磁盘镜像 |
| 扩展名与实际格式一致 | .vmdk 其实是 raw(qemu-img 会静默当 raw 转换,产出错误结果) |
| descriptor 型 VMDK 的 extent 文件齐全 | 只拷了 .vmdk 描述符、漏了 -flat.vmdk / 分片 |
.vmx 引用的磁盘本地存在且可识别 | 只拷了 .vmx、vmdk 仍在 datastore 上;.vmx 被当磁盘喂给 qemu-img |
| 虚拟容量 ≥ 100MiB | 空文件、日志文件被误当磁盘 |
| 磁盘数量 ≥ 1 | 目录里根本没有磁盘 |
| 输出虚拟容量 ≥ 源的一半 | 源被误读(如把 .vmx/.ovf 当磁盘)导致产出垃圾盘 |
固件(BIOS/UEFI)探测
优先级:--firmware/--uefi/--secure-boot 显式指定 > 源探测 > 系统画像默认。
探测手段(按可靠性排序,只做能确证的判断):
- 元数据声明:
.vmx的firmware = "efi"/"bios"、OVF/OVA 的ovf:firmware(EFI/BIOS)—— 最可靠,且--dry-run下同样有效(OVA 不解包,只扫归档头部 64MiB 内的 OVF); - libguestfs(
guestfish)可用时:part-get-parttype+part-get-gpt-type找 ESP (.vmx源会先展开为其引用的 vmdk 再探测); - 裸盘源(
.raw/无扩展名/.img):fdisk -l找EFI System,或sfdisk找分区类型EF; - 分区表可读且确认没有 ESP → 固件明确判为 BIOS(不留「未知」);
- 既无元数据又读不到分区表(dry-run 下的 OVA/OVF 目录、
ssh:///vpx://远程源)→ 暂不判定,日志写明原因与人工确认方法;这类源在转换完成后会按输出盘补判一次。
补充:
.vmx里efi64.secureBoot.enabled = "TRUE"而本次未开--secure-boot→ 告警提示 「源可能是 Secure Boot 引导,请加--secure-boot」(不自动改固件,避免误判);- 判定结果与依据统一打印一行「依据「…」判定源为 … → …」,
--firmware显式指定时不再重复探测; - qcow2/VMDK 等镜像格式不会尝试直读分区表(会报错且结论不可靠);
virt-fw-vars只读 EFI 变量存储文件,不能用于源磁盘。
空间与覆盖保护
- 转换前估算:输出 = 源实际占用 ×1.2 + 256M(
--compress时 ×0.7 + 256M); v2v 临时目录(VIRT_V2V_TMPDIR/TMPDIR)≈ 实际占用 + 1G。 输出目录不足 → 直接退出;临时目录不足 → 告警并退出。确要继续加--force-space; - 远程源(
ssh:///vpx://)无法估算容量时跳过空间检查并告警,可用--remote-size 100G指定; - 输出目录尚不存在时(例如
--dry-run),空间检查自动回退到最近的已存在祖先目录; - 输出文件已存在时拒绝执行,提示
--overwrite或换-n; --overwrite会直接重转并覆盖同名文件(img 模式由qemu-img覆写;v2v 产物再重命名为<名称>.qcow2/<名称>-diskN.qcow2)。转换中途失败时残缺文件会留在原地, 但报告状态记为FAILED/ABORTED(rc=N),不会被当成成功;重跑请先删除或继续--overwrite。
8. 自检脚本
scripts/selftest.sh 用合成源(稀疏 VMDK、descriptor+flat 两段式 VMDK、GPT+ESP 裸盘、 MBR 裸盘、OVA、多盘目录、垃圾镜像)覆盖全部脚本与关键特性,不需要真实 VMware 导出, 也不需要 libvirt/KVM;缺工具的用例自动 SKIP。
bash
cd scripts
./selftest.sh # 全量自检(mktemp 建临时目录,结束后自动清理)
./selftest.sh -q # 快速模式:第 2 节矩阵只跑 rhel5/rhel9/ubuntu-2204/windows-2019,其余不变
./selftest.sh -k # 保留临时工作目录,便于排查
./selftest.sh -w /tmp/st -k # 指定工作目录(配合 -k 保留现场复现)
./selftest.sh -h # 用法退出码:0=全部通过(SKIP 不算失败)、1=有 FAIL(自动保留工作目录并列出失败用例)、 2=前置条件不满足(缺 qemu-img、mktemp 失败、未知参数)。
覆盖内容(12 节):
bash -n语法检查 +shellcheck -S error(如已安装)- 全矩阵:14 个
convert-*.sh×--mode img,校验 qcow2 格式/容量、XML 合法性、汇总状态、报告 TSV、运行日志 --dry-run无副作用(含 OVA 源;XML 预览写临时文件再cat,不污染重定向到文件时的预检输出)- 覆盖保护 /
--overwrite/--no-xml - ESP 自动探测、MBR 明确判 BIOS、
.vmx/OVA 元数据判固件(含 dry-run)、Secure Boot 元数据告警、--uefi、--secure-boot(SMM +*.ms.fd)、--no-secure-boot --arch/--32bit/ 默认 x86_64 /--machine-type- 各系统默认值与降级策略(RHEL5 保守栈、RHEL6 降级、Windows 2008 免驱、Windows 2019 拒绝静默降级)
- 源类型覆盖:descriptor+flat VMDK、OVA(含解包与临时目录清理)、多盘目录(多
<disk>XML)、 本地.vmx(展开为引用的 vmdk、跳过光驱与present="FALSE"、引用盘缺失时ABORTED)、virt-v2v命令构造(单元级:-i vmx/ova必带源位置参数、-ic连接串不重复) - 源合理性校验与异常退出记录(含
--force-source) - 选项覆盖:
--mac、--bridge-name、--libvirt-network、--vcpus/--mem、--checksum、--compress/--prealloc冲突、--cluster-size、--compat 0.10、--report/--log - 客户机适配提示、手工清单、
virtio-win目录/ISO 校验(单元级) - 全部脚本
-h帮助完整性
9. 各系统默认值矩阵
固件默认全部为 bios;UEFI 通过源探测(OVF ovf:firmware / ESP)或 --uefi、--secure-boot 指定。
| 系统 | 模式 | 磁盘总线 | 网卡 | 机型 | qcow2 compat | vCPU / 内存(MiB) | v2v memsize | 缺 virt-v2v 时 |
|---|---|---|---|---|---|---|---|---|
| RHEL / CentOS 5 | img | ide | e1000 | pc | 0.10 | 2 / 2048 | 2048 | 本就是 img |
| RHEL / CentOS 6 | v2v | virtio | virtio | pc | 1.1 | 2 / 4096 | 3072 | 降级 img + 告警 |
| RHEL / CentOS 7 | v2v | virtio | virtio | q35 | 1.1 | 2 / 4096 | 4096 | 降级 img + 告警 |
| RHEL / Rocky / Alma 8 | v2v | virtio | virtio | q35 | 1.1 | 2 / 4096 | 4096 | 降级 img + 告警 |
| RHEL / Rocky / Alma 9 | v2v | virtio | virtio | q35 | 1.1 | 2 / 4096 | 4096 | 降级 img + 告警 |
| Ubuntu 18.04 | v2v | virtio | virtio | q35 | 1.1 | 2 / 4096 | 3072 | 降级 img + 告警 |
| Ubuntu 20.04 | v2v | virtio | virtio | q35 | 1.1 | 2 / 4096 | 4096 | 降级 img + 告警 |
| Ubuntu 22.04 | v2v | virtio | virtio | q35 | 1.1 | 2 / 4096 | 4096 | 降级 img + 告警 |
| Ubuntu 24.04 | v2v | virtio | virtio | q35 | 1.1 | 2 / 4096 | 4096 | 降级 img + 告警 |
| Windows 2008 / 2008 R2 | v2v | sata | e1000 | pc | 1.1 | 2 / 4096 | 4096 | 降级 img(免驱兜底) |
| Windows 2012 / 2012 R2 | v2v | virtio | virtio | q35 | 1.1 | 2 / 4096 | 4096 | 报错退出 |
| Windows 2016 | v2v | virtio | virtio | q35 | 1.1 | 4 / 8192 | 4096 | 报错退出 |
| Windows 2019 | v2v | virtio | virtio | q35 | 1.1 | 4 / 8192 | 8192 | 报错退出 |
| Windows 2022 | v2v | virtio | virtio | q35 | 1.1 | 4 / 8192 | 8192 | 报错退出 |
Windows 的 virtio-win 驱动目录名(VIRTIO_WIN_DIR):2008→2k8R2、2012→2k12R2、 2016→2k16、2019→2k19、2022→2k22;--win-x86(2008)切 2k8 + i686, --win-nonr2(2012)切 2k12。
各系统关键注意点(脚本运行时会打印对应清单,这里是要点摘录)
- RHEL 5:
ide/e1000免驱栈 +qcow2 compat 0.10;initramfs 里通常没有 virtio 驱动, 改 virtio 前必须在客户机内mkinitrd;/etc/modprobe.conf里可能残留alias eth0 pcnet32。 - RHEL 6:initramfs 需含
virtio_blk/virtio_scsi/virtio_pci(dracut --force);70-persistent-net.rules会按旧 MAC 绑定网卡名,迁移后网卡可能变eth1导致无网络。 - RHEL 7/8/9:
dracut --force+ NetworkManager 连接按 MAC 绑定;SELinux 环境改动后建议--selinux-relabel; RHEL 8/9 若源是 UEFI,需确认grub2-efi-x64与shimx64已装。 - Ubuntu 18.04+:netplan 的
match: macaddress会让网卡改名后失联;update-initramfs -u; 云上镜像可能带cloud-init,迁移后需清理instance-id或禁用数据源。 - Windows:必须预装/注入 virtio-win(
viostor、netkvm、balloon、qxl); 转换后首次启动建议bcdedit /set {current} bootstatuspolicy ignoreallfailures; 域控角色要记录 FSMO、核对时间同步(Kerberos 容忍 5 分钟); 激活方式(KMS/MAK)、静态路由、盘符布局要提前记录。
10. 故障排查
| 现象 | 原因与处理 |
|---|---|
virt-v2v: command not found / 提示缺依赖 | 装 virt-v2v + libguestfs-tools;Linux 会自动降级 img(有告警),Windows 2012+ 会退出 |
libguestfs appliance launch failed / supermin 报错 | 装 guestfsd supermin linux-image-*;或 export LIBGUESTFS_BACKEND=direct;无 /dev/kvm 权限时把用户加入 kvm 组 |
Windows 转换后开机蓝屏 0x0000007B | 缺 virtio 磁盘驱动。用 --mode v2v --virtio-win <iso>;或临时 --disk-bus sata --net-model e1000 起来后再装驱动 |
| UEFI 源转完起不来 / 进了 BIOS 引导菜单 | 固件判定错了。用 --uefi 显式指定;确认 OVMF 已装;--arch i686 客户机不能用 64 位 OVMF_CODE.fd |
Secure Boot 客户机报 secure='yes' 相关错误 | 需要带 MS 密钥的 OVMF_CODE*.ms.fd;缺失时脚本会退回普通 UEFI 并告警,请补装 ovmf/edk2-ovmf |
| Linux 迁移后网卡名变了、拿不到 IP | 旧 MAC 绑定。改 netplan/ifcfg 的 MAC 匹配,或删 70-persistent-net.rules 后重建 initramfs;也可用 --mac 固定回旧 MAC |
| 找不到系统盘 / initramfs panic | initramfs 无 virtio 驱动。dracut --force(RHEL)或 update-initramfs -u(Ubuntu);脚本会枚举客户机 /lib/modules 下的内核版本给出具体命令 |
.vmdk 转换结果异常(大小/内容不对) | 该文件其实是 raw,或 descriptor 的 extent 缺失。源合理性校验会拦下;确认无误再用 --force-source |
以 .vmx 为源,产出的 qcow2 只有几百字节 / 起不来 | qemu-img 不认识 .vmx(会当 raw 读)。工具在 img 模式已自动展开为其引用的 vmdk,并在输出侧比对虚拟容量兜底;若展开不出本地磁盘会 ABORTED,按提示把 vmdk 下载到 vmx 同目录、或改 --mode v2v、或直接把 .vmdk/.ova 作为 -s |
.vmx 展开失败:vmx 引用的磁盘在本地不存在 | vmdk 仍在 datastore 上(只拷了 vmx)。补齐 vmdk(或改 vmx 里的 fileName 为实际路径);远程可用 --mode v2v 让 virt-v2v 自己解析 |
| 输出目录空间不足 | 预检按「源实际占用 × 1.5」拦截;换目录或清理后重跑 |
| 输出文件已存在被拒绝 | 加 --overwrite(原子替换)或换 -n |
| OVA 解包失败 | 装 tar(libarchive-tar-perl);OVA 内含 ovf + vmdk,也可先手工解包后用目录作为源 |
远程 ssh:// / vpx:// 连不上 | 检查 --password-file、--vddk-libdir、--vddk-thumbprint;先用 --dry-run 看命令 |
| 想看将要执行什么但不落盘 | --dry-run(严格只读,连输出目录都不建) |
| 日志/报告在哪 | 输出目录内 run-<名称>-<时间戳>.log 与 convert-report.tsv;可用 --log/--report 指定路径 |
11. 已知限制
--dry-run阶段无法读取 OVA/多盘目录内部真实清单(不落盘就不解包),因此该模式下的磁盘列表是保守估计;--dry-run下的固件判定依赖元数据(.vmx的firmware=、OVA 头部 OVF 的ovf:firmware); 元数据里没有声明时不猜,日志写明「暂不判定」,转换完成后按输出盘补判;- OVA 的元数据扫描只读归档头部 64MiB(OVF 通常在最前),避免为找 firmware 声明而读完整个大文件;
- ESP/UEFI 自动探测对 qcow2/VMDK 源在无 libguestfs 的机器上无法进行,会保持系统默认(日志有提示);
- img 模式的
.vmx源要求其引用的 vmdk 已在本地(工具不会去 datastore 拉取); --guest-fix依赖可用的 libguestfs appliance;失败时脚本会终止并记录ABORTED,不会留下改坏一半的镜像;- 多盘源的主盘按 OVF/vmx 声明或文件名排序选取,特殊布局请核对日志中的磁盘清单;
- 转换过程只读源,但 OVA 解包与 virt-v2v overlay 会占用临时空间(
VIRT_V2V_TMPDIR/TMPDIR)。