ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

bhyve虚拟机Ubuntu系统盘扩容:用parted resizepart轻松搞定

2026/10/7 10:31:39 拓冰建站 浏览量
bhyve虚拟机Ubuntu系统盘扩容:用parted resizepart轻松搞定 折腾过 bhyve 的朋友都知道给虚拟机扩容这件事说难不难说简单也真不简单。最近我又一次扩充一台 Ubuntu 虚拟机的系统盘从宿主机到虚拟机内部来回折腾本来想着跟往常一样改改卷大小、进系统用 fdisk 调一下分区就完事结果这次偏偏多绕了一步在 Ubuntu 里多敲了一个 parted 命令才把新空间真正“激活”。正好有朋友也问到这个问题我把这次的操作过程完整复盘一遍希望能给同样在用 bhyve Ubuntu 的人一点参考。先说清楚这篇文章要解决的问题在 FreeBSD 宿主机上跑 bhyve 虚拟机虚拟机里装的是 Ubuntu系统盘空间不够了需要扩大虚拟机的系统盘容量。常规思路是先把宿主机这层的存储后端撑大再进到 Ubuntu 内部让分区表认出新空间最后让文件系统也跟着长大。这次跟以往最大的区别就是分区表这步使用了 parted 的 resizepart 子命令而不是以前我一直习惯的 fdisk 交互式操作。这个差别看起来不大但遇到 GPT 分区和某些边界情况时parted 反而更省事也不会让你手一抖把起始扇区搞错。这篇内容既适合刚接触 bhyve 的新手也适合那些扩容过很多次、想找个更顺手方法的老手。我会把宿主机端的 zvol/文件镜像扩容、虚拟机里的分区调整、最后一步文件系统扩容都讲清楚另外把我这次踩过的坑一并列出来比如分区表类型不匹配、内核不认新分区表、resize2fs 报错等问题直接给你一套可以照着敲的流程。1. 扩容前先搞懂bhyve 虚拟机磁盘到底存在哪里1.1 bhyve 磁盘后端的两种主流形态bhyve 本身是一个跑在 FreeBSD 上的原生虚拟机监控器它跟 VirtualBox、VMware 这类带图形界面的虚拟机不太一样几乎所有配置都得通过命令行和配置文件来驱动。虚拟机看到的“硬盘”在宿主机上通常对应两种东西一种是 ZFS 的 zvol另一种是普通的磁盘镜像文件。用 zvol 当后端的好处很明显你能直接用 ZFS 的快照、复制、压缩等特性而且 zvol 在 ZFS 里就是一个块设备虚拟机的读写可以走 ZFS 的 ARC 缓存性能比普通文件镜像要稳。用文件镜像比如 .raw 或 .img就简单直接创建方便、方便拷贝迁移但性能上限和功能丰富度都不如 zvol。我这次扩容的机器后端就是 zvol这种选择在规模化的 bhyve 环境里很常见。1.2 扩容的真正难点三层链路都要打通先想清楚扩容这件事的本质。虚拟机里看到的磁盘容量实际上由三层决定宿主机层的存储后端大小比如 zvol 的 volsize或镜像文件的实际字节数虚拟机磁盘上的分区表信息分区表记录的每个分区在磁盘上的起止范围分区内的文件系统大小比如 ext4 的块组数量、inode 表位置。简单来说磁盘总容量变大了并不等于 Ubuntu 里可用的空间变多了。你拿一块 50G 的硬盘给 Ubuntu如果分区表里根分区仍然只写到 20G 的位置那 Ubuntu 只会看到 20G就算分区表改了如果 ext4 文件系统本身的空间结构还凝固在 20G 处Ubuntu 的文件系统也不会自动扩展。所以扩容一定得三步做齐宿主机扩后端 → 虚拟机里扩分区 → 扩文件系统。任何一步漏了结果都是“看着磁盘大了但 df -h 还是老样子”。1.3 这次为什么多了个 parted 命令以前我扩容进 Ubuntu 之后通常用 fdisk 的交互界面先 d 删掉目标分区再 n 新建一个分区然后手动把起始扇区填成原来的值最后 w 保存。这套流程轻车熟路但有个隐患每次删掉分区重建起始扇区必须一字不差地填回去手一抖或者复制粘贴出错数据就全没了。另外 fdisk 对于 GPT 分区表也能处理但交互式操作在脚本化或远程终端里显得很啰嗦。这次扩容时我发现这台 Ubuntu 的分区表是 GPT而且分区数量不止一个用 fdisk 删了重建风险太高。于是改用 parted 的 resizepart 子命令直接告诉它“从第几个分区开始把结束位置挪到磁盘末尾”。这个命令只调整分区的终点起始位置完全不动彻底避开了删除分区再重建带来的风险。我实际敲完之后才意识到这一步其实比 fdisk 的方案要优雅得多以后大概率会成为我的默认操作。2. 宿主机端先把底层存储撑大2.1 先确认你的虚拟机用的是哪种后端动手之前先别急着敲命令。得先搞清楚这台虚拟机的磁盘到底挂的是什么。我通常这样查看一下虚拟机配置文件或者直接用 zfs list 看看有没有对应的 zvol。# 在 FreeBSD 宿主机上 zfs list -o name,volsize,used,available如果看到类似zroot/vm/ubuntu这种名字并且用了 volsize 属性说明磁盘后端就是 zvol。要是没有 zvol那就去虚拟机配置里找磁盘文件路径一般是.raw或.img结尾的普通文件。# 查看 bhyve 虚拟机配置常见路径 cat /etc/vm.conf # 或者直接用 vm 命令列出 vm list注意这里有个很容易忽略的点bhyve 虚拟机有时用vm run这种工具来管理配置写在/etc/vm.conf或/usr/local/etc/vm.conf里面会给每个虚拟机的磁盘指定disk0disk1等设备的来源可能是/dev/zvol/...也可能是一个文件路径。看清楚这步后面所有操作才不会搞错对象。2.2 zvol 扩容一行 zfs 命令如果磁盘后端是 zvol扩容很简单直接用zfs set volsize。比如我要把zroot/vm/ubuntu这个 zvol 从 20G 扩到 50Gzfs set volsize50G zroot/vm/ubuntu就这么一行。执行完可以再确认zfs get volsize zroot/vm/ubuntu这里要特别提醒ZFS 的 volsize 表示逻辑卷大小扩容后 zvol 的实际占用used 属性不会立刻增长而是等虚拟机往里写数据时才会消耗空间。这是一个很容易让人误解的地方别一看 used 没变就觉得扩容没生效。还有一个实践上的建议如果虚拟机正在运行我倾向于先把虚拟机关机再执行zfs set volsize。虽然 ZFS 支持在线调整 zvol 大小但 bhyve 的 virtio-blk 设备是否能无缝感知扩容后的容量取决于驱动和固件与其在运行状态下赌这个不如停机操作干净又安全。这次我也没例外先停了 Ubuntu在宿主机上扩好卷再启动虚拟机进去操作。2.3 文件镜像扩容truncate 与潜在隐患如果你的 bhyve 磁盘是 raw 格式的镜像文件扩容也简单用 truncate 把文件“撑大”即可# 在原基础上增加 30G truncate -s 30G /vm/ubuntu.raw # 或者直接指定最终大小 truncate -s 50G /vm/ubuntu.rawtruncate 修改的是文件逻辑大小不会填充实际数据所以扩展的部分在文件系统里显示为空洞不占宿主机磁盘空间速度很快。但有个大坑如果后端不是 raw而是 qcow2 或其他带格式的镜像直接用 truncate 往往会把镜像头搞乱虚拟机可能直接起不来。bhyve 原生支持最好的是 raw 格式和 zvolqcow2 通常需要额外的转换/挂载流程。所以再次强调动手前先确认后端类型。如果是 qcow2先qemu-img resize去扩别用 truncate 硬怼。3. 虚拟机内部用 parted 重新划分分区3.1 开机后先确认磁盘设备名和分区表类型宿主机扩容完成之后启动 Ubuntu。进入系统后先看虚拟机关联到的块设备名称。bhyve 的 virtio 磁盘在 Linux 里通常是/dev/vtbd0有些内核版本或配置也可能显示为/dev/vda取决于 virtio 驱动。我这里的 Ubuntu 显示为/dev/vtbd0。lsblk fdisk -l /dev/vtbd0lsblk 能直观看到磁盘和分区的层级关系。比如NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT vtbd0 252:0 0 50G 0 disk ├─vtbd0p1 252:1 0 1M 0 part ├─vtbd0p2 252:2 0 1G 0 part /boot └─vtbd0p3 252:3 0 19G 0 part /这里能看到磁盘 vtbd0 现在已经是 50G但最下面的根分区还停留在 19G原来 20G 磁盘减去 boot 分区等说明分区表还没有感知到新增空间。这就是我们要处理的核心问题。接下来关键一步确认分区表类型。GPT 和 MBR 的调整方式有细微差别。执行parted /dev/vtbd0 print输出里会明确显示Partition Table: gpt或Partition Table: msdos。如果是 GPT后面用 parted 会很顺手如果是 MBRmsdos也可以用 parted 扩但要小心主分区数量不能超过 4 个的限制。3.2 parted resizepart 的正确姿势确认完后就可以用 parted 调整分区了。我要把第三个分区根分区编号 3扩展到磁盘末尾。parted 支持交互模式和非交互模式我强烈推荐非交互模式因为命令执行完结果一目了然出错也容易回溯。# 非交互模式直接把第 3 个分区的终点设为磁盘 100% 位置 parted /dev/vtbd0 resizepart 3 100%这条命令的意思是把分区 3 的 end 位置调整到磁盘结尾 100%。parted 会自动计算结束扇区完全不用你手动换算起始扇区、结束扇区那些数字。如果是交互模式大概是这种感觉parted /dev/vtbd0 (parted) resizepart 3 End? [40.0GB]? 100% (parted) quit交互模式里parted 会问你新的结束位置你可以直接输入想设置的容量数值比如50GB也可以输入100%。我个人更喜欢非交互式因为可以完整保留命令记录方便写文档和回头检查。这里有一个很重要的细节parted 的 resizepart 只需要指定分区号和新的结束位置完全不需要碰起始位置。这也是我这次特别想强调的一点——相比 fdisk 删除重建这个命令天然就更安全。起始位置一旦改变文件系统的基本盘就碎了而 resizepart 把这个风险直接降为零。3.3 执行后再仔细确认分区状态执行完 parted 之后千万别急着去扩文件系统先确认分区表本身没问题parted /dev/vtbd0 print这时应该能看到分区 3 的终点已经变成磁盘末尾了。我再建议顺便看一眼lsblk fdisk -l /dev/vtbd0正常的话vtbd0p3 的 SIZE 已经变成了接近 48G 左右取决于前面有没有 boot 分区。到这一步分区表已经“认识”了新的空间但内核可能还保留着旧的分区表缓存。Linux 内核是在分区表变化后可能不会主动重读。最稳妥的办法是重启虚拟机让系统以全新状态加载分区表。但如果你不想重启有几种方式可以触发内核重读分区表执行partprobe /dev/vtbd0或partx -u /dev/vtbd0。我在这次操作中先试了 partprobe能更新大部分场景但如果是根分区所在的磁盘有时还是会提示 partition in use这时候最好不要强行操作直接重启最省心。注意扩容过程中任何一步出现“设备忙”或“分区被占用”的提示都不要强制重试。尤其是根分区所在磁盘内核重读会有风险。我这次的方案就是干脆重启Ubuntu 启动非常快没必要省这几秒钟给自己挖坑。4. 文件系统扩容最后一步别漏掉也别搞错命令4.1 ext4resize2fs 使用要点分区表已经扩好了但 Ubuntu 里的文件系统还是旧尺寸。这一步对应的是根分区通常文件系统是 ext4也可能是 xfs取决于当初安装选项。先确认文件系统类型df -T /输出里Type那一列如果是ext4就用 resize2fs如果是xfs就要改用 xfs_growfs。我这次这台虚拟机是 ext4所以执行# 在线扩容根分区对应的文件系统 resize2fs /dev/vtbd0p3不需要指定大小resize2fs 默认会把文件系统扩展到分区大小。执行完再看df -h /正常情况下根分区已经变成接近 48G 的容量了。这里我要特别提一个容易踩的坑如果分区表中分区 3 的结束位置没有真正确认好resize2fs 可能会报错比如Couldnt find valid filesystem superblock或者Invalid argument。遇到这类报错第一反应不应该是怀疑文件系统损坏而应该先回去检查分区表用parted /dev/vtbd0 print确认分区终点是否真的到了磁盘末尾、有没有出现未分配空间。绝大多数时候问题都出在分区层不在文件系统层。4.2 其他文件系统xfs 和 btrfs 的差异如果当初装系统时选了 XFS那扩容方式完全不同。XFS 文件系统扩展必须挂载后才能进行而且它是基于挂载点来扩容不是基于设备节点# 假设根分区是 xfs xfs_growfs /注意看区别resize2fs 后面跟的是设备路径/dev/vtbd0p3xfs_growfs 后面跟的是挂载点/。这是因为 XFS 的文件系统扩容工具在设计上必须针对已挂载文件系统操作而且它读取的也是挂载信息里的设备。如果是 btrfs命令又不一样btrfs filesystem resize max /btrfs 可以支持 subvolume 和在线 resize相对灵活但在 Ubuntu 默认安装里比较少见这里就不展开了。总之动手前一定先确认文件系统类型别拿 ext4 的命令去怼 xfs那是牛头不对马嘴。5. 实际操作中踩过的坑与排查实录5.1 为什么 fdisk 删除重建的风险那么大在这次扩容的过程中我稍微复盘了一下之前用 fdisk 删分区重建的经验越想越觉得这次选择 parted 是明智的。fdisk 交互式删除重建时系统会提示你输入分区的起始扇区很多人想当然地直接回车“使用默认值”结果默认的起始位置和原来并不完全一致轻则分区偏移导致文件系统无法挂载重则被识别成损坏分区。我在以前的一台测试虚拟机上就翻过车删除分区后新建时起始扇区输错了导致后面所有分区的顺序错乱恢复起来相当耗时。parted 的 resizepart 从根本上规避了这个风险——它不给你修改起始位置的机会只让你改终点。对于扩容场景这就够了。还有一点现在的 util-linux 新版 fdisk 也支持resizepart命令了但很多人习惯的还是旧版交互式流程。如果你不想装 parted或者系统里正好没有 parted可以试试这条fdisk /dev/vtbd0 Command (m for help): r有那份功夫我宁可装 parted它的输出格式更直观命令也更好写进脚本。5.2 分区表类型不匹配导致 resizepart 报错有次我在另一台机器上执行parted resizepart报了错。查了半天才发现那台虚拟机的磁盘分区表是 MBRmsdos而我在指令里用了类似 GPT 场景下的写法导致 parted 对分区边界的校验方式不一样给出了Error: Cant have overlapping partitions之类的提示。后来我把输出贴出来细看发现问题在于磁盘尾部有未分配空间且 MBR 的分区记录方式对结束位置有自己的一套对齐规则。解决办法也不难先用parted /dev/vtbd0 unit MiB print查看精确的边界再用parted /dev/vtbd0 resizepart 3 新结束位置指定到合适的 MiB 边界。总而言之遇到报错别慌先确认分区表类型、确认分区编号、确认没有其他分区挡在目标结束位置之前。5.3 根分区在线扩容的危险边界理论上resize2fs 支持在线扩容也就是说分区表调整好之后不必重启也能直接执行。但在实际操作中我建议根分区还是重启一次最好。原因有几个根分区被内核持续挂载使用partprobe 可能无法稳定重读分区表如果分区表信息与内核实际使用的块设备状态不一致resize2fs 可能读到不完整的块设备大小系统在扩容过程中如果发生异常断电或 IO 错误恢复的复杂度要比普通分区高很多。我这次是停机扩的 zvol启动 Ubuntu 后先做 parted然后重启了一遍再执行 resize2fs。你说慢吧也就多一分钟但换来的确定性和安全性远大于这一分钟的成本。5.4 扩容后宿主机 zvol 空间占用骤增的疑问还有一个容易误解的点还在宿主机端。扩容 zvol 后有人会惊讶地发现 zfs list 里的 used 值涨了不少以为出问题。这其实是因为虚拟机开机后Ubuntu 的 ext4 文件系统扩容会触发大量元数据更新写入新的块组和 inode 表自然消耗了 ZFS 的存储空间。如果你启用了 ZFS 的压缩属性情况会好很多。另外扩容完成后如果你有快照习惯建议在确认系统正常后再清理旧的过期快照别在扩容中途删快照以免万一出问题时没有后悔药。我把这次遇到的典型问题和处理方式整理成一张表放在下面症状可能原因处理方式lsblk 显示磁盘已变大但分区没变分区表未更新用 parted resizepart 调整分区终点parted print 显示分区表类型不匹配GPT/MBR 判断错误先确认分区表类型再按对应规则调整partprobe 提示设备忙根分区或挂载中的分区无法安全重读重启 Ubuntu 再继续resize2fs 找不到有效超级块分区表起点/终点异常或分区未扩展成功回头检查 parted print 输出确认分区边界df -h 容量没变化文件系统还没扩容按文件系统类型执行 resize2fs/xfs_growfs宿主机 zfs used 暴涨虚拟机文件系统扩容写入元数据正常现象必要时检查 ZFS 压缩属性5.5 再补两个实用小技巧第一如果有条件执行扩容前给 zvol 或文件镜像做一个快照这是成本最低的保险。我在这次扩容前顺手打了个 ZFS 快照zfs snapshot zroot/vm/ubuntuexpand_before万一后面哪一步出了问题一条zfs rollback就能把虚拟机的存储状态恢复到扩容前。这种“事前快照”的习惯能省掉很多个通宵抢救数据的夜晚。第二远程操作时建议把每一步的命令输出都存下来方便事后复盘parted /dev/vtbd0 print | tee /tmp/parted_before.txt # 执行扩容... parted /dev/vtbd0 print | tee /tmp/parted_after.txt diff /tmp/parted_before.txt /tmp/parted_after.txt这样一眼就能看到分区边界发生了什么变化也方便排查问题。6. 这次扩容后我沉淀下来的操作心得复盘这次扩容我对“宿主机 zvol 扩展 虚拟机内 parted 调整分区 resize2fs 扩展文件系统”这条链路有了更清晰的把握。如果你要问我现在给 bhyve 里的 Ubuntu 扩容最推荐的路径是什么我会给出这样一套宿主机确认后端类型zvol 还是 raw 文件zvol 执行zfs set volsize或 raw 文件执行truncate -s N启动 Ubuntu用parted /dev/vtbdX resizepart 分区号 100%扩展分区重启以确保内核重读分区表根据文件系统类型执行resize2fs、xfs_growfs或btrfs filesystem resize max用df -h验证顺手打一个确认状态的快照。最关键的变化就是把从前用 fdisk“删了重建”的老操作换成了 parted 的 resizepart。这个过程真的只有一字之差但安全性却高了不止一个量级。尤其当你面对的是根分区、GPT 分区表、多分区布局的时候parted 的“只动终点不碰起点”理念几乎是针对扩容场景量身定做的。如果只是临时应付一台虚拟机你现在就可以照着这篇的步骤去做如果打算长期维护一批 bhyve 虚拟机我建议把扩容流程脚本化把 zvol 大小、分区号、文件系统类型都做成参数到时候一条命令跑完省心省力。脚本化的过程中强烈建议保留每一步的校验逻辑别只图快毕竟系统盘扩容这种东西一次出错付出的代价远比你省下的那几分钟多。