Truncate empy space from a raw dd image
I have a raw disk image I took using dd
of a Ubuntu instance. The total disk size is 300 GB, but only 5.5 GB used.
Is there a way to resize the raw dd image down to 20 GB, keeping all of the 5.5 GB of data, and just truncating empty blocks?
Solution 1:
Check for sector sizes:
sudo fdisk -l '/home/user/images/test.img'
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00070424
Device Boot Start End Sectors Size Id Type
/home/user/images/test.img1 * 2048 26623 24576 12M e W95 FAT16
/home/user/images/test.img2 26624 7200767 7174144 3,4G 83 Linux
Use end number (7200767) as reference add 1 and * 512 like below:
sudo truncate --size=$[(7200767+1)*512] '/home/user/images/test.img'
Your file should be truncated
Solution 2:
Since it is a raw image, it will always be exactly the same size as the instance you made it from. However, there are a few tricks you can use to achieve the same.
Zeroing
Writing zeroes to the areas with unused space prepares it for compression that effectively reduces the size to less than the used space:
sudo mount -o loop instance.img /testmount
sudo dd if=/dev/zero of=/testmount/zero
sudo rm -f /testmount/zero
sudo umount /testmount
Compression
Simply compressing the image will make it smaller, regardless if you zeroed it first:
gzip instance.img
or, for a more modern approach:
zstd -T0 instance.img
Filesystem-aware imaging
If the image does not have to be raw (i.e. a representation of the block device rather than the content), you also have the option of using filesystem-aware tools to create the image. Zeroing is not needed in this case. For example, ZFS comes with built-in support for this, example with comression:
sudo zfs snapshot myvms/myinstance@myimage
sudo zfs send myvms/myinstance@myimage | zstd -T0 > instance.zfs.zst