ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

KVM虚拟机直挂物理硬盘分区:从virtio-blk配置到权限与迁移实战

KVM虚拟机直挂物理硬盘分区:从virtio-blk配置到权限与迁移实战 KVM虚拟化环境里最常见的存储接入方式是把磁盘做成qcow2镜像文件丢给虚拟机用这种玩法简单、支持快照磁盘管理也灵活。但总有那么一些场景绕不开直接挂载物理硬盘分区宿主机上有一块现成的数据盘里面是ext4或XFS文件系统已经堆了好几T数据你不想再复制一份或者你要做数据恢复、灾难应急需要让虚拟机直接读写物理磁盘上的原始区块。这时候如果还用镜像文件去搞先要创建等大的qcow2再全量拷贝数据时间成本高得吓人而KVM本身就支持把宿主机上的真实块设备、物理分区直接“塞”给虚拟机让虚拟机像使用自己的虚拟磁盘一样去操作这块物理分区。这篇文章就把KVM虚拟机直接挂载物理硬盘分区这件事讲透从最基础的XML配置、virsh命令到权限、SELinux、设备标识这些容易翻车的点再到LVM、RAID、VFIO等进阶形态一次性梳理清楚。1. 先搞清楚一件事直挂分区到底解决了什么问题1.1 和qcow2镜像的本质差异先说个最容易被忽略的底层逻辑。qcow2镜像文件存放在宿主机某个文件系统里QEMU进程要读写这个文件走的是“文件系统层”也就是说虚拟机的IO请求会被翻译成对文件的read/write操作再由宿主机内核完成真正的磁盘IO。qcow2在这个翻译层之上还加了写时复制、快照、压缩、加密这些能力功能强但每一层都会带来开销。直挂物理硬盘分区就不一样了。XML里typeblock的设备QEMU直接把分区当作一个原始块设备来打开io请求通过io’native‘走Linux AIO绕过页面缓存直达硬件中间少了一层文件系统翻译也少了一层qcow2的格式处理。用大白话说镜像文件是“虚拟机把宿主机的文件当成硬盘”直挂分区是“虚拟机把宿主机的一块真实硬盘区域直接占用了”。所以直挂分区的IO路径短、延迟低、吞吐高而且不产生额外空间占用宿主机看到多大分区虚拟机就用多大分区。但代价也很明显qcow2提供的快照、优雅迁移这些“花活”在直挂裸设备上基本都玩不了后续章节我会展开讲。1.2 哪种业务场景必须走直挂从我实际运维经验来看以下四类场景基本绕不开直挂分区已有物理数据盘直接交给VM使用。宿主机上有磁盘阵列或旧数据盘里面是已经写满数据的文件系统直接挂给某台VM省去拷贝。尤其当数据量以TB计的时候走镜像拷贝的时间成本不是半小时一小时可能是整整一个晚上。数据恢复与应急取证。物理机故障后把系统盘或数据盘接到一台Linux宿主机上直接挂给一个应急VM在里面挂载原文件系统、读取日志、导数据。这种场景要求VM能访问原始块设备走镜像文件反而会因空间不足或格式兼容性出问题。特定硬件场景。比如审计设备、存储控制器测试、NAS系统迁移宿主机的RAID卡或SAS控制器识别出来的逻辑卷需要原封不动给虚拟化平台里的某台客户机用。高性能IO业务。数据库、大文件顺序读写服务性能压测时能明显感觉到直挂裸盘比qcow2稳延迟和抖动都会小一截。一句话直挂分区是给“已经存在的物理数据”和“性能敏感业务”准备的不是给常规新建VM用的。2. virtio-blk直挂分区的完整实操XML和virsh两种写法2.1 准备阶段看清磁盘分区、设备号与文件系统动手之前一定要先在宿主机上把目标设备看清楚这一步不能省。我用的三条命令lsblk -f blkid fdisk -l /dev/sdb1lsblk -f可以看到设备树和文件系统类型blkid能输出分区的UUID和文件系统UUIDfdisk -l则会显示分区表详细信息。确认三件事分区没有被宿主机挂载mount | grep sdb1没有输出才安全设备对应的路径、大小、文件系统类型是否符合预期宿主机内核里没有被LVM或MD阵列占用的痕迹避免把被阵列控制的成员盘裸挂给VM导致数据损坏。还有一个最容易踩的坑如果分区在宿主机上已经挂载了再直挂给VM等于两个系统同时去写同一个文件系统轻则文件系统损坏重则整盘数据全没。操作前必须umount干净。2.2 XML配置直接指定块设备路径最常用的方式通过virsh edit修改虚拟机配置。假设虚拟机叫win10要把/dev/sdb1挂给它作为第二个磁盘目标设备是vdb虚拟总线用virtio。disk typeblock devicedisk driver nameqemu typeraw cachenone ionative/ source dev/dev/sdb1/ target devvdb busvirtio/ /disk这段XML里有几个参数不是随便写的逐一说明typeblock是核心它告诉libvirt这是一个块设备不是文件。如果这里写fileQEMU会把/dev/sdb1当成普通文件打开那样直挂就失去了意义。driver typeraw表示不经过任何格式转换直接把块设备当成raw格式透传。这一点非常关键如果写typeqcow2QEMU会尝试按qcow2格式解析一个raw分区大概率直接报错。cachenone屏蔽宿主机的页缓存。虚拟化场景最忌讳双缓存宿主机缓存一份、客户机再缓存一份数据一致性很容易出问题性能也受影响。ionative让QEMU直接用Linux原生AIO不走缓冲IO配合cachenone是直挂方案的推荐组合。修改完XML后执行virsh define /etc/libvirt/qemu/win10.xml让配置重新生效然后启动或重启虚拟机。如果VM正在运行可以先virsh destroy再virsh start未保存的数据注意提前处理。2.3 virsh命令行热插拔不想停VM可以用virsh attach-disk热插拔这个操作在工作中很常用virsh attach-disk win10 /dev/sdb1 vdb --driver qemu --subdriver raw --cache none --persistent --live参数含义--live表示立即生效--persistent表示写入持久化配置VM重启后依然存在--config表示只写入配置下次启动生效--subdriver raw等价于XML里的driver typeraw。这里要特别注意很多教程只写了--live结果VM一重启分区就没了。因为热插拔默认只在运行期生效不写--persistent或者--config不代表这件事被“记住”了。我见过不止一次同事在测试环境热插了一块盘跑了几个星期某天VM因重启弄丢了磁盘数据盘没自动挂载业务直接中断。所以在生产环境要么用--live --persistent双参数要么干脆先热插测试再写进XML正式落地。移除分区对应的命令virsh detach-disk win10 vdb --persistent2.4 虚拟机内的验证与使用进入虚拟机系统后先确认设备是否识别fdisk -l lsblk如果设备已经出现比如为/dev/vdb就可以正常使用了。假如这个分区原本就是有数据的直接挂载文件系统mount /dev/vdb1 /mnt/data如果是给VM的全新裸分区先在VM里做文件系统mkfs.ext4 /dev/vdb完成之后写入/etc/fstab实现VM内的开机自动挂载。直挂模式下VM重启后设备路径通常是固定的virtio设备名跟总线顺序走所以fstab里建议用UUID而不是设备名避免路径漂移。3. 绕不开的权限和设备标识坑3.1 让QEMU进程有权限碰你的物理分区直挂裸设备最容易翻车的地方不在XML而在权限。默认情况下libvirt会以qemu:qemu用户运行QEMU进程而/dev/sdb1这样的块设备通常属于root:disk权限是brw-rw----qemu用户根本打不开这个设备节点。典型报错出现在/var/log/libvirt/qemu/win10.log里提示类似“Permission denied”或“Could not open /dev/sdb1”。解决方案有三种从推荐到不推荐排列方式一调整udev规则让系统自动授权。在/etc/udev/rules.d/下新建一个规则文件把分区的属主改成qemu用户KERNELsdb1, OWNERqemu, GROUPqemu, MODE0660改完后执行udevadm control --reload-rules和udevadm trigger生效。这样即使重启后设备节点重建也会自动带上正确权限属于一劳永逸的做法。方式二手动chown。临时应急可以chown qemu:qemu /dev/sdb1但设备节点一旦被系统重建重启、拔插盘属主会恢复原样只适合临时测试。方式三修改qemu.conf。把/etc/libvirt/qemu.conf里的user和group改成root因为权限问题直接让QEMU以root运行。这样确实省事但等于把整个虚拟化层的隔离性都放弃了虚拟机里的一个权限漏洞可能直接威胁宿主机生产环境我坚决不推荐。还有一种情况要注意如果sdb1是一个LVM逻辑卷或RAID设备它的属主和普通分区不同需要先ls -l /dev/mapper/xxx或ls -l /dev/md0确认。3.2 SELinux/AppArmor对块设备访问的干扰在RHEL/CentOS/Fedora这类启用SELinux的系统上即使权限对了QEMU也可能被SELinux策略拦下来。最典型的报错是这个internal error: process exited while connecting to monitor: qemu-system-x86_64: -drive file/dev/sdb1,formatraw,ifnone: Could not open /dev/sdb1: Permission denied这种时候用ausearch -m avc -ts recent看审计日志会发现AVC denial记录。临时解决办法是给设备节点打上适合QEMU访问的标签chcon -t virt_image_t /dev/sdb1不过/dev目录下的设备节点在重启后标签会被重置这种做法不可持续。从根本上解决可以写SELinux策略或使用semanage fcontext给设备路径预设上下文。但很多生产环境给KVM宿主机配直挂盘时干脆会将libvirt相关domain的SELinux宽松处理具体要看公司的安全规范。Ubuntu/Debian系的AppArmor也有类似问题。检查/etc/apparmor.d/下是否有影响libvirt的profile必要时在/etc/apparmor.d/local/usr.lib.libvirt.virt-aa-helper里添加对应设备路径的规则然后systemctl reload apparmor。3.3 设备路径漂移与重启失效问题/dev/sdb1这种命名方式是内核按设备发现顺序分配的重启、换插槽、换HBA卡之后sdb完全可能变成sdc或sde。配置文件里如果写死了source dev/dev/sdb1一旦路径变了VM启动时会直接找不到盘。解决思路有两个用by-id或by-uuid路径。查询方式ls -l /dev/disk/by-id/ ls -l /dev/disk/by-uuid/然后在XML里改写成source dev/dev/disk/by-uuid/xxxx-xxxx-xxxx/或者source dev/dev/disk/by-id/scsi-SATA_WDC_WD4000F9YZ-XXXX/这样只要设备本身还在路径怎么漂移都能找到。如果是LVM卷建议直接写/dev/mapper/xxx因为这个路径在LVM激活后是稳定的。做静态软链接。在宿主机上创建一个固定目录比如/dev/vmdisks/把目标分区链接过去mkdir /dev/vmdisks ln -s /dev/sdb1 /dev/vmdisks/win10-data1然后在XML里写source dev/dev/vmdisks/win10-data1/。配合udev规则可以保证链接稳定不过维护成本略高一般用by-id就够。说到“重启失效”很多用户搜索“mount挂载新硬盘重启没了”其实是同一个问题的两种表现。一种是上面说的VM配置没持久化另一种是VM内部的/etc/fstab设置不对。我的统一建议是宿主机侧确认XML配置持久化VM内部用UUID写fstab双保险缺一不可。4. 热插拔、快照与迁移边界行为4.1 attach-disk的live/config/persistent三种状态前面提到了--live和--persistent这里把libvirt对磁盘状态的完整语义说清楚。一个磁盘配置可能处在三种状态之一activeVM运行期间已经在使用的设备。--live操作会改变这个状态但不影响持久化配置。persistent写入VM的永久XML定义。--config或--persistent操作会改变它重启VM后保留。如果--live和--persistent都没有指定命令默认只对当前运行域生效重启即失。查看磁盘在两种状态下的差异可以用virsh dumpxml win10 --live virsh dumpxml win10 --inactive--live输出的是当前运行的配置--inactive输出的是磁盘的重启后配置。如果两者不一致说明存在“临时生效”的改动这个细节排查问题的时候非常有用。4.2 直挂分区能打快照吗直挂分区的VM能不能打快照答案是基本不能而且原因不在KVM配置而在块设备的格式限制。内部快照internal snapshot需要磁盘格式支持保存快照数据qcow2可以raw块设备本身没有快照功能所以不行。外部快照external snapshot虽然理论上可以给raw设备加一个qcow2 overlay但它要求原磁盘必须保持只读QEMU才能将新写入导到overlay中。对一个要持续读写的物理分区来说这个假设也不成立。如果你确认自己的业务需要快照建议不要用直挂裸分区方案改用LVM逻辑卷。因为LVM的lvcreate --snapshot是在宿主机层做块级快照不依赖QEMU能力lvcreate -L 20G -s -n>disk typeblock devicedisk driver nameqemu typeraw cachenone ionative/ source dev/dev/vg_data/lv_vmdata/ target devvdb busvirtio/ /disk需要提醒的是LVM逻辑卷扩容时宿主机和虚拟机都在访问这块设备扩容操作不会影响数据安全但同一个卷如果同时挂给两台VM共享读写模式就会造成严重的文件系统损坏风险这点必须牢记。5.2 MD RAID阵列设备直挂的注意事项宿主机上用mdadm做的软RAID形成的/dev/md0也可以直挂给VM。写法和普通分区没有区别source dev/dev/md0/但有两个特殊之处需要关注软RAID设备在系统启动时由mdadm组装如果RAID成员盘启动顺序变化或其中一块盘掉线/dev/md0可能无法在VM启动前出现。建议在/etc/mdadm/mdadm.conf里写死阵列的UUID并检查初始化脚本能正确组装所有阵列。不要轻易把MD设备同时给宿主机自己使用和虚拟机使用。比如宿主机已经挂载了这个RAID上的文件系统又直挂给VM就会出现上节说的双重写风险。5.3 直接挂载和VFIO直通的取舍比virtio-blk直挂分区更激进的方案是VFIO PCI直通。它是把宿主机的PCIe设备HBA卡、网卡、GPU、NVMe控制器直接分配给虚拟机虚拟机设备驱动直接操作硬件。和virtio-blk直挂分区相比维度virtio-blk 直挂物理分区VFIO PCI 直通性能靠近物理机仍有虚拟化层等同于物理机无虚拟化损耗配置复杂度简单改XML即可需要开启IOMMU、按PCI地址绑定vfio-pci灵活性分区/磁盘/卷都可挂整个PCI设备独占不能拆分隔离性QEMU通过块设备接口访问客户机直接操作物理硬件适用场景数据盘、文件系统、LVM卷NVMe盘、GPU、网卡、专用加速卡如果是NVMe固态硬盘追求极致性能又不怕分区粒度粗可以用VFIO直通整块NVMe控制器如果只是想给VM挂一块现成的数据分区virtio-blk直挂是最省事性价比最高的选择。5.4 四种存储接入方式的选型建议根据实际业务规模我给你一个可以直接照抄的选型思路日常VM、模板机、测试环境一律qcow2镜像优先考虑快照、克隆、后端存储迁移能力。性能敏感但数据可以重建raw格式镜像文件牺牲快照换取一点性能。已有数据盘、数据恢复、大容量存储virtio-blk直挂物理分区优先保证数据可直接访问和IO路径短。数据库等超高性能需求 独立物理磁盘VFIO整卡直通彻底不要虚拟化IO栈。命令行速查表建议收藏# 查看VM当前磁盘配置 virsh dumpxml vm | grep -A 5 disk # 热插拔挂载持久立即 virsh attach-disk vm /dev/disk/by-uuid/xxx vdb --driver qemu --subdriver raw --cache none --live --persistent # 热插拔卸载持久立即 virsh detach-disk vm vdb --live --persistent # 查看设备在VM内的IO统计 virsh domblkstat vm vdb # 查看VM实时磁盘信息 virsh domblkinfo vm vdb最后再分享一个小技巧。直挂分区前我习惯先在宿主机上对目标分区做一次只读测试用dd if/dev/sdb1 of/dev/null bs1M count1024检查设备能否被顺畅读取。如果这条命令都报IO错误那么直挂给VM后大概率也会出问题趁早排查硬件远比在虚拟化层面反复折腾来得实在。直挂物理分区这个功能KVM做了很多年技术上非常成熟真正出问题的地方往往都在权限、路径、持久化这些“应该已经搞定”的细节上操作前多花两分钟确认操作中能省出两小时。
返回列表