如何挂载压缩的磁盘映像?

如果我制作了一个磁盘镜像并使用gzip/xz等进行压缩,是否有办法直接挂载它而不需要先解压缩呢?
比如说我已经使用了
sudo dd if=/dev/sdc1 | gzip -9 > image1.dd.gz

如何在不先创建未压缩副本的情况下挂载原始图像?
或者我已经使用过。
sudo dd if=/dev/sdc | gzip -9 > wholedisk.dd.gz

如果磁盘有多个分区,那会不会更难一些?
使用整个磁盘的未压缩镜像,然后使用kpartx或更新版本的losetup与其-P标志一起,可以为每个分区创建一个循环。
但是有没有办法挂载/losetup/读取压缩的镜像呢?
如果对于gzip/xz无法工作,是否有任何压缩方法可以使用?

关于重复问题的说明

目前建议的重复问题是:

不使用压缩,并且不是一个重复问题

mount命令本身无法挂载压缩的映像。


我能告诉你,这绝对是可能的。但是我现在无法告诉你具体方法,因为相关说明在两个外部硬盘上,而我目前无法访问它们。不过我想让你知道这是可行的。一旦我有答案(并且没有其他人在那之前给出答案),我会回来告诉你。 - UTF-8
3可能是从整个磁盘映像中挂载单个分区(设备)的重复问题。 - Panther
1@UTF-8 这真是令人鼓舞,谢谢。顺便说一下,最初的目标是制作一个较小的备份,用于存储几乎为空或有大量易于压缩的数据的驱动器/分区,并且能够在不写入大量额外数据或需要大量可用空间来提取的情况下进行读取。 - Xen2050
请参阅https://major.io/2010/12/14/mounting-a-raw-partition-file-made-with-dd-or-dd_rescue-in-linux/。 - Panther
@bodhi.zazen 谢谢,但这些方法并没有解决压缩的问题。据我所知,mount和losetup/kpartx不能自动解压图像文件。 - Xen2050
那么你已经回答了自己的问题 ;) - Panther
2@bodhi.zazen 不好意思?也许我应该澄清一下,mount命令不会自动解压图像,所以这个问题并不是https://askubuntu.com/questions/69363的重复(也许我错过了笑话,希望解压不是唯一的答案 :) - Xen2050
你已经回答了自己的问题。"Mount不会挂载压缩的镜像"这部分是正确的,如果你使用squashfs,mount可以挂载压缩的镜像。所以你必须先解压它,QED。我链接的问题告诉你如何挂载镜像中的分区。 - Panther
@Xen2050 不要对我很快就能告诉你解决方案抱有太大希望。我能去那些外部硬盘的最早时间是大约一周后。目前我正在自己提取三个压缩图像,因为我需要其中存储的东西,不想等到那时候。 - UTF-8
没关系,我可以等。也许还有其他人隐藏着的创造性解决方案,只是在等待这样的问题来回答。谢谢bodhi.zazen,我也找到了squashfs方法(通过谷歌搜索,在AskUbuntu这里的搜索不包括其他SE网站),看起来也是一个很好的答案,任何在这里给出“只是事实”指示的人至少会得到我的点赞,如果一段时间后没有其他超级答案的话,可能还会得到一个勾选标记。 - Xen2050
抱歉,我可能弄错了。我在我的外部硬盘上找不到任何可以做到那个的脚本。 - UTF-8
在Unix&Linux上有一个答案nbdkit及其xz插件可以使用xz压缩来实现,但是我一直无法让它正常工作(安装/编译插件?)。如果有一个回答展示了如何使其正常工作的简单步骤,尤其是如果还能与gzip一起使用,我会点赞并选择为正确答案。 - Xen2050
请参考:https://unix.stackexchange.com/questions/31669/is-it-possible-to-mount-a-gzip-compressed-dd-image-on-the-fly - sdaau
如果你要压缩整个磁盘镜像,选择-9似乎不太明智,因为它会不必要地减慢压缩速度。-3可能是一个比较理想的选择,它能够实现几乎相同的压缩效果,但速度会快得多。 - thomasrutter
2个回答

你可以使用squashfs来压缩磁盘镜像,然后挂载它们。
创建磁盘镜像
如果你还没有磁盘镜像,可以使用dd命令来创建一个:
dd if=/dev/sda1 of=/tmp/sda1.img bs=4M

使用Squashfs压缩图像

安装squashfs

apt-get install squashfs-tools

压缩图片:
mksquashfs /tmp/sda1.img /tmp/sda1.squash.img

或者流式传输压缩(不需要临时的dd文件)
mkdir empty-dir
mksquashfs empty-dir squash.img -p 'sda_backup.img f 444 root root dd if=/dev/sda bs=4M'

terminator14 at UbuntuForums.org致以赞美。定义/解释:
  • empty-dir - "source"目录。在我们的情况下,只是一个空目录,以满足mksquashfs的输入参数格式。
  • squash.img - 输出squashfs文件的目标和文件名。
  • sda_backup.img - squashfs文件中dd备份的名称。
  • f - 指定sda_backup.img是一个普通文件(而不是目录、块设备或字符设备)。
  • 444 - squashfs镜像中sda_backup.img文件的权限。
  • root root - squashfs镜像中sda_backup.img文件的UID和GID。可以用十进制数或名称指定。
  • dd if=/dev/sda bs=4M - 用于读取要备份的设备的dd命令。

