10

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?

Justin
  • 571

3 Answers3

9

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

4

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
0

If the disk is GPT partitioned, the truncate option given by @Wessel will cause the petition table entries to go bad, and the file can't be used to mount as a loop device. I follow this method

  1. Mount the disk image first as a loop device
sudo -i
udisksctl loop-setup -f disk.img
#notedown where its mounted
gparted /dev/loopxx
  1. In the gparted UI add a new partition of 1MB size at the end, apply changes
  2. Unmount the file udisksctl loop-delete -b /dev/loopxx
  3. dump the partition table to a file sfdisk -d disk.img > partitions.txt
  4. Find the last sector used parted disk.img 'unit s print'
  5. Find the byte offset = (last sector used + 1) * 512
  6. truncate the file truncate -s offset disk.img
  7. Update partitions.txt to reflect new state
Remove the last-lba line from the since it no longer valid
Remove last 1MB partition since we don't need it anymore
  1. Restore the partition table sfdisk disk.img < partitions.txt
Adarsha
  • 145