☰
宿主机要重启、业务不能停?KVM 热迁移 + NFS 共享存储实操记录
2026/10/28 10:14:02 网站建设 项目流程

生产机上的一次重启,往往意味着一片业务的停顿。KVM 热迁移要解决的就是这件事:把一台正在运行的虚拟机从 A 宿主机搬到 B 宿主机,业务几乎无感知。这篇用一套三节点实验(KVM1 / KVM2 / NFS)走完「克隆 → 配网络 → 搭共享存储 → 建虚拟机 → 迁移 → 验收 → 迁回」的完整链路,并把课件里没写的迁移命令、SSH 免密前提和回退步骤一并补齐。文中命令名均标注英文全称(如virsh= virtual shell),完整清单见文末《附:命令英文全称速查表》。

本文概要:

项目内容
文章主题KVM 虚拟机热迁移的完整实验流程:共享存储搭建、迁移命令、验收与回退
所属类别云计算 → 虚拟化 → KVM 运维
知识关键字virsh migrate·--live·virt-clone·nfs-server·showmount -e·exports·_netdev·nofail·virt-install·pool-define-as

主线导读:这篇分两条线走。第一条是步骤线(第四到八章),照着敲就能把虚拟机从 KVM1 搬到 KVM2;第二条是原理线(第一到三章),讲清「为什么磁盘不用搬」「什么条件下才迁得动」。命令的参数解释集中在各命令小节,步骤线里只给要敲的命令本身。

一、热迁移在搬什么:磁盘不动,只搬内存与 CPU 状态

热迁移(live migration)指虚拟机保持开机运行的前提下,从一台宿主机转移到另一台。整个过程业务侧只感知到一次极短的卡顿,通常是几十毫秒到几秒。

1.1 搬过去的是三样东西

搬运对象说明
内存虚拟机当前的全部内存页,分多轮迭代搬完
CPU 设备状态vCPU 寄存器、中断控制器状态、时钟偏移
虚拟机定义XML 配置在目标端重建,保证迁移后配置一致

磁盘不在搬运清单里。源与目标宿主机必须同时能访问同一份虚拟磁盘,磁盘留在原处,两边只是切换「谁在读谁在写」。这就是共享存储成为核心前提的原因。

1.2 迭代迁移:为什么要搬好几轮

内存不是一块静止的快照。迁移期间虚拟机还在跑,内存页持续被改写,第一轮搬过去的页面到第二轮可能又脏了。解决办法是多轮迭代:

  1. 第一轮把全量内存页搬到目标端;
  2. 期间被改写的页标记为「脏页」,下一轮只搬脏页;
  3. 每轮搬运的增量越来越小,小到一定程度时暂停源虚拟机(通常几十毫秒),把最后剩余部分一次性搬完;
  4. 目标端恢复运行,源端清理。

这也是热迁移有「可容忍短时间中断」说法的由来——中断只发生在最后暂停的那一瞬间。

1.4 四种可用的共享存储

课件列了 NFS / Ceph / RBD / iSCSI 四种,实际选型看规模:

方案形态适合场景注意事项
NFS文件级共享实验环境、中小规模依赖网络,延迟敏感型业务要评估
iSCSI块级共享已有 SAN 的环境需要多路径配置防单点
Ceph RBD分布式块存储中大型云平台三副本起步,成本高
Ceph FS分布式文件存储与 KVM 深度整合调优项多,运维门槛高

本实验用 NFS,是因为它配置最简、三台机器就能验证完整链路。生产上 Ceph 与 iSCSI 更常见,但迁移命令与前置条件完全一样——换掉的只是「磁盘放在哪」。

1.3 与另外两种迁移的对照

迁移类型虚拟机状态中断时长适用场景
冷迁移(静态迁移)关机分钟级停机窗口充足的维护
热迁移(动态迁移)保持运行毫秒到秒级不能停的业务

