Unraid 虚拟机 fnOS 存储扩容实战:64G 到 128G,一路扩容到 Btrfs
最近我的 fnOS 虚拟机 /vol1 空间快用满了,原本只有 64 GiB 的虚拟数据盘已经达到了 100% 的使用率,仅剩几百 MB 可用空间。

由于这个虚拟磁盘并不是简单的“分区 + 文件系统”结构,而是经过了 qcow2 → GPT 分区 → mdadm RAID1 → LVM → Btrfs 多层封装,因此扩容不能只执行一个命令,而是需要从最外层一路扩到最里面。
最终,我把这块虚拟磁盘从 64 GiB 成功扩容到了 128 GiB,/vol1 的可用空间也从仅剩约 424 MB 增加到了约 65 GB。
一、先看看原来的磁盘结构
首先进入 Unraid 中存放 fnOS 虚拟磁盘的目录:
cd /mnt/user/domains/fnOS/
ls
目录中可以看到:
vdisk1.img
vdisk2.img
这里这次需要处理的是 vdisk2.img。
先查看镜像信息:
qemu-img info vdisk2.img
输出显示:
image: vdisk2.img
file format: qcow2
virtual size: 64 GiB
disk size: 64 GiB
也就是说,这是一块 qcow2 格式、64 GiB 的虚拟磁盘。
进入 fnOS 后再看看里面的实际磁盘结构:
lsblk
可以看到:
vdb 128G
└─vdb1 64G
└─md0 64G
└─LVM 64G
/vol1
虽然这里的虚拟磁盘已经显示成 128G,但下面的分区和存储层实际上还是 64G。
再看文件系统:
df -Th
当时 /vol1 的状态是:
btrfs 64G 62G 424M 100% /vol1
已经基本没有空间了。
二、第一步:扩容 qcow2 虚拟磁盘
回到 Unraid 宿主机,直接使用 qemu-img 给虚拟磁盘增加 64 GiB:
qemu-img resize vdisk2.img +64G
执行后显示:
Image resized.
然后再次检查:
qemu-img info vdisk2.img
现在可以看到:
file format: qcow2
virtual size: 128 GiB
disk size: 64 GiB
这里需要注意,virtual size 已经从 64 GiB 变成了 128 GiB,而 disk size 仍然是 64 GiB。
这对于 qcow2 来说是正常的,因为 虚拟容量和当前实际占用的宿主机空间是两个概念。虚拟磁盘虽然拥有了 128 GiB 的容量,但新增出来的空间还没有真正写入数据,因此实际占用空间暂时没有增加。
三、第二步:扩展 GPT 分区
进入 fnOS 后,先检查分区表:
parted /dev/vdb print
第一次执行时,parted 会发现磁盘已经变大,但 GPT 分区表还没有使用新增出来的空间,并提示:
Warning: Not all of the space available to /dev/vdb appears to be used
这里选择:
Fix
修复 GPT 后,磁盘大小已经是:
Disk /dev/vdb: 137GB
但分区仍然只有:
1 1049kB 68.7GB 68.7GB primary raid
也就是说 /dev/vdb1 还没有跟着扩大。
于是将第 1 个分区扩展到磁盘末尾:
parted /dev/vdb resizepart 1 100%
执行完成后再次检查:
parted /dev/vdb print
结果变成:
1 1049kB 137GB 137GB primary raid
这一步完成后,GPT 分区已经从原来的约 64 GiB 扩展到了整块磁盘。
四、第三步:扩展 mdadm RAID1
这里是整个扩容过程中比较容易忽略的一层。
/dev/vdb1 后面并不是直接接 LVM,而是还有一层 mdadm RAID1:
vdb
└─vdb1
└─md0
先让 mdadm 使用新增的空间:
mdadm --grow /dev/md0 --size=max
返回:
mdadm: component size of /dev/md0 has been set to 134182895K
再检查:
lsblk
此时:
vdb 128G
└─vdb1 128G
└─md0 128G
└─LVM 64G
说明 RAID 层已经成功扩容。
继续通过:
mdadm --detail /dev/md0
确认:
Raid Level : raid1
Array Size : 127.97 GiB
Raid Devices : 1
Total Devices : 1
这块 fnOS 数据盘使用的是一个比较特殊的 单盘 RAID1 结构,因此这里实际上只有一个 RAID 成员。扩容过程中不涉及第二块磁盘的数据同步。
五、第四步:扩展 LVM PV
RAID 层扩大以后,LVM 还不知道下面已经多出了空间。
执行:
pvresize /dev/md0
然后检查:
pvs
vgs
可以看到:
/dev/md0 ... 127.96g 64.00g
以及:
VSize 127.96g
VFree 64.00g
说明 LVM 已经识别到了新增的约 64 GiB 空间,目前还有 64 GiB 没有分配给 LV。
六、第五步:扩展 LVM LV
接下来把 VG 中剩余的空间全部分配给现有的 LV:
lvextend -l +100%FREE /dev/mapper/trim_40093025_3c45_46b0_b801_159bdd4fa714-0
执行结果:
Size of logical volume ... changed from 63.96 GiB
to 127.96 GiB
至此,LVM LV 已经从约 64 GiB 扩展到了约 128 GiB。
七、第六步:扩展 Btrfs 文件系统
最后一层就是 Btrfs。
虽然 LV 已经变成 128 GiB,但是 Btrfs 文件系统本身仍然需要扩容,否则系统层面依旧无法使用新增空间。
直接执行:
btrfs filesystem resize max /vol1
系统返回:
Resize device id 1 (...) from 63.96GiB to max
说明 Btrfs 已经成功扩展到最大容量。
八、最后检查扩容结果
执行:
df -Th /vol1
最终结果:
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/... btrfs 128G 62G 65G 49% /vol1
对比一下扩容前后:
| 项目 | 扩容前 | 扩容后 |
|---|---|---|
| qcow2 虚拟磁盘 | 64 GiB | 128 GiB |
| vdb1 | 约 64 GiB | 约 128 GiB |
| md0 | 约 64 GiB | 约 128 GiB |
| LVM LV | 约 64 GiB | 约 128 GiB |
Btrfs /vol1 | 64G | 128G |
/vol1 可用空间 | 424 MB | 65G |
| 使用率 | 100% | 49% |
整个扩容过程至此完成。
九、完整命令记录
为了以后自己再次操作方便,最后把这次实际执行的核心命令整理一下。
Unraid 宿主机
cd /mnt/user/domains/fnOS/
qemu-img info vdisk2.img
qemu-img resize vdisk2.img +64G
qemu-img info vdisk2.img
fnOS
lsblk
df -Th
parted /dev/vdb print
# GPT 提示时选择 Fix
parted /dev/vdb resizepart 1 100%
parted /dev/vdb print
mdadm --grow /dev/md0 --size=max
lsblk
mdadm --detail /dev/md0
pvresize /dev/md0
pvs
vgs
lvextend -l +100%FREE /dev/mapper/trim_40093025_3c45_46b0_b801_159bdd4fa714-0
btrfs filesystem resize max /vol1
df -Th /vol1
总结
这次扩容最关键的地方,就是不要把它理解成简单的“虚拟磁盘扩容”。
实际上需要沿着存储栈一层一层向下扩:
qcow2
↓
虚拟磁盘
↓
GPT 分区
↓
mdadm RAID1
↓
LVM PV
↓
LVM LV
↓
Btrfs
↓
/vol1
任何一层没有扩容,最终系统都无法使用新增的空间。
这次实际操作下来,从宿主机的 vdisk2.img 开始,最终一路扩到了 fnOS 的 /vol1,成功把 64 GiB 存储空间翻倍到了 128 GiB。整个过程中原有数据保持不变,也不需要重新创建文件系统。
对于这种 Unraid + fnOS + qcow2 + mdadm + LVM + Btrfs 的多层存储结构,这种逐层扩容的方法也比较适合作为后续继续扩容的参考。
