《V2V 迁移实战:将 VMware 虚拟机转为 OpenStack 可用 Glance qcow2 镜像》

目录

一、源虚拟机准备

[1.1 修改 GRUB 启动参数](#1.1 修改 GRUB 启动参数)

[1.2 清理 SSH 主机密钥](#1.2 清理 SSH 主机密钥)

二、安装转换工具

三、执行镜像转换

[3.1 首次转换尝试与问题排查](#3.1 首次转换尝试与问题排查)

[3.2 启动 libvirt 服务](#3.2 启动 libvirt 服务)

四、系统清理与镜像瘦身

[4.1 清理系统敏感信息](#4.1 清理系统敏感信息)

[4.2 稀疏化压缩镜像](#4.2 稀疏化压缩镜像)

[五、上传镜像到 OpenStack](#五、上传镜像到 OpenStack)

六、创建云主机并验证

[6.1 创建云主机](#6.1 创建云主机)

[6.2 绑定浮动 IP](#6.2 绑定浮动 IP)

[6.3 连接数据磁盘](#6.3 连接数据磁盘)

七、总结


一、源虚拟机准备

首先创建一个新的centos7虚拟机

在开始迁移前,需要先对源虚拟机进行一些基础配置,确保其能够适配目标虚拟化平台。主要包括修改 GRUB 启动参数、清理 SSH 主机密钥等操作。

1.1 修改 GRUB 启动参数

首先编辑 GRUB 默认配置文件,为内核添加串口控制台参数,便于后续通过控制台进行管理和排障。

cpp 复制代码
[root@localhost ~]# vim /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="console=tty0 console=ttyS0,115200n8"
GRUB_DISABLE_RECOVERY="true"

修改完成后,需要重新生成 GRUB 配置文件,并在启动配置中追加 net.ifnames=0 参数以禁用网卡命名规则,最后重启系统使配置生效。

cpp 复制代码
[root@localhost ~]# grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.0-1160.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-1160.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-bf96eebeae3241c992e29f7197ef0629
Found initrd image: /boot/initramfs-0-rescue-bf96eebeae3241c992e29f7197ef0629.img
done
[root@localhost ~]# vim /boot/grub2/grub.cfg
在里面新加入的代码行添加 "net.ifnames=0"
[root@localhost ~]# reboot

1.2 清理 SSH 主机密钥

为避免迁移后多台虚拟机使用相同的主机密钥导致 SSH 连接冲突,需要清理源虚拟机中的 SSH 主机密钥文件,系统会在下次启动时自动重新生成。

cpp 复制代码
[root@localhost ~]# yum clean all
Loaded plugins: fastestmirror
Cleaning repos: base extras updates
Cleaning up list of fastest mirrors
[root@localhost ~]# cd /etc/ssh
[root@localhost ssh]# ll ssh_host_*
-rw-r-----. 1 root ssh_keys  227 Aug 27 18:36 ssh_host_ecdsa_key
-rw-r--r--. 1 root root      162 Aug 27 18:36 ssh_host_ecdsa_key.pub
-rw-r-----. 1 root ssh_keys  387 Aug 27 18:36 ssh_host_ed25519_key
-rw-r--r--. 1 root root       82 Aug 27 18:36 ssh_host_ed25519_key.pub
-rw-r-----. 1 root ssh_keys 1675 Aug 27 18:36 ssh_host_rsa_key
-rw-r--r--. 1 root root      382 Aug 27 18:36 ssh_host_rsa_key.pub
[root@localhost ssh]# rm -f ssh_host_*
[root@localhost ssh]# ll
total 580
-rw-r--r--. 1 root root 581843 Aug  9  2019 moduli
-rw-r--r--. 1 root root   2276 Aug  9  2019 ssh_config
-rw-------. 1 root root   3907 Aug  9  2019 sshd_config
[root@localhost ssh]# poweroff

完成以上操作后,关闭源虚拟机,准备导出镜像。

二、安装转换工具

在目标服务器上,需要安装 guestfs-toolsvirt-v2v 两个工具包,用于后续的镜像转换和系统清理操作。同时确认 virtio-win 驱动包已安装,以保证转换后的虚拟机能够正常识别虚拟化设备。

cpp 复制代码
[root@server1 ~]# yum install -y guestfs-tools.x86_64
[root@server1 ~]# yum install -y virt-v2v.x86_64
[root@server1 ~]# yum list virtio-win
Last metadata expiration check: 0:20:16 ago on Wed 02 Sep 2026 02:55:47 PM CST.
Installed Packages
virtio-win.noarch                                             1.9.58-0.el9_8
[root@server1 ~]# cd /opt/
[root@server1 opt]# ls
[root@server1 opt]# mkdir v2v
[root@server1 opt]# ls
v2v
[root@server1 opt]# cd v2v/
[root@server1 v2v]# pwd
/opt/v2v

创建 /opt/v2v 目录作为转换输出目录,后续生成的镜像文件都会存放在这里。

三、执行镜像转换

3.1 首次转换尝试与问题排查

执行 virt-v2v 命令将 OVA 格式的虚拟机转换为 qcow2 格式。首次执行时可能会遇到 libvirt 服务未启动的错误,需要先排查并解决。

cpp 复制代码
[root@server1 ~]# virt-v2v -i ova demo.ova  -o local -of qcow2 -os /opt/v2v/
virt-v2v: error: exception: libvirt: VIR_ERR_OPERATION_UNSUPPORTED:
VIR_FROM_REMOTE: Operation not supported: No URI is provided and cannot
identify any listening daemon socket path to attempt to connect to. Please
ensure the expected daemon sockets are active and/or provide an explicit
URI. For more information see
https://libvirt.org/kbase/failed_connection_after_install.html
If reporting bugs, run virt-v2v with debugging enabled and include the
complete output:
virt-v2v -v -x [...]
[root@server1 ~]# systemctl status virtqemud
○ virtqemud.service - libvirt QEMU daemon
Loaded: loaded (/usr/lib/systemd/system/virtqemud.service; enabled; preset: enabled)
Active: inactive (dead)
TriggeredBy: ○ virtqemud.socket
○ virtqemud-admin.socket
○ virtqemud-ro.socket
Docs: man:virtqemud(8)
https://libvirt.org/

检查发现 virtqemud 服务处于未激活状态,其对应的 socket 监听单元也未启动。

cpp 复制代码
[root@server1 ~]# systemctl status virtqemud.socket virtqemud-admin.socket virtqemud-ro.socket
○ virtqemud.socket - libvirt QEMU daemon socket
     Loaded: loaded (/usr/lib/systemd/system/virtqemud.socket; enabled; preset: enabled)
     Active: inactive (dead)
   Triggers: ● virtqemud.service
     Listen: /run/libvirt/virtqemud-sock (Stream)
○ virtqemud-admin.socket - libvirt QEMU daemon admin socket
Loaded: loaded (/usr/lib/systemd/system/virtqemud-admin.socket; enabled; preset: enabled)
Active: inactive (dead)
Triggers: ● virtqemud.service
Listen: /run/libvirt/virtqemud-admin-sock (Stream)
○ virtqemud-ro.socket - libvirt QEMU daemon read-only socket
Loaded: loaded (/usr/lib/systemd/system/virtqemud-ro.socket; enabled; preset: enabled)
Active: inactive (dead)
Triggers: ● virtqemud.service
Listen: /run/libvirt/virtqemud-sock-ro (Stream)

3.2 启动 libvirt 服务

手动创建 /run/libvirt 目录并设置正确的属主和权限,然后启动并启用相关的 socket 服务。

cpp 复制代码
[root@server1 ~]# mkdir -p /run/libvirt
[root@server1 ~]# chown root:root /run/libvirt
[root@server1 ~]# chmod 700 /run/libvirt
[root@server1 ~]# systemctl stop virtqemud.socket virtqemud-admin.socket virtqemud-ro.socket virtqemud.service
[root@server1 ~]# systemctl enable --now virtqemud.socket virtqemud-admin.socket virtqemud-ro.socket
[root@server1 ~]# systemctl status virtqemud.socket virtqemud-admin.socket virtqemud-ro.socket
● virtqemud.socket - libvirt QEMU daemon socket
     Loaded: loaded (/usr/lib/systemd/system/virtqemud.socket; enabled; preset: enabled)
     Active: active (listening) since Wed 2026-09-02 15:28:37 CST; 8s ago
      Until: Wed 2026-09-02 15:28:37 CST; 8s ago
   Triggers: ● virtqemud.service
     Listen: /run/libvirt/virtqemud-sock (Stream)
     CGroup: /system.slice/virtqemud.socket
Sep 02 15:28:37 server1 systemd[1]: Listening on libvirt QEMU daemon socket.
● virtqemud-admin.socket - libvirt QEMU daemon admin socket
Loaded: loaded (/usr/lib/systemd/system/virtqemud-admin.socket; enabled; preset: enabled)
Active: active (listening) since Wed 2026-09-02 15:28:37 CST; 8s ago
Until: Wed 2026-09-02 15:28:37 CST; 8s ago
Triggers: ● virtqemud.service
Listen: /run/libvirt/virtqemud-admin-sock (Stream)
CGroup: /system.slice/virtqemud-admin.socket
Sep 02 15:28:37 server1 systemd[1]: Listening on libvirt QEMU daemon admin socket.
● virtqemud-ro.socket - libvirt QEMU daemon read-only socket
Loaded: loaded (/usr/lib/systemd/system/virtqemud-ro.socket; enabled; preset: enabled)
Active: active (listening) since Wed 2026-09-02 15:28:37 CST; 8s ago
Until: Wed 2026-09-02 15:28:37 CST; 8s ago
Triggers: ● virtqemud.service
Listen: /run/libvirt/virtqemud-sock-ro (Stream)
CGroup: /system.slice/virtqemud-ro.socket
Sep 02 15:28:37 server1 systemd[1]: Listening on libvirt QEMU daemon read-only socket.

服务启动成功后,重新执行 virt-v2v 转换命令。

cpp 复制代码
[root@server1 ~]# virt-v2v -i ova demo.ova  -o local -of qcow2 -os /opt/v2v/
[   0.0] Setting up the source: -i ova demo.ova
virt-v2v: warning: making OVA directory public readable to work around
libvirt bug https://bugzilla.redhat.com/1045069
[   9.0] Opening the source
[  53.2] Inspecting the source
[  73.0] Checking for sufficient free disk space in the guest
[  73.0] Converting CentOS Linux release 7.9.2009 (Core) (centos7.0) to run on KVM
virt-v2v: The QEMU Guest Agent will be installed for this guest at first
boot.
** (process:8301): WARNING **: 15:41:10.077: Entity http://pcisig.com/pci/1af4/1012 referenced but not defined
virt-v2v: This guest has virtio drivers installed.
[ 606.8] Setting a random seed
[ 607.0] SELinux relabelling
[ 615.4] Mapping filesystem data to avoid copying unused and blank areas
[ 618.4] Closing the overlay
[ 618.9] Assigning disks to buses
[ 618.9] Checking if the guest needs BIOS or UEFI to boot
[ 618.9] Setting up the destination: -o disk -os /opt/v2v/
[ 620.0] Copying disk 1/1
█ 100% [****************************************]
[ 635.3] Creating output metadata
[ 635.3] Finishing off

转换完成后,在输出目录中会生成磁盘文件 demo-sda 和描述文件 demo.xml

cpp 复制代码
[root@server1 ~]# cd /opt/v2v/
[root@server1 v2v]# ls
demo-sda  demo.xml
[root@server1 v2v]# du -h demo-sda
1.4G    demo-sda

四、系统清理与镜像瘦身

4.1 清理系统敏感信息

使用 virt-sysprep 工具对转换后的磁盘进行系统清理,移除主机密钥、历史命令、日志等敏感信息,确保镜像可以安全分发。

cpp 复制代码
[root@server1 v2v]# virt-sysprep -a demo-sda
[   0.0] Examining the guest ...
[  51.7] Performing "abrt-data" ...
[  51.8] Performing "backup-files" ...
[  60.2] Performing "bash-history" ...
[  60.3] Performing "blkid-tab" ...
[  60.5] Performing "crash-data" ...
[  60.6] Performing "cron-spool" ...
[  60.8] Performing "dhcp-client-state" ...
[  60.9] Performing "dhcp-server-state" ...
[  60.9] Performing "dovecot-data" ...
[  61.0] Performing "ipa-client" ...
[  61.1] Performing "kerberos-hostkeytab" ...
[  61.2] Performing "logfiles" ...
[  63.1] Performing "lvm-system-devices" ...
[  63.2] Performing "machine-id" ...
[  63.4] Performing "mail-spool" ...
[  63.4] Performing "net-hostname" ...
[  64.0] Performing "net-hwaddr" ...
[  64.5] Performing "net-nmconn" ...
[  64.7] Performing "pacct-log" ...
[  64.9] Performing "package-manager-cache" ...
[  65.3] Performing "pam-data" ...
[  65.4] Performing "passwd-backups" ...
[  65.5] Performing "puppet-data-log" ...
[  65.6] Performing "rh-subscription-manager" ...
[  65.8] Performing "rhn-systemid" ...
[  65.9] Performing "rpm-db" ...
[  66.0] Performing "samba-db-log" ...
[  66.2] Performing "script" ...
[  66.2] Performing "smolt-uuid" ...
[  66.3] Performing "ssh-hostkeys" ...
[  66.4] Performing "ssh-userdir" ...
[  66.5] Performing "sssd-db-log" ...
[  66.6] Performing "tmp-files" ...
[  67.0] Performing "udev-persistent-net" ...
[  67.1] Performing "utmp" ...
[  67.2] Performing "yum-uuid" ...
[  67.3] Performing "customize" ...
[  67.4] Setting a random seed
[  67.6] Setting the machine ID in /etc/machine-id
[  67.6] SELinux relabelling
[  75.7] Performing "lvm-uuids" ...

清理完成后,确认磁盘文件大小没有明显变化。

cpp 复制代码
[root@server1 v2v]# ls
demo-sda  demo.xml
[root@server1 v2v]# du -h demo-sda
1.4G    demo-sda

4.2 稀疏化压缩镜像

使用 virt-sparsify 对磁盘进行稀疏化处理并压缩,去除空闲空间的零字节数据,生成最终的 demo.qcow2 镜像文件。

cpp 复制代码
[root@server1 v2v]# virt-sparsify --compress demo-sda demo.qcow2
[   0.1] Create overlay file in /tmp to protect source disk
[   0.1] Examine source disk
 100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ 00:00
[  43.9] Fill free space in /dev/sda1 with zero
 100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ 00:00
[ 108.4] Copy to destination and make sparse
[ 202.3] Sparsify operation completed with no errors.
virt-sparsify: Before deleting the old disk, carefully check that the
target disk boots and works correctly.
[root@server1 v2v]# ls
demo.qcow2  demo-sda  demo.xml
[root@server1 v2v]# du -h demo.qcow2
653M    demo.qcow2

经过稀疏化压缩后,镜像从 1.4G 缩减到 653M,体积减少了约一半,便于后续上传和存储。

五、上传镜像到 OpenStack

使用 admin 身份登录 OpenStack 控制台,在镜像服务中创建新镜像,选择刚才导出的 demo.qcow2 文件进行上传。

镜像上传完成后,还需要创建一个 m3.nano 规格的云主机类型,用于后续创建云主机实例。

六、创建云主机并验证

6.1 创建云主机

切换到 demo 用户,在计算服务中新建云主机。选择刚才创建好的镜像源,网络选择私有网络,并导入安全组和密钥对,确保云主机可以正常访问。

6.2 绑定浮动 IP

云主机创建完成后,为云主机 ecs-3 添加浮动 IP,使其能够通过公网地址进行访问。

6.3 连接数据磁盘

打开云主机的控制台,确认系统能够正常启动并进入操作系统。

最后,将 my_disk 数据磁盘连接到云主机 ecs-3,完成整个迁移和数据挂载流程。

七、总结

本文详细介绍了将本地虚拟机迁移到 OpenStack 云平台的完整流程,主要分为以下几个关键步骤:

  • 源虚拟机准备:修改 GRUB 串口参数、清理 SSH 主机密钥,确保迁移后系统可正常启动且无安全残留。

  • 镜像转换:使用 virt-v2v 将 OVA 格式转换为 qcow2 格式,期间需确保 libvirt 服务正常运行。

  • 系统清理与瘦身:通过 virt-sysprep 清理敏感信息,再用 virt-sparsify 压缩镜像体积,从 1.4G 缩减至 653M。

  • 上传与创建:在 OpenStack 中上传镜像、创建云主机类型,并完成实例创建、浮动 IP 绑定和数据盘挂载。

通过以上步骤,即可将本地虚拟机平滑迁移到 OpenStack 云平台,实现资源的统一管理和灵活调度。

相关推荐
2601_962381581 小时前
【转】Python渗透测试工具:sqlmap
python·渗透测试·sql注入·sqlmap·数据库安全
用户3721574261352 小时前
如何使用 Python 从 Word 文档中提取图片
python
黑马程序员毕设3 小时前
基于Java的医院药品管理系统的优化设计与实现
java·开发语言·spring boot·小程序·架构·课程设计·毕设
白山编程大哥3 小时前
Java 集合算法:从排序、查找到底层原理的实战指南
java·python·算法
_Twink1e4 小时前
openJiuwen 实训营 Day 1 · WorkSwarm 入门教程
开发语言·c++·openjiuwen
问天_观心4 小时前
大模型微调学习(一)
开发语言·人工智能·学习·语言模型·github
阿里嘎多学长4 小时前
2026-09-03 GitHub 热点项目精选
开发语言·程序员·github·代码托管
昭昭日月明5 小时前
RAGFlow 入门,不用从零造轮子
python·ai编程
源代码•宸5 小时前
前置准备:定时微服务背景和现状
开发语言·经验分享·后端·微服务·云原生·架构·golang