KVM虚拟机磁盘扩容实战:从qcow2镜像到LVM在线扩展全解析
2026/9/15 2:50:52 网站建设 项目流程

做运维和虚拟化这块的朋友,KVM虚拟机磁盘扩容迟早要碰上。不管你是给CentOS、Ubuntu还是Windows虚拟机加磁盘,核心思路其实是相通的,但细节里全是坑。这篇文章我把KVM磁盘扩容从原理到实操完整过一遍,包含原地扩容、LVM在线扩容、常见报错排查,都是我实际敲过的命令和踩过的坑。


1. 扩容前必须搞清楚的三件事

1.1 你的磁盘镜像到底是哪种格式

KVM虚拟机用的磁盘镜像常见有raw和qcow2两种。raw格式就是一块裸盘,数据直接写进去,性能好但不支持快照、压缩这些特性;qcow2是QEMU的写时复制格式,支持快照、稀疏文件、压缩,日常用得最多。

判断格式很简单:

qemu-img info /data/kvm/images/web01.qcow2

输出里会明确写image format是qcow2还是raw。这一步别跳过,因为后续所有扩容命令都依赖这个格式信息。我见过不少人直接用raw的方式去扩qcow2的盘,命令参数完全不对。

另外一个关键信息是virtual size和disk size的区别。virtual size是虚拟机看到的磁盘总大小,disk size是实际占用宿主机磁盘的空间。qcow2是稀疏的,虚拟大小10G的文件可能实际只占3G,扩容改的是virtual size,不要因为宿主机磁盘还够就以为不用看实际占用。

1.2 分区表类型决定你后面的操作难度

分区表分MBR和GPT两种。MBR最大只能认2TB的磁盘,单分区最大2TB;GPT理论支持到ZB级别,是现代Linux默认的分区方式。

查看分区表类型:

fdisk -l /dev/vda # 或者 parted /dev/vda print

如果是MBR,并且你想把磁盘扩到超过2TB,那是白折腾,只能重新分区或者改用GPT。如果只是扩到几百G,MBR完全够用。这块先确认清楚,免得后面执行到一半才发现路走死了。

1.3 数据备份永远排在第一位

扩容操作虽然有办法尽量做到不丢数据,但只要动了分区表和文件系统,就有出事的概率。我在生产环境扩容前,标准流程是至少做一次完整镜像备份:

# 先关机虚拟机 virsh shutdown web01 # 备份qcow2镜像(用cp --reflink在支持的文件系统上秒完成) cp --reflink=auto /data/kvm/images/web01.qcow2 /backup/web01.qcow2.bak # 或者用qemu-img转换为备份 qemu-img convert -O qcow2 /data/kvm/images/web01.qcow2 /backup/web01.qcow2.bak

qcow2格式支持快照的话,也可以直接做一个外部快照作为回滚点。但我的习惯是直接复制镜像文件,因为快照链一旦长了,后续的清理和合并反而容易出问题。


2. 原地扩容:直接放大qcow2镜像的两种方式

2.1 关机状态下用qemu-img resize

这是最稳妥、最常用的方式。虚拟机完全关机,宿主机上执行:

# 关机 virsh shutdown web01 # 确认已关 virsh list --all | grep web01 # 扩展镜像,比如加到100G qemu-img resize /data/kvm/images/web01.qcow2 100G # 确认结果 qemu-img info /data/kvm/images/web01.qcow2

这里有个细节值得说清楚:qemu-img resize后面的数值是目标大小而不是增加大小。写100G是最终100G,不是增加100G。如果原始是50G,想加到100G,命令还是写100G。

还有一个坑,如果虚拟机有快照,直接resize会报错:

qemu-img: Can't resize an image which has snapshots

遇到这个就得先把快照都清理掉再扩容。清理快照意味着丢失回滚点,所以扩容前务必确认业务状态正常再动这个。

2.2 不关机也能扩:块设备级别的在线扩容

热扩容只适用于资源池或LVM后端存储,直接对qcow2文件在线resize是不行的。如果你的KVM用的是LVM存储池,那可以在虚拟机运行状态下扩展逻辑卷:

# 在宿主机上查看虚拟机对应的LV lvdisplay | grep -A 5 web01 # 在线扩展LV,这一步不会影响虚拟机运行 lvextend -L +20G /dev/vg_kvm/lv_web01

虚拟机里面需要执行重新扫描设备:

# 虚拟机内,让系统重新读取磁盘大小 echo 1 > /sys/class/scsi_disk/0:0:0:0/device/rescan # 或者用partprobe重新读取分区表 partprobe /dev/vda

