前阵子遇到一个很实际的需求一台 VirtualBox 虚拟机里的 Windows 系统彻底起不来了但我只想把里面的几个文档和数据库备份捞出来。以前我会先把镜像转成 raw 再挂载镜像几十 GB转换一次要几分钟中途还容易把磁盘空间占满。后来换成 vdfuse 这条命令直接在 Linux 宿主机上把 VDI/VMDK/VHD 虚拟磁盘镜像挂成用户态文件系统几秒钟就能看到分区整个过程顺了很多。这篇文章就把我在实际操作中总结的用法、坑和选型思路完整梳理一遍适合所有想把 VirtualBox 镜像里的数据“掏出来”的人参考。1. vdfuse 到底是什么以及它解决了什么问题1.1 虚拟磁盘镜像的“容器”本质VDI、VMDK、VHD 这三种格式虽然出身不同但本质上都是“容器”。它们把一个虚拟磁盘保存成单文件或多文件文件内部有元数据、块分配表、数据扇区还有可能存在快照链。平时这些格式由虚拟化软件自动识别所以你不会感觉到它们和普通文件有什么差别。可一旦你想在宿主机上直接读取它普通工具就不认了。你以为的“读镜像”就是 mount 一下但实际上 Linux 的 mount 命令不认识 VDI/VMDK/VHD 内部结构它只认真正的块设备或者经过 loop 挂载的 raw 镜像文件。这时候就需要一层翻译把虚拟磁盘内部的分区结构重新暴露出来。vdfuse 做的就是这件事。它本质上是一个 FUSE 前端的翻译器。你给它一个镜像文件它把这个镜像里的“整块磁盘”和“每个分区”以文件形式暴露在某个挂载点下。看到的不再是镜像内部二进制数据而是entiredisk、partition1、partition2这样的节点后续你想挂哪个分区就用 mount 去挂这些节点。1.2 为什么我不直接转成 raw很多人第一反应是转换格式VBoxManage clonehd --format RAW vm.vdi vm.raw qemu-img convert -f vdi -O raw vm.vdi vm.raw这两种方式都能得到一个大文件随后直接 mount -o loop vm.raw或者用 losetup 挂成块设备。缺点也很明显转换时间随镜像大小线性增长一个动态分配的 VDI 虽然实际占用只有 30GB但转换出来的 raw 是完整虚拟容量可能直接是 300GB。如果你的磁盘只剩 50GB转换直接失败。vdfuse 不生成完整副本它按需读取镜像内部数据通过 FUSE 把扇区内容映射出来。读取速度取决于镜像存放的位置和 FUSE 实现的效率但对于“捞几个文件”“离线检查分区表”“只读分析系统盘”这类需求已经足够快了。1.3 实际能用在哪些场景我实际用下来vdfuse 最适合这些场景虚拟机系统崩溃需要进入分区目录找回用户文件想对一台虚拟机的系统盘做只读安全扫描不想启动 VM备份后想验证镜像里的数据是否完整需要快速查看某个分区用了什么文件系统、分区表是什么样小规模修改镜像内的配置文件比如替换一个授权文件。注意最后一项有一定风险涉及写镜像时我会尽可能先复制一份后面会详细说。2. 安装 vdfuse 与前置环境准备2.1 先确认内核和用户态 FUSE 支持vdfuse 依赖 Linux FUSE。绝大多数桌面和服务器发行版默认内核都带 fuse 模块但极简环境、容器环境里可能没启用。安装之前先检查ls -l /dev/fuse modprobe fuse如果ls /dev/fuse没有输出说明 /dev 下没有 fuse 设备节点可以先加载模块。能正常加载后确认/dev/fuse存在。注意这个设备节点也是用户态挂载的基础后面很多权限问题都和它有关。另外很多发行版把普通用户放进 fuse 组才能使用 fusermount 挂载。实际操作我一般都直接用 root 或者 sudo但如果你想用普通用户执行 vdfuse可以检查一下自己是否在 fuse 组里groups没在就把自己加进去重新登录一次。2.2 安装 virtualbox-fuse 包我用的发行版里vdfuse 由风险包名virtualbox-fuse提供。Debian 系下直接sudo apt update sudo apt install virtualbox-fuseRedHat 系下类似sudo dnf install virtualbox-fuse如果你的仓库里没有这个包也可以去 VirtualBox 相关工具链的源码里找 vdfuse 自己编译但那需要额外解决依赖非必要不建议。装好后确认一下which vdfuse vdfuse -h能打出帮助说明说明环境已经就绪。2.3 vdfuse 常用参数速查vdfuse 的参数不多但有几个关键项必须记住参数含义说明-f 文件指定镜像文件必填路径可以是相对路径或绝对路径-t 类型指定镜像类型可填 vdi / vmdk / vhd不填时自动识别-r只读方式打开强烈建议救援场景先加这个-a 选项传给 FUSE 的附加参数最常用 allow_other解决多用户访问问题-d调试模式出问题排错用会输出详细日志-h显示帮助记不清参数时直接看命令基本形态是sudo vdfuse -f /path/to/image.vdi /mnt/vdi如果自动识别失败就用 -t 显式指定。VMDK 多文件分段时-f 指向主描述符文件通常也能工作。2.4 准备挂载点挂载前先建好目录。我会建两个sudo mkdir -p /mnt/vdi sudo mkdir -p /mnt/winroot第一个放 vdfuse 产生的磁盘节点第二个放最后分区挂载结果。不要在 vdfuse 挂载点里直接放文件因为一挂载 FUSE 目录原本目录里的内容会被暂时隐藏。3. 完整实操从镜像到分区目录3.1 第一次挂载镜像看看里面长什么样假设镜像叫 vm.vdi。执行sudo vdfuse -f vm.vdi -a allow_other /mnt/vdi没有报错的话查看ls -l /mnt/vdi你可能会看到类似这样的内容-r--r--r-- 1 root root 128849018880 Jan 1 1970 entiredisk -r--r--r-- 1 root root 10737418240 Jan 1 1970 partition1 -r--r--r-- 1 root root 53687091200 Jan 1 1970 partition2这里entiredisk代表整块虚拟磁盘partition1、partition2分别代表磁盘里的分区。注意这些节点虽然表现为普通文件但严格说是 FUSE 暴露出来的“虚拟块设备接口”大小显示的是虚拟容量不是实际占用空间。不要尝试用 mkfs 对它格式化那会把镜像写坏。如果只有一个分区且是直接文件系统没有分区表那么可能只看到entiredisk。这种情况我会直接用 entiredisk 做后续挂载因为分区表本身就不存在。3.2 挂载单分区用 partitionN 一步到位最常见的 Windows 虚拟机磁盘通常是分区表里一个 NTFS 主分区。此时直接把 partition1 挂出来mount -o loop,ro /mnt/vdi/partition1 /mnt/winroot这里-o loop告诉内核把普通文件当块设备。Linux 新版 mount 在遇到普通文件时也会自动调用 loop但显式写更稳。加 ro 是为了安全救援场景我不希望在读取过程中意外改了镜像内容。挂载成功后df -h /mnt/winroot此时就能看到正常的 NTFS 文件系统进去复制文件即可。如果镜像比较大第一次读取时可能会慢因为 FUSE 要按需读取镜像内部分配的块。后续再次访问同一块区域会有缓存体感会好很多。3.3 多分区磁盘别急着挂 partition1很多 Linux 虚拟机或者配置了 EFI 引导的 Windows 虚拟机磁盘里会有多个分区。比如 EFI 系统分区、MSR 分区、Windows C 盘、恢复分区。保险的做法是先看整个磁盘的分区表fdisk -l /mnt/vdi/entiredisk输出里能清楚看到起始扇区、类型、大小。如果 vdfuse 已经为你生成 partition1/partition2 等文件直接逐一挂载分区文件就行。例如mount -o loop,ro /mnt/vdi/partition2 /mnt/winroot如果ls /mnt/vdi里只有 entiredisk没有生成 partitionN或者你想更精确地控制偏移可以用 offset 参数手动挂载。假如 fdisk 显示主分区从第 2048 扇区开始扇区大小 512 字节那么偏移就是mount -o loop,ro,offset$((512*2048)) /mnt/vdi/entiredisk /mnt/winroot这里的计算逻辑是偏移量 扇区大小 × 起始扇区号。512 乘 2048 等于 1048576 字节也就是 1MB 对齐的典型起点。手动 offset 适合一些很老或者特殊格式的镜像也是排查问题时的兜底手段。遇到 LVM 或 LUKS 的虚拟机磁盘情况更复杂一点。挂载 partition 文件后先用 file 命令判断file /mnt/vdi/partition1如果返回 “LVM2 PV” 或 “LUKS encrypted file”那需要额外处理 LVM用 losetup 创建 loop 设备然后 vgscan、vgchange -ay再挂载逻辑卷。这部分很容易劝退新手但判断逻辑清晰先识别文件系统类型再决定下一步。3.4 只读还是读写这个选择决定安全vdfuse 默认不加 -r 时允许写入镜像。但我个人的习惯是救援场景一律先加 -r。sudo vdfuse -f vm.vdi -r /mnt/vdi只读挂载有两大好处不会因为误操作破坏原始镜像不会因为 FUSE 处理写请求时对动态分配镜像进行扩展而意外填满宿主机磁盘。如果确认需要修改镜像里的内容我的做法是先备份cp --sparsealways vm.vdi vm-backup.vdi--sparsealways会尽量保持稀疏文件特性备份文件不会立刻占满等量磁盘空间。然后不加 -r 重新挂载。另外永远不要在一个仍在运行的虚拟机里挂载同一个 VDI。虚拟化软件和 vdfuse 同时访问同一镜像极有可能把镜像写坏。操作前记得先关机。4. 常见问题与排查实录4.1 /dev/fuse 权限问题最常见的是普通用户执行 vdfuse 时报fusermount: failed to open /dev/fuse: Permission denied或者fuse: device not found, try modprobe fuse first解决办法分步来确认输出 /dev/fuse 存在把自己加入 fuse 组重新登录检查 /etc/fuse.conf 是否需要 user_allow_other 配置。如果以上都不行直接用 sudo 执行 vdfuse 是最快解。因为这种工具本来就是给系统管理员准备的root 权限下问题少很多。4.2 allow_other 报了 option not allowed如果你想让 root 或另一个用户能在挂载后读取 FUSE 暴露的文件就用到 -a allow_other。但有些发行版默认只允许挂载者本人访问直接使用 allow_other 会报错。解决办法是在 /etc/fuse.conf 里找到#user_allow_other改成user_allow_other保存后重新执行 vdfuse。这一步非常容易漏我第一次折腾时卡了很久新环境搭建时建议直接提前改好。4.3 vdfuse 无法识别镜像类型有时候执行后会看到类似 “Cannot determine image type” 或者直接错误退出。原因一般是三种镜像格式不是 VDI/VMDK/VHD可能是 qcow2 或其他格式镜像已经损坏头部元数据不完整需要显式指定类型。解决方法是先用 file 命令看一下镜像file vm.vdi然后用 -t 强制指定类型。如果确定是 qcow2 等 vdfuse 不支持的格式就转用 qemu-nbd 或 libguestfs别硬刚。4.4 mount 分区时报错 wrong fs type挂载 partition1 时出现mount: /mnt/winroot: wrong fs type, bad option, bad superblock这个报错不等于镜像坏了。我遇到的情况有几类分区是 NTFS但系统没有安装 ntfs-3g分区实际是 LVM不能用普通 mount 直接挂分区是加密分区需要先解锁分区文件并不是真正的分区内容可能 offset 选错。先跑file /mnt/vdi/partition1它会告诉你它的真实类型。比如 NTFS 就装 ntfs-3gext4 就看内核支持LVM 就走 LVM 流程。总之不要看到 wrong fs type 就开始怀疑工具。4.5 快照链和差分镜像的坑VirtualBox 的快照机制会生成子镜像子镜像只保存变化的数据真正初始数据在父镜像里。如果你对一个快照生成的差分 VDI 执行 vdfuse它有时会报错或读出来的分区内容不完整因为它默认把它当成单文件独立镜像处理。最稳的方法是先把整个快照链“拍平”成一个单文件VBoxManage clonehd vm-snapshot.vdi vm-flat.vdi --format VDI然后用 vdfuse 挂载拍平后的文件。这一步虽然消耗时间但能规避大量权限、格式和一致性隐患。5. 同类工具对比和我的选型心得5.1 qemu-nbd、guestmount、vdfuse 到底怎么选Linux 生态里能挂载虚拟磁盘镜像的不止 vdfuse 一个。我把常用方案整理成了表工具挂载方式适合场景注意点vdfuseFUSE 用户态VirtualBox 系 VDI/VMDK/VHD 快速读取写镜像有风险需配合权限配置qemu-nbd内核 NBD需要把镜像当真实块设备操作需要 nbd 模块卸载时记得 d 断开guestmountlibguestfs FUSE自动化巡检、跨格式挂载依赖较多首次安装体积大qemu-img convert转换成 raw一次转换后频繁使用耗时间、耗空间举个例子如果你要往镜像里写一个文件vdfuse 也能写但更安全的做法是 qemu-nbdsudo modprobe nbd max_part8 sudo qemu-nbd -c /dev/nbd0 vm.qcow2 sudo mount /dev/nbd0p1 /mnt/nbd操作完后sudo umount /mnt/nbd sudo qemu-nbd -d /dev/nbd0这种是完整的内核级块设备很多分区工具对它的兼容性比 FUSE 节点更好。但日常只是读文件我会优先 vdfuse因为没必要启用内核模块。5.2 什么场景用 vdfuse 是最优解我现在的判断标准很简单只读救援、快速提取文件、检查镜像内容选 vdfuse需要频繁修改分区表、做系统迁移、对镜像做格式化选 qemu-nbd批量巡检多台虚拟机的磁盘内容选 guestmount因为它不用 root 手动挂载整个链条需要交付一个干净 raw 文件给另一个平台才用 qemu-img convert。vdfuse 的优势是轻量、直接、贴近 VirtualBox 生态缺点也同样明显支持的镜像格式不如 qemu 家族广写操作安全性不如块设备工具直观。理解这些边界就不会在错误场景里硬用。5.3 我踩过几次坑之后的固定操作流程最后分享一套我现在固定使用的操作流程照着做基本不会翻车先确认虚拟机已关机镜像没有在使用vdfuse -f 镜像 -r -a allow_other /mnt/vdils -l /mnt/vdi查看分区节点fdisk -l /mnt/vdi/entiredisk确认分区表单独挂载需要的 partition重复分区加 offset用完先 umount 分区目录再 umount /mnt/vdi最后再做其他处理。我自己最喜欢的细节是先用 -r 挂载因为只读模式会省掉“手滑写坏镜像”这种灾难。数据救援本来就是紧张活能少一个风险就少一个。vdfuse 把镜像读取变得像读普通文件一样简单但边界和风险始终存在工具用得顺不顺往往取决于你对格式和权限背后的原理是否清楚。
阅读完成 · 觉得有帮助?