ARTICLE DETAIL

资讯详情

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

KVM虚拟机系统盘扩容实战:从宿主机到根目录完整指南

KVM虚拟机系统盘扩容实战:从宿主机到根目录完整指南 KVM 虚拟机跑着跑着根分区突然满了这是运维日常里最让人头疼的问题之一。尤其是系统盘当初建虚拟机时图省事给了 50G结果数据一涨根目录直接飙到 95% 以上服务告警不断。网上关于 KVM 扩容的教程散得不行有的只讲宿主机层面改磁盘大小有的只讲分区工具用法很难找到一条从宿主机到虚拟机内部完整的操作链路。这篇就基于我的实际经验把 KVM 虚拟机系统盘扩容、根目录空间调整这件事从头到尾捋一遍从原理到操作、从 LVM 到普通分区、从在线调整到离线扩容都覆盖到照着做基本能一次成功。先说清楚一个核心认知给 KVM 虚拟机扩容不是一个动作而是两个层面的操作。第一层是在宿主机上扩展虚拟磁盘镜像文件的大小第二层是进入虚拟机内部把新增加的容量分配给物理分区或者 LVM 逻辑卷最后再让文件系统真正识别并利用这些空间。很多人在第一步做完就停了结果进系统一看容量一点没变又跑回来问为什么。记住宿主机扩的是“瓶子”虚拟机内部扩的才是“水”两者缺一不可。1. 扩容前的准备盘点现状与风险评估1.1 确认虚拟磁盘的类型与格式动手之前先搞清楚虚拟机的磁盘是raw还是qcow2这决定了后续的操作思路。KVM 环境里两种格式都很常见它们的差异直接影响到能不能在线扩容。# 在宿主机上查看虚拟机的磁盘配置 virsh domblklist 虚拟机名称 # 查看镜像文件的详细信息 qemu-img info /data/kvm/images/你的虚拟机.qcow2qcow2格式支持qemu-img resize在线扩容这是它最大的优势之一。raw格式也支持扩容但如果当初是预分配方式创建的扩容后内部结构是连续的问题不大如果是稀疏文件扩容后文件仍然保持稀疏特性只要虚拟机内部逻辑分区对得上就行。我的建议是生产环境能转qcow2就转qcow2快照、压缩、在线扩容都方便得多。转换格式的命令如下按需执行注意转换过程需要足够的磁盘空间而且最好在虚拟机关机状态下操作qemu-img convert -f raw -O qcow2 原磁盘.img 新磁盘.qcow21.2 区分 LVM 分区与普通分区的扩容策略这是整个扩容操作里最关键的分岔路。进入虚拟机后根目录所在的分区有两种常见布局一种是直接挂在/的普通分区比如/dev/vda1另一种是先建一个物理卷PV再组成卷组VG最后从卷组里划分逻辑卷LV挂载到根目录这是很多企业装机脚本的标准做法。两种布局的扩容路径完全不同LVM 布局执行pvresize扩展物理卷再用lvextend扩展逻辑卷最后用xfs_growfs或resize2fs扩展文件系统。全程在线风险极低。普通分区布局需要先删除分区再重建分区来占用新空间期间分区表会发生变更虽然数据不会丢但操作不当会带来风险必须小心谨慎。提示判断方法很简单执行df -hT看根目录的文件系统类型再执行lsblk查看分区结构。如果看到vda1下面套着centos-root这种名字就是 LVM如果直接是vda1挂载到根目录就是普通分区。1.3 备份是扩容的地基扩容虽然是个常规操作但中间涉及的环节不少尤其是修改分区表和调整文件系统元数据都算是对磁盘结构动了手术。一旦断电、命令敲错或者文件系统出现异常数据受损的代价比扩容本身大得多。给虚拟机做备份我常用两种方式。第一种是用virsh snapshot做虚拟机层面的快照优点是可以回滚整个虚拟机状态缺点是快照文件会占据额外空间而且大磁盘快照的创建和删除都有性能开销。第二种是直接在宿主机上复制虚拟磁盘镜像文件这个方法简单粗暴但非常可靠缺点是复制的是完整镜像占空间。# 快照方式qcow2 格式专用 virsh snapshot-create-as 虚拟机名称 backup-before-resize --disk-only # 磁盘镜像复制方式适用于关机状态 cp /data/kvm/images/你的虚拟机.qcow2 /data/kvm/images/你的虚拟机.qcow2.bak我的习惯是数据量小、业务可停机的直接复制镜像文件数据量大或需要快速回滚的打快照。无论哪种方式备份完后都要确认备份文件大小和虚拟机磁盘大小对得上再开始动刀。1.4 清理系统盘空间让扩容收益最大化在真正扩容之前有个性价比极高的步骤经常被忽略——先清理系统盘里的垃圾文件。扩容是加资源但如果你先清理出 20% 的存量空间等于变相增加了可用余量而且能让扩容后的实际效果更好。常用清理手段包括用yum clean allCentOS或apt autoremoveUbuntu清理包管理器缓存清理 journald 日志journalctl --vacuum-size100M检查/var/log下的旧日志文件清理 Docker 镜像和容器日志如果虚拟机里跑容器的话。这一步做完你会发现根分区从 95% 降到 80%心里踏实很多。2. 宿主机层面彻底搞懂 qemu-img resize 的用法2.1 qcow2 在线扩容实战确认完虚拟机磁盘格式和内部结构就可以在宿主机上操作了。以给 50G 的 qcow2 磁盘扩展到 100G 为例# 假设虚拟机名称为 vm-web磁盘路径为 /data/kvm/images/vm-web.qcow2 qemu-img resize /data/kvm/images/vm-web.qcow2 100G这个命令执行速度非常快因为对于 qcow2 格式来说它只是在元数据层标记一个新的虚拟大小并不会立刻写满整个镜像文件。扩容后的镜像文件在宿主机上依然只占用原本的数据量大小这是 qcow2 的精妙之处。执行结束后用qemu-img info确认虚拟磁盘大小已经变成 100Gqemu-img info /data/kvm/images/vm-web.qcow2注意qemu-img resize 支持指定最终大小或者增加的大小比如qemu-img resize 磁盘 50G表示最终大小为 50Gqemu-img resize 磁盘 50G表示增加 50G。我给的建议是尽量用“最终大小”表达法语义清晰不容易出错。2.2 raw 磁盘扩容与格式转换如果你的虚拟机用的是 raw 格式磁盘在线扩容的命令其实一样qemu-img resize /data/kvm/images/vm-web.raw 100Graw 格式扩容同样只改元数据执行速度也快。但 raw 格式有它的局限不支持快照、不支持压缩所以如果你有这个虚拟机的后续管理需求我强烈建议趁这次扩容直接把 raw 转成 qcow2。转换命令在宿主机上执行注意目标文件不能和源文件同名qemu-img convert -f raw -O qcow2 /data/kvm/images/vm-web.raw /data/kvm/images/vm-web.qcow2转换完成后需要修改虚拟机的磁盘配置把原来指向.raw的路径替换成.qcow2# 编辑虚拟机配置 virsh edit vm-web在配置里找到source file/data/kvm/images/vm-web.raw/改成.qcow2的路径保存退出。如果虚拟机处于开机状态热修改配置可能不生效稳妥起见关机后再改。这里有个优先级问题先转换格式、修改配置还是先扩容答案是都可以但我的建议是先转换格式再在新格式上执行扩容这样一步到位少一次踩坑机会。2.3 宿主机层操作的系统校验扩容操作完成后重启虚拟机在 KVM 环境里并不总是必需的。对于 qcow2 格式虚拟机的 virtio-blk 驱动通常能感知到磁盘尺寸的变化但部分内核版本需要重启才能真正让系统识别到新的虚拟磁盘大小。如果你在虚拟机里执行lsblk发现 vda 的大小没变可以试着重启虚拟机这会触发 virtio-blk 重新读取磁盘几何信息。不过重启虚拟机是上层操作还有一个更轻量的校验方法进入虚拟机后执行echo 1 /sys/class/block/vda/device/rescan。这个文件存在与否取决于虚拟机内内核和 virtio 驱动版本有的系统里路径不完全一样可以先用ls /sys/class/block/vda/device/确认。如果 rescan 成功lsblk里 vda 的大小立刻就会刷新不需要重启。3. 虚拟机内部操作LVM 布局的扩容全流程3.1 物理卷扩展pvresize 的意义宿主机层面的磁盘已经扩大到 100G现在进入虚拟机内部操作。先用lsblk确认系统是否识别到了新大小lsblk正常情况下vda应该显示为 100G。如果还是 50G执行 2.3 节里的 rescan 或重启虚拟机。接下来执行物理卷扩展。对于 LVM 布局物理卷是 LVM 体系的地基地基不扩大后面的逻辑卷和文件系统都不可能扩大pvresize /dev/vda2执行后用pvdisplay或pvs确认物理卷大小已经从原来的 50G 变为 100Gpvs PV VG Fmt Attr PSize PFree /dev/vda2 centos lvm2 a-- 100.00G 50.00G看到 PFree 不再是 0说明物理卷扩展成功。这一步非常关键如果漏了它后面的lvextend会直接提示Insufficient free space。3.2 逻辑卷扩展lvextend 的两种方式物理卷扩展完成后接下来把新空间分配给根目录所在的逻辑卷。首先确认根目录对应的逻辑卷名称df -hT输出里/dev/mapper/centos-root或者/dev/centos/root都是常见的 LVM 逻辑卷路径。扩展逻辑卷有两种常用的方式方式一指定逻辑卷名扩展简单清晰lvextend -L 50G /dev/centos/root方式二直接使用-r选项在扩展逻辑卷的同时自动扩展文件系统lvextend -r -L 50G /dev/centos/root提示-r选项对应的是resize filesystem它会自动检测逻辑卷上的文件系统类型调用对应的扩展工具。这种方式最省事一步到位。不过对于生产环境我习惯分两步走先扩逻辑卷确认成功后再单独扩文件系统一旦操作出问题更容易定位是哪个环节出错。3.3 文件系统扩展xfs_growfs 与 resize2fs 的选择扩展逻辑卷后文件系统仍然保留原来的大小最后一步就是让文件系统吃到新空间。这一步要根据根目录的文件系统类型选择工具。如果文件系统是 XFS使用xfs_growfs /注意 XFS 的扩容工具是xfs_growfs要传入挂载点参数而且它只能扩大不能缩小这是文件系统本身的设计约束。如果文件系统是 ext4使用resize2fs /dev/centos/rootext4 支持离线和在线扩容在线扩容时需要文件系统已经挂载这个命令会扫描文件系统并扩展到逻辑卷的新大小。我见过有人在 ext4 上误用 xfs_growfs工具会直接报错说文件系统类型不匹配所以一定要先确认类型。执行完成后用df -hT /确认根目录容量已经是预期值。以我的经验XFS 在扩容后容量识别非常即时df输出立刻就会刷新到 100G。3.4 一个典型 LVM 扩容操作的完整串演把上面的步骤串起来一个完整的 LVM 布局扩容操作是这样的# 1. 宿主机执行扩容对应 2.1 节 qemu-img resize /data/kvm/images/vm-web.qcow2 100G # 2. 虚拟机内部确认新磁盘大小 lsblk # vda 显示 100G # 3. 扩展物理卷 pvresize /dev/vda2 # 4. 确认物理卷变化 pvs # 5. 扩展逻辑卷 lvextend -L 50G /dev/centos/root # 6. 扩展文件系统XFS 示例 xfs_growfs / # 7. 确认结果 df -hT /这套流程下来整个扩容操作完成。你可能觉得步骤多但每一步都是为了让系统在数据安全的前提下资源最大化。LVM 在扩容这件事上确实比裸分区优雅得多这也是我为什么建议生产环境的根分区用 LVM 的原因。4. 非 LVM 场景普通分区扩容的风险与实操4.1 为什么普通分区扩容更麻烦不是所有虚拟机都采用了 LVM 布局。很多一键安装脚本或者早期创建的虚拟机根分区就是一个普通分区比如/dev/vda1。这种情况下新扩容的空间不会自动出现在任何分区里你只能看到vda从 50G 变成了 100G但vda1依然是 50G。麻烦的地方在于要给vda1扩容必须修改vda1的分区大小以占用vda剩余的空间。而分区的元数据记录在分区表里修改分区大小的常规思路是删除分区再重新创建但这个删除操作对不了解分区机制的人来说非常吓人。实际上只要保证新创建分区的起始扇区位置和原分区完全一致删除重建分区并不会影响数据区内容数据依然完好。但操作过程的每一步都需要确认。4.2 fdisk 交互式扩容操作全流程以/dev/vda1挂载到根目录、文件系统为 ext4 为例# 进入 fdisk 交互界面 fdisk /dev/vda在 fdisk 交互界面里依次执行以下操作# 输入 p 查看当前分区表记录 vda1 的 Start 扇区位置 p # 输入 d 删除 vda1 分区此时会提示选择分区号输入 1 d # 输入 n 新建分区选择 primary主分区分区号输入 1 n # 提示 First sector 时系统通常会默认使用之前记录的原起始扇区直接回车即可 # 提示 Last sector 时默认是磁盘最大扇区直接回车即可 # 输入 p 确认新分区表重点确认 Start 扇区与原分区一致 p # 输入 w 写入分区表并退出 w执行完这步系统会提示内核重新读取分区表。比较新的系统会自动完成不用额外操作旧的系统可能需要重启或执行partprobe /dev/vda手动触发。4.3 让内核重读分区表与文件系统扩展分区表写入后用lsblk查看分区大小是否更新。如果 vda1 已经从 50G 变成 100G说明分区恢复得很好如果依然显示 50G执行partprobe /dev/vda或者重启虚拟机。在确认分区大小更新后最后一步是扩展文件系统。ext4 文件系统使用resize2fs /dev/vda1注意如果你在 fdisk 删除分区后忘了重新创建分区就重启虚拟机系统会因为找不到根分区而无法启动。这种情况下可以通过宿主机上的virsh console进入 grub 界面或者挂载救援镜像来修复但过程比较痛苦。所以这个操作务必谨慎如果自己对分区操作没有十足把握建议优先选择后面的 virt-resize 方案或者提前备份。4.4 GPT 分区的特例处理上面演示的是 MBR 分区表的情况。如果虚拟机使用的是 UEFI 引导或者 GPT 分区表fdisk 的交互过程略有不同GPT 分区表没有primary/logical的概念创建分区时只需要指定分区号而且 GPT 分区表末尾有一个备份分区表头删除重建分区后系统会自动处理这个备份头。整个过程比 MBR 稍微简单一点但核心逻辑一样保持新分区的起始扇区与原分区一致。5. 不想进系统操作virt-resize 离线扩容方案5.1 virt-resize 的核心价值如果你对 fdisk 删除重建分区有顾虑或者在虚拟机内部操作有诸多不便还有另一个非常推荐的方案使用virt-resize工具离线扩容。它来自 libguestfs 工具集安装简单yum install libguestfs-tools -yvirt-resize 的核心思想是在宿主机上直接对虚拟磁盘镜像文件进行操作避开虚拟机内复杂的操作环境。它对磁盘内部的分区表、LVM 结构、文件系统进行自动调整全程不需要虚拟机开机。这个方式尤其适合以下场景虚拟机内部环境复杂不好操作根分区是非 LVM 布局不想用 fdisk 担惊受怕需要在批量虚拟机初始化前一次性把磁盘调整到合适大小5.2 virt-resize 的具体操作步骤virt-resize 不能直接扩容现有镜像它需要一个新的空镜像文件作为目标然后将旧镜像内容拷贝过去并扩容。操作步骤如下# 1. 创建一个新的大小为 100G 的空镜像文件 qemu-img create -f qcow2 /data/kvm/images/vm-web-new.qcow2 100G # 2. 执行 virt-resize将旧镜像内容复制到新镜像并扩容 virt-resize --expand /dev/vda1 /data/kvm/images/vm-web.qcow2 /data/kvm/images/vm-web-new.qcow2其中--expand /dev/vda1指定要扩展的分区。如果磁盘里有 LVM 结构也可以指定--expand /dev/vg/root的形式virt-resize 会优先展开对应的逻辑卷及其上游物理卷、卷组结构。执行完成后将新镜像文件替换旧镜像。操作方法依然是修改虚拟机的磁盘路径配置virsh edit vm-web如果担心替换后启动有问题我习惯先保留旧镜像文件作为备份等新镜像启动验证无误后再删除。5.3 virt-resize 的两个前提条件使用 virt-resize 有两个注意点。第一新旧镜像的文件格式必须兼容通常都用 qcow2。如果原镜像不是 qcow2先用qemu-img convert转成 qcow2。第二target 镜像文件必须大于源镜像的实际数据占用因为 virt-resize 在拷贝过程中会维护临时空间如果刚好卡在源镜像的虚拟大小边缘有时候会因为临时空间不足而失败。创建一个比源虚拟大小多出 10-20G 的 target 是一个保险策略。5.4 virt-resize 完整操作串演对于普通分区非 LVM 的虚拟机我更喜欢 virt-resize 而不是 fdisk因为操作完全在宿主机侧虚拟机内部不用做任何操作逻辑上更干净。完整的操作演示如下# 宿主机操作 # 1. 确认源镜像信息 qemu-img info vm-web.qcow2 # 2. 创建目标镜像 qemu-img create -f qcow2 vm-web-new.qcow2 100G # 3. 执行扩容拷贝 virt-resize --expand /dev/vda1 vm-web.qcow2 vm-web-new.qcow2 # 4. 替换镜像先关机 virsh shutdown vm-web virsh edit vm-web # 修改 source file...vm-web.qcow2/ 为 ...vm-web-new.qcow2 # 5. 启动虚拟机并验证 virsh start vm-web这个方案唯一的缺点是它要求虚拟机关机而在线扩容方案可以在虚拟机运行期间完成但它的优点在于安全性和可预测性。如果你的虚拟机能接受短暂停机这个方案更省心。6. 常见问题与排查技巧实录6.1 扩容后 lsblk 里 vda 大小没变化进入虚拟机执行lsblk后发现 vda 仍然是原来的大小。这种情况大多是因为内核的 virtio-blk 驱动没有自动感知到磁盘尺寸变化。解决办法执行echo 1 /sys/class/block/vda/device/rescan如果提示文件不存在那么检查路径是否正确或者重启虚拟机。重启基本能在 99% 的情况下解决问题。6.2 pvresize 提示找不到物理卷执行pvresize /dev/vda2时报错No such file or directory或者Failed to find physical volume。这种情况通常是因为分区名不对先执行lsblk确认正确的物理卷设备名。有些系统里是/dev/vda2有些可能是/dev/sda2这取决于虚拟机的磁盘控制器类型。按照lsblk的实际输出为准。6.3 df -h 显示的容量没有变化扩展完逻辑卷、也执行了xfs_growfs或resize2fs但df -h输出没有变化。这个问题的常见原因是你扩展文件系统时用的路径不对。比如 XFS 挂在/data但你写成xfs_growfs /dev/mapper/centos-data这在某些版本上会提示参数错误或者报not a mount point。xfs_growfs 命令要么传挂载点要么不传参数让它自动探测ext4 的 resize2fs 则传逻辑卷设备路径两者不要弄混。6.4 扩容过程中虚拟机断电或故障扩容期间如果虚拟机意外断电最危险的影响不是虚拟磁盘镜像损坏而是否在 fdisk 写分区表的过程中中断。如果中断发生在分区表写入前那么原分区表未变虚拟机仍然可以正常启动如果中断发生在写入后而新的分区表有不一致启动时可能会进入紧急模式或无法识别根分区。这种场景下最好的修复手段是用备份恢复。这也是为什么我一直强调扩容前必须做备份而且备份要独立存储不能和虚拟磁盘放在同一路径下。6.5 在线扩容和 virt-resize 怎么选两种方案各有适用场景我把它们的取舍整理成了一张表对比维度在线扩容LVM 场景virt-resize 离线扩容虚拟机状态运行中即可操作需要关机适用分区布局优先 LVM普通分区也可所有布局均适用操作风险中等步骤多但每步可控较低自动化处理对虚拟机内部操作要求需要进入系统操作无需进入系统执行时间快分钟级中等取决于镜像大小适用场景生产环境不间断业务可接受短时停机的场景在线扩容适合追求零停机的场景virt-resize 适合追求低风险、可预测的场景。我个人的选择标尺如果虚拟机内是 LVM 且文件系统支持在线扩容优先在线操作如果是普通分区、又担心手误就上 virt-resize。没有哪种方案是绝对正确的适合你的环境的就是最好的。6.6 文件系统支持的边界XFS 和 ext4 都是支持在线扩容的主流文件系统但它们的行为不同。XFS 只支持扩容、不支持缩容所以如果你搞错了方向想缩小根目录这条路是堵死的。ext4 支持在线扩容也支持离线缩容但缩容操作有诸多限制且不受推荐。因此扩容前确认方向、确认文件系统、确认逻辑卷布局比实际操作本身更重要。计划好目标容量是我给每个做扩容的人的第一个建议。7. 收尾这些经验是我踩过坑之后才悟出来的做 KVM 虚拟机扩容最核心的体验可以归结为两句话宿主机层面只负责扩大虚拟磁盘的外壳虚拟机内部才是真正决定容量的内核两层操作缺一不可。很多人在宿主机执行完qemu-img resize就以为大功告成结果进系统发现毫无变化又反过来怀疑命令是不是敲错了其实只是漏了虚拟内部分区和文件系统的扩展。我个人在实际操作中还有几个习惯分享出来给你参考。第一扩容后我会顺手把虚拟机的磁盘信息、扩容时间、目标容量记录在一个文件里下次再遇到同类问题可以直接参考省得临时翻聊天记录。第二每次扩容前我花五分钟执行清理命令先清出一部分空间这样需要扩展的增量变得更小操作速度更快。第三只要条件允许我会优先在 LVM 布局上做在线扩容这套方案验证过太多次可靠性确实高。关于这个内容后续的应用还有一个方向值得研究如果你想批量给多台虚拟机扩容可以把本文的操作封装成脚本在宿主机上用virsh list循环处理一步到位给整个集群的虚拟机加容量。这本质上就是把今天的操作流程自动化原理是一样的只是一层封装。扩容本身不复杂复杂的是各种环境差异带来的不确定性。你只要把前置排查做细致、按场景选择合适的路径、每一步都验证上一次执行的结果这场给虚拟机加容量的活儿就不会翻车。
返回列表