lvextend在线扩容本身对虚拟机是透明的,但注意控制 scsi 磁盘的可以被热插拔,virtio-blk 磁盘热插拔支持差一些。后面第4节会详细讲通过virsh attach-device热加磁盘的做法,那是另一种在线扩容思路。


3. 进入虚拟机内部调整分区和文件系统

3.1 让内核重新读取新磁盘大小

宿主机层面resize完镜像之后,只是把虚拟磁盘变大了,虚拟机里的操作系统还看不到。重启虚拟机是暴力的办法,但生产环境不想重启,可以这样让内核重新识别磁盘:

# 对virtio-blk磁盘,重扫SCSI设备 echo 1 > /sys/class/block/vda/device/rescan # 或者用partprobe让分区表重新加载 partprobe /dev/vda # 如果以上不行,只能重启虚拟机 reboot

这部分在测试环境多试几次就明白了。需要注意的是,vda是virtio接口的命名方式,sda是SCSI模拟的命名方式。devices里的target总线类型如果是virtio,设备名就是vd开头;如果是sata或者scsi,就是sd开头。

3.2 不同分区方案的调整方法,看完不走弯路

虚拟机内部的磁盘布局通常有两种情况:单分区直接挂载,或者用LVM。两种情况的操作完全不同。

单分区直接挂载的情况

比如根分区就是/dev/vda1,直接挂载在/上。这种情况下扩展分区和文件系统需要用到fdisk重新调整分区:

# 查看当前分区信息 fdisk -l /dev/vda # 进入fdisk交互模式 fdisk /dev/vda # p 查看分区 # d 删除分区(注意:数据还在,只是删除分区表记录) # n 新建分区(起始扇区要和原来一样!) # w 保存退出

删掉分区再重建听着吓人,但是只要你把起始扇区设成和原来一样,数据不会丢。关键是最后保存之前不要执行w以外的操作。我建议刚开始搞这个的时候,先在一台测试机上完整走一遍,真的熟练了再对生产环境操作。

建完分区后:

partprobe /dev/vda # ext4文件系统 resize2fs /dev/vda1 # xfs文件系统 xfs_growfs /
LVM的情况

LVM就优雅得多,因为逻辑卷可以动态扩展:

# 先扩展物理卷 pvresize /dev/vda2 # 查看卷组剩余空间 vgdisplay # 扩展逻辑卷 lvextend -L +20G /dev/centos/root # 或者扩展到占用全部剩余空间 lvextend -l +100%FREE /dev/centos/root # 扩展文件系统 resize2fs /dev/centos/root # ext4 xfs_growfs / # xfs

CentOS默认的安装方式基本都是LVM,所以如果你只是给CentOS虚拟机扩容,大概率走的就是pvresize、lvextend、xfs_growfs这条路线,不需要碰fdisk删分区重建那套危险操作。

为什么优先推荐LVM

到这里你能看出区别了:LVM方案全程不删分区,操作风险低;单分区方案要删掉分区重建,虽然有办法保证数据不丢,但手一抖就是事故现场。所以我一直建议,新装虚拟机的时候,不管磁盘多大,系统盘直接用LVM。扩容业务的数据库盘或者数据盘,能用LVM也是优先LVM,这份时间投资很划算。

3.3 分区表MBR的2TB限制要避开

这部分我要单独拎出来说,因为很多人在2TB边界上栽过跟头。MBR分区的单分区最大只能到2TB,如果你创建的虚拟机磁盘很大,比如6TB,MBR分区表根本认不了那么多。

遇到这种情况的解决方案是:

  • 新机器直接用GPT分区
  • 已经用MBR的小磁盘要扩大到超过2TB,最省事的办法是给虚拟机新增一块磁盘,而不是扩原来的盘

新增磁盘的方式下一节详细讲。


4. 更省事的方式:给虚拟机加一块新磁盘

4.1 在宿主机上创建并挂载新磁盘镜像

如果你不想折腾原来的磁盘,或者原磁盘MBR已经接近2TB上限,直接加新盘是更好的方案。创建新镜像:

# 创建10G新qcow2镜像 qemu-img create -f qcow2 /data/kvm/images/web01-data.qcow2 10G # 编辑虚拟机配置,添加磁盘 virsh edit web01

在配置文件里找到devices段,添加:

<disk type='file' device='disk'> <driver name='qemu' type='qcow2' cache='none'/> <source file='/data/kvm/images/web01-data.qcow2'/> <target dev='vdb' bus='virtio'/> </disk>

保存后重启虚拟机或者热插拔。

4.2 不重启虚拟机,用virsh attach-device热插拔