课件里「用于可容忍短时间中断,但必须要快速恢复业务。比如轻量级数据库业务,桌面云业务」说的就是热迁移的适用边界:高并发写密集的业务要谨慎,内存脏页产生速度超过搬运速度时,迁移可能迟迟无法收敛。

二、什么时候用:三个真实场景

场景动因迁移方向
服务器维护前要重启 / 换硬件,先把虚拟机挪走迁出 → 维护完迁回
服务器升级前升级过程有中断风险迁出 → 升级完迁回
整合闲置资源把空闲机上的虚拟机集中,关掉空机器迁往集中节点

第三类是数据中心最常用的:一台物理机上跑着几十台虚拟机,运维可以把它们均匀分布到少数几台,然后关掉完全空载的机器省电。

三、前置条件四项

迁移开始前逐项自查,任何一项不满足都会在中途失败:

  1. 磁盘在共享存储上,且源与目标宿主机都能访问。可用 NFS / Ceph / RBD / iSCSI。
  2. 目标端有一台规格相同的空虚拟机(CPU 核数、内存大小一致)。名字可以与源相同,也可以不同。
  3. 两台宿主机之间网络可达,且建议关闭防火墙(本实验systemctl stop firewalld.service)。生产环境应改为放行迁移所需端口。
  4. 能接受一次短时间中断。业务层要有重连机制,数据库类业务要确认连接池会重试。

⚠️注意:共享存储上的磁盘文件不能被任何一方以独占方式打开。如果源虚拟机磁盘还在 KVM1 的本地目录,即使手工把文件复制到 NFS 上再改 XML 指向它,也会因为缓存不一致导致数据损坏——必须在共享存储上重新创建虚拟机,或先把磁盘转成共享存储上的 raw/qcow2 文件。

四、搭环境:从一台 KVM 克隆出三节点

实验拓扑:KVM1 是已经做完单机实验的宿主机,从它完整克隆出 KVM2 和 NFS,三台机器通过192.168.108.0/24网段互通。

4.1 完整克隆 KVM1 → KVM2 / NFS

克隆前先还原 KVM1 的快照,保证源状态干净。virt-manager 里右键虚拟机 → 克隆 →选择完整克隆(不要链接克隆,完整克隆才是一份独立磁盘)。

# KVM1 上操作,命令行等价写法virt-clone--originalkvm-node--nameKVM2--auto# --auto:自动生成磁盘与 MACvirt-clone--originalkvm-node--nameNFS--auto

virt-clone用法速查表:

参数含义英文原意
--original源虚拟机名original
--name新虚拟机名name
--auto自动生成磁盘文件名与 MAC 地址auto
--replace目标已存在时直接覆盖,不再询问replace
--file指定新磁盘路径,默认与源同目录file

完整克隆与链接克隆的区别:完整克隆把磁盘完整复制一份,新机器与原机器互不影响;链接克隆只建一个差异盘,原机器的磁盘文件被删,链接克隆立刻失效。要做迁移实验,必须用完整克隆。

4.2 改主机名与 IP

三台机器开机顺序:先 KVM1,再依次开 KVM2、NFS。逐台改主机名和 IP。

