通过组合合适的VM文件系统功能(例如支持在线resize的XFS文件系统)和QEMU底层virsh qemu-monitor-command
指令可以实现在线动态调整虚拟机磁盘容量,无需停机,对维护在线应用非常方便。本文实践在线不停机情况下添加KVM虚拟机磁盘以及在线扩展Linux虚拟机磁盘及文件系统。(Windows扩容虚拟磁盘需要重启vm后识别)
本文虚拟机磁盘扩容(resize)部分步骤需要在VM内部使用操作系统命令,所以适合自建自用的测试环境。
生产环境reize虚拟机磁盘系统,可采用libguestfs 来修改虚拟机磁盘镜像。libguestfs
可以查看和编辑guest内部文件,脚本化修改VM,监控磁盘使用和空闲状态,以及创建虚拟机,P2V,V2V,以及备份,clone虚拟机,构建虚拟机,格式化磁盘,resize磁盘等等。
快速起步
案例使用的虚拟机名字是dev7
,增加和resize的磁盘文件是dev7-data.img
Copy cd /var/lib/libvirt/images
qemu-img create -f qcow2 dev7-data.img 20G
qemu
可以映射物理存储磁盘(/dev/sdb
)或虚拟磁盘文件到KVM虚拟机my_vm
的虚拟磁盘(vdb
),语法如下
Copy virsh attach-disk dev7 --source /var/lib/libvirt/images/dev7-data.img --target vdb --persistent --driver qemu --subdriver qcow2
注意:这里一定要指定--driver qemu --subdriver qcow2
,因为libvirtd
出于安全因素默认关闭了虚拟磁盘类型自动检测功能,并且默认使用的磁盘格式是raw
,如果不指定磁盘驱动类型会导致被识别成raw
格式,就会在虚拟机内部看到非常奇怪的极小的磁盘。
(演示动态扩容磁盘文件系统)在dev7虚拟机内部
格式化文件系统和挂载文件系统
Copy mkfs.xfs /dev/vdb
mkdir /data
echo "/dev/vdb /data xfs defaults 0 0" >> /etc/fstab
mount /data
此时在dev7
虚拟机内部df -h /data
可以看到输出信息显示磁盘20G
Copy Filesystem Size Used Avail Use% Mounted on
/dev/vdb 20G 33M 20G 1% /data
Copy virsh qemu-monitor-command dev7 --hmp "info block"
这里可以看到dev7-data.img
虚拟磁盘文件对应的块信息
Copy drive-virtio-disk1: removable=0 io-status=ok file=/var/lib/libvirt/images/dev7-data.img ro=0 drv=qcow2 encrypted=0 bps=0 bps_rd=0 bps_wr=0 iops=0 iops_rd=0 iops_wr=0
Copy virsh qemu-monitor-command dev7 --hmp "block_resize drive-virtio-disk1 30G"
注意:最近我在arch linux上执行上述 info block
命令并没有正确显示出磁盘镜像名称,显示的是类似:
Copy libvirt-3-format: /var/lib/libvirt/images/sles12_data.qcow2 (qcow2)
Attached to: /machine/peripheral/virtio-disk1/virtio-backend
Cache mode: writeback
这导致 block_resize
命令不能针对设备执行。所以我改为直接采用 qemu-img
命令进行resize,类似命令:
Copy sudo qemu-img resize /var/lib/libvirt/images/rhel8.qcow2 +10G
此时在dev7
虚拟机内部fdisk -l /dev/vbd
可以看到磁盘设备已经增长到30G
在虚拟机内部调整文件系统(XFS可以在线调整挂载磁盘的文件系统大小)
此时在dev7
虚拟机内部df -h /data
可以看到输出信息显示磁盘30G
Copy Filesystem Size Used Avail Use% Mounted on
/dev/vdb 30G 33M 30G 1% /data
Windows虚拟机磁盘添加和扩展方法类似,但需要注意处理virtio
驱动以及磁盘resize后需要重启VM操作系统才能识别。详细见下文。
以下是实践过程记录
Linux虚拟机
添加磁盘
以下操作针对dev7
虚拟机操作
Copy virsh qemu-monitor-command dev7 --hmp "info block"
--hmp
表示human monitor command
,可以直接传入monitor中操作的命令,不需要任何格式转换。如果缺少--hmp
,则monitor会认为接收json
格式命令,会出现错误,如internal error cannot parse json info kvm: lexical error: invalid char in json text
这里输出显示
Copy drive-virtio-disk0: removable=0 io-status=ok file=/var/lib/libvirt/images/dev7.img ro=0 drv=qcow2 encrypted=0 bps=0 bps_rd=0 bps_wr=0 iops=0 iops_rd=0 iops_wr=0
drive-ide0-0-0: removable=1 locked=0 tray-open=0 io-status=ok [not inserted]
Copy cd /var/lib/libvirt/images
qemu-img create -f qcow2 dev7-data.img 20G
显示输出(初始文件只有193K)
Copy Formatting 'dev7-data.img', fmt=qcow2 size=10737418240 encryption=off cluster_size=65536 lazy_refcounts=off
警告
不要在运行虚拟机所连接的磁盘镜像上使用qemu-img
命令修改镜像,有可能会导致镜像损坏。
检查新创建的磁盘信息
Copy qemu-img info /var/lib/libvirt/images/dev7-data.img
这里输出显示
Copy image: /var/lib/libvirt/images/dev7-data.img
file format: qcow2
virtual size: 10G (10737418240 bytes)
disk size: 196K
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
qemu-img
也支持磁盘格式转换
Copy qemu-img convert -O vmdk /images/sles11sp1.raw /images/sles11sp1.vmdk
Copy virsh attach-disk dev7 --source /var/lib/libvirt/images/dev7-data.img --target vdb --persistent
提示
Copy Disk attached successfully
Copy virsh domblklist dev7 --details
显示输出
Copy Type Device Target Source
------------------------------------------------
file disk vda /var/lib/libvirt/images/dev7.img
file disk vdb /var/lib/libvirt/images/dev7-data.img
block cdrom hda -
可以看到输出
Copy Disk /dev/vdb: 0 MB, 197120 bytes, 385 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
这里比较奇怪,在虚拟机内部看到的磁盘只有0 MB, 197120 bytes, 385 sectors
,并不是qemu-img create
命令创建的10G磁盘。(尝试重启了一次虚拟机也没有解决问题)
在虚拟机内部格式化磁盘文件系统会提示报错 - 因为对虚拟机内部来说这个虚拟磁盘没有可用空间
提示报错
Copy size 48 of data subvolume is too small, minimum 100 blocks
但是在物理服务器上可以看到设备文件是10G
显示输出
Copy dev7-data.img: QEMU QCOW Image (v3), 10737418240 bytes
这个问题困扰了我,直到我通过virsh edit dev7
查看这个虚拟机设备配置才发现,原来virsh attach-disk
添加磁盘设备时候没有指定磁盘设备类型,被默认添加成raw
类型,对比了原虚拟机系统vda
设备和vdb
设备:
Copy <disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/dev7.img'/>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</disk>
<disk type='file' device='disk'>
<driver name='qemu' type='raw'/>
<source file='/var/lib/libvirt/images/dev7-data.img'/>
<target dev='vdb' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</disk>
所以重新添加设备
Copy virsh detach-disk dev7 /var/lib/libvirt/images/dev7-data.img --persistent
virsh attach-disk dev7 --source /var/lib/libvirt/images/dev7-data.img --target vdb --persistent --type qcow2
但是提示error: unsupported configuration: unknown disk device 'qcow2'
,似乎不能正确传递--type
参数。
我搞错了,不是传递--type qcow2
,而是使用--driver qcow2
检查/etc/libvirt/qemu.conf
配置,原来为了安全原因,默认关闭了虚拟机镜像磁盘类型检测,即默认是注释掉 #allow_disk_format_probing = 1
,建议通过更新guest XML的<disk>
段落配置设置磁盘类型<driver type='XXXX'/>
。
这里测试环境适当放低安全限制,生产环境不建议使用,而是应该通过控制系统来修订磁盘类型
Copy # If allow_disk_format_probing is enabled, libvirt will probe disk
# images to attempt to identify their format, when not otherwise
# specified in the XML. This is disabled by default.
#
# WARNING: Enabling probing is a security hole in almost all
# deployments. It is strongly recommended that users update their
# guest XML <disk> elements to include <driver type='XXXX'/>
# elements instead of enabling this option.
#
allow_disk_format_probing = 1
然后再次使用
Copy virsh attach-disk dev7 --source /var/lib/libvirt/images/dev7-data.img --target vdb --persistent
但是还是出现报错error: unsupported configuration: unsupported driver name '(null)' for disk '/var/lib/libvirt/images/dev7-data.img'
,则参考sda
系统盘配置传递参数
Copy <disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/dev7.img'/>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</disk>
Copy virsh attach-disk dev7 --source /var/lib/libvirt/images/dev7-data.img --target vdb --persistent --driver qemu
此时确实在dev7
虚拟机内部看到了正确的磁盘大小,但是virsh edit dev7
显示的sdb
设备配置并没有自动加上类型type='qcow2'
Copy <disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/dev7.img'/>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</disk>
<disk type='file' device='disk'>
<driver name='qemu'/>
<source file='/var/lib/libvirt/images/dev7-data.img'/>
<target dev='vdb' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</disk>
所以,我觉得开启libvirtd
的allow_disk_format_probing = 1
并没有什么方便,还是手工传递参数比较准确。即再次编辑/etc/libvirt/qemu.conf
注释掉#allow_disk_format_probing = 1
,再重启systemctl restart libvirtd.service
。然后重新传递完整参数挂载磁盘
Copy virsh attach-disk dev7 --source /var/lib/libvirt/images/dev7-data.img --target vdb --persistent --driver qemu --type qcow2
依然失败unsupported configuration: unknown disk device 'qcow2'
!!! 仔细看了 virsh help attach-disk
帮助,发现传递参数实际上是和XML文件对应的。所以
Copy <driver name='qemu' type='qcow2'/>
对应的参数是
Copy --driver <string> driver of disk device
--subdriver <string> subdriver of disk device
即正确的命令是
Copy virsh attach-disk dev7 --source /var/lib/libvirt/images/dev7-data.img --target vdb --persistent --driver qemu --subdriver qcow2
终于成功
参考 Supported qemu-img Formats 说明,默认使用raw
格式,这个格式是最快的虚拟磁盘文件格式。如果文件系统支持空洞(例如ext2
或ext3
,则只有写过的扇区将使用空间)。使用qemu-img info
可以获得镜像的实际大小,或者使用ls -l
。不过,虽然raw
格式镜像有性能优势,但是只支持基本特性。例如,raw
格式不支持快照。
Copy mkfs.xfs /dev/vdb
mkdir /data
echo "/dev/vdb /data xfs defaults 0 0" >> /etc/fstab
mount /data
挂载之后查看/data
分区可以看到20G可用空间
Copy /dev/vdb 20G 33M 20G 1% /data
resize Linux磁盘
注意 :只有raw
格式支持双向resize(扩大或缩小),qcow2
版本2或qcow2
版本3的镜像只支持扩大(grown)不支持缩小(shrunk)
Copy qemu-img resize filename [+|-]size[K|M|G|T]
Copy qemu-img resize /var/lib/libvirt/images/dev7-data.img 30G
此时在虚拟机内部fdisk -l /dev/vbd
查看磁盘是看不到磁盘空间增长到30G,依然是原先的20G
Copy Disk /dev/vdb: 21.5 GB, 21474836480 bytes, 41943040 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
这说明qemu-img resize
只在hypervisor层调整了虚拟磁盘镜像,所以我们需要采用qemu-monitor
的底层命令
使用qemu-monitor
底层命令获取虚拟机内部磁盘信息
Copy virsh qemu-monitor-command dev7 --hmp "info block"
信息显示输出
则我们需要扩容的磁盘是drive-virtio-disk1
(对应dev7-data.img
)
Copy virsh qemu-monitor-command dev7 --hmp "block_resize drive-virtio-disk1 30G"
此时再在虚拟机内部fdisk -l
检查磁盘就可以看到vbd
磁盘已经扩容到30G
Copy Disk /dev/vdb: 32.2 GB, 32212254720 bytes, 62914560 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
不过此时XFS文件系统/data
还看不到增长的磁盘空间,我们还需要使用XFS支持的动态扩容
Copy # df -h /data
Filesystem Size Used Avail Use% Mounted on
/dev/vdb 20G 33M 20G 1% /data
# mount -v | grep /data
/dev/vdb on /data type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
显示输出
Copy meta-data=/dev/vdb isize=512 agcount=4, agsize=1310720 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=0 spinodes=0
data = bsize=4096 blocks=5242880, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
data blocks changed from 5242880 to 7864320
再次检查文件系统/data
可以看到已经30G空间
Copy # df -h /data
Filesystem Size Used Avail Use% Mounted on
/dev/vdb 30G 33M 30G 1% /data
Windows虚拟机
virtio
设备驱动
Windows虚拟机默认安装采用了IDE
磁盘类型设备,性能较差,需要转换成virtio
磁盘类型才能在KVM环境得到较好的性能。不过,Windows发行版并没有这个KVM Praavirtualized(virtio)驱动,需要独立安装以便识别出virtio
磁盘。
virtio
驱动盘安装方法参考 KVM Paravirtualized (virtio) Drivers
在HOST物理服务器上安装virtio
驱动盘(针对物理服务器RHEL 6.8操作系统)
Copy yum install virtio-win
安装后,在/usr/share/virtio-win/
有virtio-win.iso
驱动ISO镜像,在virtio
磁盘添加到Windows虚拟机之后,Windows操作系统会识别到新设备,就可以引导从该镜像安装驱动。
如果要在Windows安装时候就直接安装到virtio
半虚拟化磁盘(viostor/virtio-scsi
)上,则需要在Windows安装过程中选择virtio-win.iso
驱动或者虚拟软盘镜像virtio-win<version>.vfd
RHEL/CentOS 7没有找到virtio-win
软件包,参考 Windows Virtio Drivers 直接下载 Latest virtio-win iso 或 Stable virtio-win iso 存放到 /var/lib/libvirt/images
目录下,连接到虚拟机
Copy virsh attach-disk windev /var/lib/libvirt/images/virtio-win.iso hdb --type cdrom
这里hdb
设备是从virsh edit windev
查看的CDROM对应设备
如果原先在Windows虚拟机中已经添加了iso设备,则擦用virsh update-device
(从XML文件获取配置)命令来更换ISO镜像 - 先创建virtio-iso.xml
文件内容如下
Copy <disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='/var/lib/libvirt/images/virtio-win.iso'/>
<backingStore/>
<target dev='hdb' bus='ide'/>
<readonly/>
<alias name='ide0-0-1'/>
<address type='drive' controller='0' bus='0' target='0' unit='1'/>
</disk>
然后执行
Copy virsh update-device windev virtio-iso.xml
如果要持久替换,则使用virsh update-device windev virtio-iso.xml --persistent
增加磁盘设备
以下操作针对windev
虚拟机操作
Copy virsh qemu-monitor-command windev --hmp "info block"
这里输出显示
Copy drive-ide0-0-0: removable=0 io-status=ok file=/var/lib/libvirt/images/windev.img ro=0 drv=qcow2 encrypted=0 bps=0 bps_rd=0 bps_wr=0 iops=0 iops_rd=0 iops_wr=0
drive-ide0-0-1: removable=1 locked=0 tray-open=0 io-status=ok file=/var/lib/libvirt/images/win2012.iso ro=1 drv=raw encrypted=0 bps=0 bps_rd=0 bps_wr=0 iops=0 iops_rd=0 iops_wr=0
Copy cd /var/lib/libvirt/images
qemu-img create -f qcow2 windev-data.img 20G
Copy virsh attach-disk windev --source /var/lib/libvirt/images/windev-data.img --target vdb --persistent --driver qemu --subdriver qcow2
在Windows虚拟机中更新virtio
驱动识别新增磁盘设备
在Windows虚拟机添加了virtio
磁盘设备vdb
之后,使用Window设备管理器可以看到新增加了一个SCSI控制器
,此时还没有驱动安装,所以无法使用。在这个SCSI控制器
设备上右击鼠标,选择更新驱动程序软件...
,然后搜索D:\
驱动器更新驱动程序
virtio设备
可以同时更新另外一个没有识别的PCI设备
驱动,方法相同,这个原先未识别到PCI设备
实际上是VirtIO Balloon Driver
此时打开计算机管理(本地)
工具查看磁盘管理
(或者命令行调用diskmgmt.msc
)可以看到新增了一块未知且脱机
的20G磁盘,就是我们刚才动态添加的磁盘设备
virtio设备识别
按照Windows操作系统增加磁盘方法,先将新增磁盘联机
,然后再初始化
(创建MBR或GPT分区)
virtio设备联机
virtio设备初始化
然后再创建简单卷
(分配盘符格式化)
virtio设备格式化
完成后即可使用磁盘
resize Windows磁盘
Copy virsh qemu-monitor-command windev --hmp "info block"
这里可以看到windev-data.img
虚拟磁盘文件对应的块信息
Copy drive-virtio-disk1: removable=0 io-status=ok file=/var/lib/libvirt/images/windev-data.img ro=0 drv=qcow2 encrypted=0 bps=0 bps_rd=0 bps_wr=0 iops=0 iops_rd=0 iops_wr=0
Copy virsh qemu-monitor-command windev --hmp "block_resize drive-virtio-disk1 30G"
此时在物理服务器查看文件可以看到增长到30G
Copy qemu-img info windev-data.img
这里输出显示
Copy image: windev-data.img
file format: qcow2
virtual size: 30G (32212254720 bytes)
disk size: 87M
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
但是在Windows虚拟内部还看不到磁盘空间增加依然显示是20G
没有找到不停止Windows虚拟机动态扩展磁盘方法 ,通过关闭Windows操作系统然后再次启动操作系统,就可以看到磁盘从20G更改到了30G:
virtio设备resize
接下来只需要在Windows虚拟机中扩展磁盘分区就可以完整使用扩容后的30G磁盘空间。
参考