生产环境不方便重启的时候,热插拔是很好的方案。先把设备xml写好:

cat > /tmp/vdb.xml << 'EOF' <disk type='file' device='disk'> <driver name='qemu' type='qcow2' cache='none'/> <source file='/data/kvm/images/web01-data.qcow2'/> <target dev='vdb' bus='virtio'/> </disk> EOF virsh attach-device web01 /tmp/vdb.xml --live --config

--live表示立即生效但不写入配置文件,--config表示写入配置文件下次开机也有效。两个一起用就是既要现在生效,也要重启后保留。

虚拟机内部查看:

lsblk fdisk -l /dev/vdb

新盘没有分区,初始化之后挂载:

# 分区 fdisk /dev/vdb # n新建分区,w保存 # 格式化 mkfs.ext4 /dev/vdb1 # 挂载 mkdir /data mount /dev/vdb1 /data # 写入fstab确保重启后自动挂载 echo "/dev/vdb1 /data ext4 defaults 0 0" >> /etc/fstab

4.3 新增磁盘与扩容原磁盘怎么选,我的一点建议

新增磁盘适合这几种情况:原MBR分区接近2TB上限;原分区不是LVM,不想做删分区重建的操作;数据库或大数据应用希望独立磁盘做IO隔离,减少同一块盘上的争用。

扩容原磁盘适合只有一块系统盘、没有额外槽位、应用全在一个文件系统内的场景。两种方式没有绝对的对错,但运维角度上,数据盘独立出来会让后续备份、迁移、故障隔离都清晰得多。


5. 实操案例:CentOS 7虚拟机从50G扩到120G

5.1 案例环境与目标

这台虚拟机是标准CentOS 7系统,安装的时候用的LVM布局,根分区在centos_web-root这个逻辑卷上。原磁盘50G,业务增长快,需要扩到120G。

宿主机环境是KVM加Libvirt管理,镜像路径在/data/kvm/images/下面。

5.2 宿主机操作:关机、备份、扩容

# 第一步,关机 virsh shutdown web01 virsh list --all | grep web01 # 第二步,备份 cp --reflink=auto /data/kvm/images/web01.qcow2 /data/backup/web01.qcow2.bak_$(date +%F) # 第三步,查看当前大小 qemu-img info /data/kvm/images/web01.qcow2 # 输出为 virtual size: 50G # 第四步,扩容到120G qemu-img resize /data/kvm/images/web01.qcow2 120G # 第五步,确认 qemu-img info /data/kvm/images/web01.qcow2 # 输出为 virtual size: 120G # 第六步,启动虚拟机 virsh start web01

--reflink=auto这个参数只在文件系统支持reflink时才有效,比如XFS在4.9以上内核就支持。如果是不支持的文件系统,它会自动退化成普通复制,不用担心写错。

5.3 虚拟机内操作:识别新大小、扩展PV、扩展LV、扩展文件系统

# 第一步,确认系统看到的新磁盘大小 lsblk # 应该能看到vda变成120G # 如果lsblk还是旧的50G,重扫设备 echo 1 > /sys/class/block/vda/device/rescan lsblk # 第二步,查看当前PV和VG状态 pvs vgs # 正常情况下vda2是PV # 第三步,扩展物理卷到整个磁盘(如果有空闲分区) # 如果vda2之后没有空余分区,先parted或fdisk建分区再pvresize # 如果vda2是最后一个分区且分区还未占满磁盘,直接: pvresize /dev/vda2 # 确认VG可用空间 vgs # 会看到VFree不再是0 # 第四步,扩展LV到根 lvextend -l +100%FREE /dev/centos_web/root # 第五步,扩展文件系统 xfs_growfs / # 第六步,确认 df -h

看到df -h中根分区变成约118G左右,扩容就结束了。

5.4 案例复盘:为什么效果和预期有偏差

这个案例里有一个容易踩的坑,就是如果虚拟机里的分区表并不是把整个磁盘都分给一个分区,而是有/boot分区独立占用,那pvresize之前必须先确认空闲空间在哪。

我们这台只是/boot独立分区,/dev/vda2是LVM PV且位于磁盘末端,所以pvresize /dev/vda2就能把后面新加的空间吸收进来。如果你的虚拟机/boot是LVM的一部分(CentOS 7默认/boot独立,CentOS 8以后也有部分自定义安装是这样),那你可能要操作的LV不同,或者要先把/boot分区扩展到独立分区再处理LVM。

实际工作中最麻烦的判断是:磁盘末尾是否有可用空间?如果没有,就要在中间建分区再补进VG。这部分对不熟LVM的朋友还是有点绕,建议先在测试机模拟同样布局走一遍。