挂载镜像

首先挂载squashfs镜像:

mkdir /mnt/squash
mount /tmp/sda1.squash.img /mnt/squash

这将为您提供未压缩的磁盘映像,以便您挂载。
mkdir /mnt/sda1
mount /mnt/squash/sda1.img /mnt/sda1

或者,如果它是一个完整的驱动器镜像(分区),您可以使用losetup将dd镜像附加到循环设备(可能是可选的),然后使用kpartx -apartprobe来查找和分离分区到单独的设备,甚至使用vgscan / vgchange -ay如果有LVM。

2我添加了一些即时的squashfs信息,以避免需要一个临时的纯dd文件。使用squashfs是个好答案,只是不支持更友好的管道方式的xz/gz格式。 - Xen2050
这个方法对于包含多个分区的完整磁盘镜像也能行得通吗? - friederbluemle
点击此处查看完整磁盘:https://unix.stackexchange.com/questions/31669/is-it-possible-to-mount-a-gzip-compressed-dd-image-on-the-fly - HackerBoss
根据文件系统的类型,挂载可能需要使用ro,noload选项,就像这样:mount -o ro,noload /mnt/squash/sda1.img /mnt/sda1 - HackerBoss

我成功地让一个NBD服务器“提供”了一个未压缩的.gz或.xz文件版本。我不确定它是否经常需要读取整个压缩文件(目前只在RAM中测试过小文件),但至少它可以工作,而无需提取整个未压缩副本。

实时查看gz / xz压缩的dd镜像

  1. 安装 nbdkit 和客户端

    apt install nbdkit nbd-client
    
  2. 创建演示 "dd" 样式文件 - 一个空的50M文件,带有 ext 文件系统并压缩它 (仅用于测试)

    fallocate -l 50M 50m
    mkfs.ext3 -v 50m
    

    然后使用 gzip 或 xz 进行压缩

    gzip -vk9 50m
    xz -v9k 50m
    

    注意: xz 选项 --block-size=16MiB 可以提供更好的随机访问性能,但代价是更少的压缩 (可能只有1%?)。请参阅 nbdkit's xz plugin description

  3. 在压缩的镜像上运行服务器

    nbdkit -v --no-fork -i 127.0.0.1 /usr/lib/i386-linux-gnu/nbdkit/plugins/nbdkit-gzip-plugin.so file=~/Downloads/50m.gz
    

    或者对于 xz

    nbdkit -v --no-fork -i 127.0.0.1 /usr/lib/i386-linux-gnu/nbdkit/plugins/nbdkit-xz-plugin.so file=~/Downloads/50m.xz
    

    --no-fork 告诉服务器 "不要分叉到后台",因此在可能出现错误消息并使用 CTRL-C 终止它时会更容易一些。

    -v 可能 / 将显示太多状态消息,特别是在读取时。

  4. 运行客户端 (在另一个终端/窗口中)

    sudo nbd-client -nofork 127.0.0.1 10809 /dev/nbd0
    

    -nofork 类似于上面的 -no-fork,但我无法使用 CTRL-C、kill <pid>sudo kill <pid> 来杀死客户端。使用 CTRL-C 结束服务器会停止服务器和客户端。

  5. 观察到 /dev/nbd0 现在与未压缩的镜像相同

    $ sudo diff -s /dev/nbd0 ~/Downloads/50m
    Files /dev/nbd0 and /home/user/Downloads/50m are identical
    

    /dev/nbd0 现在可以像未压缩的镜像一样使用;挂载、使用 dd 进行读取/复制,或使用 kpartxpartprobevgscan / vgchange 等!

感谢 Cristian Ciupitu on Unix & Linux,虽然需要进行一些深入挖掘才找到插件并使一切顺利运行。

在Fedora 31上,使用相同的客户端命令nbdkit -v --no-fork -i 127.0.0.1 --filter=xz file ~/Downloads/50m.xz非常顺利。 - EkriirkE
在Ubuntu xenial 16.04 LTS上,nbdkit 1.1.11使用旧的NBD协议,与nbd-client 3.13中使用的新NBD协议不同,但您可以使用3.10之前的nbd-client版本,例如来自Ubuntu precise 12.04 old LTS的nbd-client 3.8 [仅在本地使用旧版本以确保安全!]。 - user1742529
只需在/usr/lib/.../nbdkit-xz-plugin.so的位置上简单地指定xz,就可以很好地让它自动选择x86_64-linux-gnui386-linux-gnu - ManSamVampire
截至Ubuntu 20.04(nbdkit v1.16.2),nbdkit-xz-plugin.so文件丢失。因此,可能应该使用 --filter=xz,如 @EkriirkE 指定的那样。而我只是下载了 Debian Buster 的 nbdkit deb 包,从中提取了插件并使用它,这也起作用了。 - ManSamVampire