How to Shrink a Dynamic VirtualBox Image

Vagrant is great for portable development machines, it's fast to setup a quick environment and can use your vm provider of choice. However, while dynamic, since the images are virtual as opposed to an actual disk, when we fill these and they increase it size, if we then remove files, the image size doesn't shrink back, it stays the same. So you might have a 30GB image file with only 8GB of information.

To shrink these to the size of the actual files contained inside we first we want to zero out the bytes on our guest image

sudo dd if=/dev/zero of=/test.file bs=4096k
sudo rm -rf /test.file

After a couple minutes we get something like

dd: writing to test.file: No space left on device
57643857+0 records in
57643856+0 records out
29513654272 bytes (30 GB) copied, 98.1224 s, 301 MB/s

Exit and shutdown the guest machine vagrant halt is useful here.

I'm using VirtualBox so I'll use vboxmanage with the --compact flag, if we run

vboxmanage modifyhd /path/to/thedisk.vdi --compact

you should be done.

If you have a .vdi image you will be fine but if you're using a .vmdk format you'll get

Progress state: VBOX_E_NOT_SUPPORTED
VBoxManage: error: Compact medium operation for this format is not implemented yet!

Easy enough, we convert to a .vdi and then back to .vmdk (make sure to backup prior). In converting to a .vdi, it will do the shrinking for us so we just need to run

VBoxManage clonehd "source.vmdk" "cloned.vdi" --format vdi
VBoxManage clonehd "cloned.vdi" "resized.vmdk" --format vmdk

For vagrant... after cloning, open VirtualBox, go to Settings > Storage and replace the .vmdk file with the new .vdi one.

After that your VM and filesystem should now be a bit lighter.