6. 常见问题与排查技巧实录

6.1 resize报错:Can't resize an image which has snapshots

之前提到过,镜像存在快照时不能resize。排查方式:

virsh snapshot-list web01

如果有输出,说明存在快照。处理方案是合并快照后再扩容,这里注意快照合并需要关机状态:

virsh shutdown web01 # 列出快照 virsh snapshot-list web01 # 合并快照(名字是快照名) virsh blockcommit web01 vda --active --pivot

合并完成后确认快照消失,再执行resize。

6.2 resize成功但虚拟机里还是旧容量

这个现象很常见,原因通常是宿主机resize和虚拟机内部识别之间缺少一步重扫操作。按下面的顺序排查:

# 虚拟机内 lsblk # 如果看不到新大小 echo 1 > /sys/class/block/vda/device/rescan lsblk # 还是不行就partprobe partprobe /dev/vda lsblk

生产环境如果还不行,就只能通过重启虚拟机解决。这也是为什么我更倾向于如果业务允许,直接维护窗口重启再扩,避免在线重扫的各种不确定。

6.3 resize2fs报错:Filesystem has unsupported feature(s)

这种情况一般是文件系统太老,扩容用的resize2fs版本不匹配。比如虚拟机里是RHEL 6时代的ext4特性,宿主机上或者救援环境里的resize2fs版本太新不兼容。

解决办法是不要跨版本搞,在虚拟机里安装对应版本的e2fsprogs再执行resize。做离线扩容的时候尤其注意这个问题,建议优先用虚拟机自带的工具。

6.4 扩容过程中宿主机磁盘满了怎么办

qcow2是稀疏的,resize后virtual size变大,但disk size不会立刻变大,只有虚拟机内部实际写入数据才会占用宿主机空间。但如果你虚拟机里执行了dd填0或者大量写入,宿主机磁盘就会涨得很快。

扩容前检查宿主机磁盘剩余空间:

df -h /data/kvm/images

一般建议剩余空间至少是被扩容虚拟机的当前实际使用量的两倍。备份文件也会占空间,备份完确认能正常启动虚拟机再决定是否删除备份,别图省事。

6.5 热插拔的SCSI盘识别不到

用controller类型是virtio-scsi的话,热插拔SCSI设备后系统不一定自动识别。解决办法是虚拟机内手动重扫SCSI总线:

# 查看SCSI host编号 ls /sys/class/scsi_host/ # 对每个host重扫 echo "- - -" > /sys/class/scsi_host/host0/scan echo "- - -" > /sys/class/scsi_host/host1/scan # 以此类推

这里补充一点:virtio-blk(dev为vda、vdb这种)热插拔的支持不如virtio-scsi好,但是日常使用场景下virtio-blk更多见。新架构环境我一般推荐virtio-scsi控制器,热插拔体验好很多,代价是虚拟机内要装对应驱动,性能几乎没有差别。Windows虚拟机尤其明显,virtio-scsi对热插拔的支持远好于virtio-blk。


7. 操作检查清单

最后给一份我平时每次扩容都对照执行的检查清单,贴在操作文档旁边,照着做能省掉大部分翻车风险:

  • 确认虚拟机磁盘格式(qcow2 / raw)
  • 确认分区表类型(MBR / GPT)
  • 确认文件系统类型(ext4 / xfs)
  • 确认虚拟机内是LVM还是单分区
  • 关机前备份镜像或确认有快照
  • 确认宿主机剩余磁盘空间充足
  • 执行qemu-img resize后用qemu-img info确认
  • 启动虚拟机后确认lsblk识别新容量
  • 调整分区、PV、LV时每一步都用vgs、lsblk检查结果
  • 扩展文件系统后用df -h确认生效
  • 扩容完成后主动重启一次虚拟机,确认fstab挂载无报错

我个人在实际操作中的体会是,KVM磁盘扩容本身不复杂,真正让人翻车的往往是对虚拟机内部磁盘布局不够清楚就急着动手。扩容前先把lsblk、pvs、df -h这几条命令的输出存下来,对照本文的流程走一遍,比任何优化技巧都管用。

最后再分享一个小技巧:如果你要给一批相同配置的虚拟机扩容,别一台台手动敲命令。先把模板机的磁盘扩好后,用virt-clone克隆新虚拟机,新机器直接就是扩容后的大小。或者写个脚本循环调用virsh和qemu-img,把机器列表放进数组里批量处理。批量操作之前先把单台跑通,这个顺序不能乱。

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

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

立即咨询