# KVM1 上把克隆出来的机器改成 KVM2[root@KVM1 ~]# hostnamectl set-hostname KVM2[root@KVM1 ~]# bash # 换 shell 让新主机名生效[root@KVM2 ~]#
[root@KVM2 ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens160TYPE=EthernetBOOTPROTO=noneONBOOT=yesIPADDR=192.168.108.102# 改成本机 IPPREFIX=24GATEWAY=192.168.108.2#UUID=3b58adc4-7bfb-4ce7-bdc5-7893a708ebb3 ← 这一行必须删掉[root@KVM2 ~]# nmcli connection reload ens160 # 让配置生效[root@KVM2 ~]# ip addr show ens160 # 验证地址已变
机器IP角色
KVM1192.168.108.101源宿主机
KVM2192.168.108.102目标宿主机
NFS192.168.108.100共享存储

⚠️注意:克隆出来的机器带着和源机器相同的 UUID,网卡配置文件里那行#UUID=不删,两台机器会有相同的网卡标识,nmcli会拒绝加载并报「连接已存在」。NFS 那台同样照此办理,IP 改成192.168.108.100。

4.3 三节点 hosts 同步

迁移命令要用主机名互访,先把 hosts 配好,再复制到另外两台:

# KVM1 上操作[root@KVM1 ~]# cat >> /etc/hosts << EOF192.168.108.100 NFS192.168.108.101 KVM1192.168.108.102 KVM2 EOF[root@KVM1 ~]# scp /etc/hosts root@KVM2:/etc/hosts # 复制到 KVM2[root@KVM1 ~]# scp /etc/hosts root@NFS:/etc/hosts # 复制到 NFS

五、NFS 共享存储:让两台 KVM 看到同一份磁盘

5.1 /etc/exports 五个参数逐个讲

[root@NFS ~]# mkdir /nfs # 用于共享的目录[root@NFS ~]# vim /etc/exports/nfs *(rw,no_root_squash,no_subtree_check)
参数含义英文原意
/nfs共享出去的目录,第一列固定是路径导出路径
*允许所有网段访问通配所有客户端
rw客户端对该目录有读写权限read-write
no_root_squash客户端用 root 访问时不映射 root不压缩 root
no_subtree_check不检查父目录权限不检查子树

root_squash(默认行为)会把客户端的 root 映射成匿名用户,虚拟机的磁盘文件以 root 身份写入时就会权限不足,所以这里必须写no_root_squash。

5.2 服务端验证:本地先通

[root@NFS ~]# systemctl restart nfs-server.service # 重启 NFS 服务[root@NFS ~]# showmount -e localhost # 本地测试共享成功没Export listforlocalhost: /nfs *[root@NFS ~]# systemctl stop firewalld.service # 停止防火墙服务

5.3 客户端验证:跨机能看见

# 在 KVM1、KVM2 上分别执行[root@KVM1 ~]# showmount -e 192.168.108.100Export listfor192.168.108.100: /nfs *[root@KVM1 ~]# mkdir /NFS[root@KVM2 ~]# mkdir /NFS

两级验证都要过:本地showmount -e localhost能列出来,说明服务端导出正常;跨机showmount -e <NFS IP>能列出来,说明网络与防火墙没挡。只过第一级就往下走,是新手最常卡住的地方。

5.4 挂载与持久化

临时挂载用于立即验证,写进 fstab 才能重启后还在:

mount-tnfs192.168.108.100:/nfs /NFS# 临时挂载df-h/NFS# 验证:应看到 192.168.108.100:/nfs
# /etc/fstab 追加一行192.168.108.100:/nfs /NFS nfs defaults,_netdev,nofail00
选项作用英文原意
_netdev声明这是网络挂载,等网络就绪后再挂network device
nofail挂不上也不阻塞启动no fail

_netdev不加,开机时网卡还没起来就去挂 NFS,必然失败;nofail不加,NFS 那台没开会让本机卡在启动阶段。两个都写,是网络存储 fstab 的固定写法。

六、KVM 挂载 NFS 存储池并在共享存储上建虚拟机

6.1 图形化添加存储池

virt-manager 里选中 KVM1 → 左下角+添加新存储:

字段填法
Typenetfs
Target Path/NFS(本机挂载目录)
Host NameNFS的地址
Source Path/nfs(NFS 共享目录)

KVM2 做同样的操作。

6.2 命令行等价写法

图形化点选背后是这几条命令,脚本化部署时直接抄:

[root@KVM1 ~]# virsh pool-define-as nfs-pool netfs \--source-host192.168.108.100 --source-path /nfs--target/NFS[root@KVM1 ~]# virsh pool-build nfs-pool # 建挂载点目录[root@KVM1 ~]# virsh pool-start nfs-pool # 挂载[root@KVM1 ~]# virsh pool-autostart nfs-pool # 设开机自启[root@KVM1 ~]# virsh pool-list --details # 验证:state 应为 running

pool-define-as用法速查表:

参数含义英文原意
<名称>存储池名字位置参数
netfs池类型,网络文件系统network file system
--source-hostNFS 服务器地址source host
--source-pathNFS 上共享出来的目录source path
--target本机的挂载点目录target

pool-define-as只是把定义写进 libvirt 配置,并不会真的挂上。pool-build建目录、pool-start才执行挂载,三步缺一不可。

6.3 在共享存储上创建虚拟机

上传 CentOS 镜像到 KVM1,然后创建虚拟机,磁盘位置选共享存储:

# 命令行写法:磁盘放在 nfs-pool 里virt-install--namevm-web01--ram2048--vcpus2\--diskpool=nfs-pool,size=20,bus=virtio\--cdrom/var/lib/libvirt/images/CentOS-stream-9.iso\--networknetwork=default--graphicsvnc,listen=0.0.0.0\--os-variant centos-stream9

--disk pool=nfs-pool,size=20指定磁盘建在存储池里。正常装完系统,重启时会自动弹出光盘。

virt-install用法速查表(全文仅此一张,两处示例共用):

参数含义英文原意
--name虚拟机名称name
--ram内存大小,单位 MBrandom access memory
--vcpus虚拟 CPU 核数virtual CPUs
--disk磁盘,可写pool=<池名>,size=<GB>,bus=<总线>disk
--cdrom挂载安装镜像CD-ROM
--network网络,可写network=<网络名>network
--graphics图形方式,vnc,listen=0.0.0.0监听所有地址graphics
--os-variant操作系统类型,影响默认硬件配置OS variant
--noautoconsole不自动打开控制台窗口no auto console
--print-xml只打印 XML 不真正创建,常配管道给virsh defineprint XML
--location指定安装源(网络仓库或 ISO 路径)location

--print-xml | virsh define /dev/stdin这个组合很常用:先生成 XML 再定义,得到一台不装系统的空虚拟机,正是热迁移目标端需要的形态。

七、执行迁移:两条路

7.1 前置:目标端建好空虚拟机 + SSH 免密

迁移的目标端要先有一台规格相同的空虚拟机。用virt-clone带--replace不适用(源还在跑),正解是直接建一台不装系统的:

# KVM2 上建一台同规格空虚拟机(不装系统)virt-install--namevm-web01--ram2048--vcpus2\--diskpool=nfs-pool,size=20,bus=virtio\--networknetwork=default--graphicsvnc\--os-variant centos-stream9--noautoconsole--print-xml|virshdefine /dev/stdin

再配 SSH 免密,virsh migrate走的是 libvirt 远端协议:

# KVM1 上操作[root@KVM1 ~]# ssh-keygen -t ed25519 -N '' -f /root/.ssh/id_ed25519[root@KVM1 ~]# ssh-copy-id root@KVM2 # 输入 KVM2 的 root 密码一次[root@KVM1 ~]# ssh root@KVM2 'virsh --version' # 验证免密可用

7.2 virsh migrate:参数逐个表

virshmigrate--live--persistent--undefinesource\vm-web01 qemu+ssh://KVM2/system
参数含义英文原意
--live热迁移,虚拟机不停机在线
--persistent目标端配置持久化,重启后仍在持久
--undefinesource迁移成功后删除源端虚拟机定义取消源定义
--copy-storage-all磁盘也一起复制(非共享存储场景)复制全部存储
--change-protection禁止迁移期间被意外中断保护模式
qemu+ssh://KVM2/system目标 libvirt 地址qemu 协议 + SSH 通道

--undefinesource对应课件里「将源虚拟机删除」那一步。如果不加,KVM1 上会留下一份已关机的同名定义,之后在 KVM1 上误启动会同时挂载同一份磁盘,造成数据损坏。

7.3 图形化迁移

virt-manager 里右键虚拟机 →Migrate(迁移),填目标主机名KVM2,勾选「迁移后删除源定义」,等待进度条走完。图形化本质就是调用同一条virsh migrate --live。

7.4 迁移前的最后一步:关防火墙

# KVM1、KVM2 都要执行[root@KVM1 ~]# systemctl stop firewalld.service[root@KVM2 ~]# systemctl stop firewalld.service

7.5 迁移过程的实时观测

迁移是异步进行的,命令返回后作业仍在后台跑。用domjobinfo看进度:

# 在 KVM1 上执行,另开一个终端[root@KVM1 ~]# virsh domjobinfo vm-web01Job type: Virtual machine migration Operation: Outgoing migration Time elapsed:8124ms Time remaining:43876ms Data processed:1.125GiB Data remaining:2.875GiB Memory processed:1.125GiB Memory remaining:2.875GiB Expected downtime:12ms Compression cache:256.5MiB
字段含义怎么用
Data processed/Data remaining已搬 / 待搬的内存总量估算还要多久
Expected downtime预计的最后一次暂停时长判断业务能否接受
Memory bandwidth当前搬运速率过低说明网络或磁盘是瓶颈

⚠️ 关注Expected downtime:它随迭代轮次逐步收敛。若长时间停留在几百毫秒以上,说明脏页产生速度接近搬运速度,迁移可能迟迟无法完成——写密集型业务要警惕这一点。

7.6 限速与大规模迁移

一次迁走十几台虚拟机会把网络占满,影响同网段的其他业务。virsh migrate-setmaxdowntime控制暂停时长上限,带宽则靠存储与网络侧控制:

# 在 KVM1 上执行[root@KVM1 ~]# virsh migrate-setmaxdowntime vm-web01 500 # 暂停上限 500 毫秒[root@KVM1 ~]# virsh migrate-setmaxdowntime vm-web01 0 # 0 = 取消上限,尽快完成

暂停上限越大,总迁移时间越短(省去反复迭代),但业务中断感越明显;上限越小中断越短,总时间越长。生产上按业务的敏感程度折中取 100~500 毫秒。

八、验收与回退

8.1 四项验收

迁移命令返回即算成功,但要确认真的落在 KVM2 上:

# 在 KVM2 上执行[root@KVM2 ~]# virsh list --all # 状态应为 running[root@KVM2 ~]# virsh domblklist vm-web01 # 磁盘应指向 /NFS 下的共享文件[root@KVM2 ~]# virsh domjobinfo vm-web01 # 无进行中的作业# 在虚拟机内部执行ipaddr show ens160# 业务连通性仍在,IP 未变

domblklist是最关键的一条:如果磁盘还指向 KVM1 的本地路径,说明这台虚拟机根本没建在共享存储上,之前几步有遗漏。

8.2 中途失败的回退

迁移过程中中断,源虚拟机通常仍在运行,业务不受影响。若源端状态异常:

# KVM1 上执行[root@KVM1 ~]# virsh list --all # 确认源还在[root@KVM1 ~]# virsh domjobabort vm-web01 # 放弃未完成的迁移作业[root@KVM1 ~]# virsh snapshot-revert vm-web01 clean # 必要时还原到迁移前的快照

8.3 迁回 KVM1

维护 / 升级完成后原路迁回,方向反过来即可:

# 在 KVM2 上操作[root@KVM2 ~]# virsh migrate --live --persistent --undefinesource \vm-web01 qemu+ssh://KVM1/system

九、踩坑记录

现象根因处置
nmcli connection reload后 IP 没变配置文件里 UUID 行没删,加载的是旧连接删#UUID=行后重新 reload
showmount -e <IP>超时防火墙没关,或 NFS 服务没起systemctl stop firewalld+systemctl restart nfs-server
客户端 root 写不进共享目录exports 用了默认的root_squash改成no_root_squash并exportfs -r
迁移报磁盘路径不可访问磁盘不在共享存储,或在 KVM1 本地在共享存储池上重建虚拟机
迁移后 KVM1 仍留同名定义漏加--undefinesource手工virsh undefine vm-web01

十、补遗:libvirt 工具族与虚拟化产品清单

10.1 virt-viewer:只做一件事的图形控制台

项说明
作用连接虚拟机的 VNC / SPICE 画面,单独弹出窗口
不管什么不创建、不修改、不删除虚拟机
典型用法virt-viewer --connect qemu:///system vm-web01

virt-manager 内置的虚拟机控制台就是调用它。只想看一台机器屏幕时,单独开一个 viewer 比打开整个管理界面轻。

10.2 virt-sysprep:镜像交付前的清理

把虚拟机转成模板前,用它清掉机器相关的身份信息,避免克隆出来的机器主机名、SSH 主机密钥、MAC 缓存全一样:

virt-sysprep-dvm-web01# 直接作用于一台已关机的虚拟机
清理项说明
主机名与 /etc/hosts还原成默认值
SSH 主机密钥删除,下次开机重新生成
网卡 MAC 与 udev 持久化规则清除
日志与历史记录清空

⚠️ 操作前必须关机,且不可逆,建议先做一份快照。

10.3 常见虚拟化产品对照

产品定位
KVMLinux 内核虚拟化模块,开源,云厂商主流
QEMU硬件模拟器,常与 KVM 配合做 I/O 虚拟化
XenHypervisor 在操作系统之下,Dom0 管理域
VMware ESX / ESXi商业 Hypervisor,vSphere 体系核心
Microsoft Hyper-VWindows Server 内置虚拟化
Virtuozzo容器级虚拟化,共享内核
LXCLinux 容器,操作系统级隔离
FusionCompute华为服务器虚拟化产品

📚 参考资料(官方文档 · 中英双语)

英文原版

  • virsh 命令行工具手册
  • libvirt 迁移官方文档
  • exports 文件格式手册(man7)

中文版

  • 在 Linux ECS 上挂载 NFS 协议文件系统(阿里云)

其余手册在服务器上直接查(showmount、exportfs、mount.nfs等,无需联网):

man1virsh# 虚拟机管理命令man1virt-install# 创建虚拟机man1virt-clone# 克隆虚拟机man1virt-sysprep# 镜像清理man5exports# NFS 导出配置man8exportfs# 导出表维护man8showmount# 查看 NFS 导出表man8nfsd# NFS 服务端守护进程

附:命令英文全称速查表

命令 / 缩写英文全称 / 原意作用
virshvirtual shelllibvirt 命令行管理工具
virt-installvirtual install命令行创建虚拟机
virt-clonevirtual clone克隆虚拟机
virt-viewervirtual viewer虚拟机图形控制台
virt-sysprepvirtual system preparation虚拟机镜像清理
migratemigrate虚拟机迁移
NFSNetwork File System网络文件系统
nfs-serverNFS serverNFS 服务端
showmountshow mount查看 NFS 导出表
exportsexportsNFS 导出配置文件
exportfsexport file system维护导出表
TCOTotal Cost of Ownership总体拥有成本

总结:热迁移的关键不在那条virsh migrate命令,而在它前面的准备——磁盘必须落在 NFS / Ceph 这类共享存储上,目标端要有同规格空虚拟机,两台宿主机之间 SSH 免密与防火墙都要提前打通。这篇的三节点实验把这四件事按顺序做完了,命令可以直接照着敲。


📚同系列 · KVM 虚拟化实战

  • 上一篇:《KVM 虚拟机管理:virt-manager 与 virsh 命令速查手册》
  • 相关篇:《KVM 装完连不上:VNC、光驱、快照三类坑的排错实录》
  • 相关篇:《虚拟化到底虚拟了什么:CPU、内存、IO 三层原理拆解》

⬅️ 上一篇:KVM 虚拟机管理与命令速查 ➡️ 下一篇:ESXi 嵌套部署与磁盘置备

💬 你迁移虚拟机时踩过什么坑?Permission denied还是磁盘路径不可访问?评论区贴出报错,一起看。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询