Create a bootable image from a single ext4 partition

Beware! This will create a bootable partition image as if it were a whole disk. It works (at least for me) but one cannot extend or create new partitions alongside this one, because there is no partition table!
To make full use of my virtual hard drive I had to fix this, and it took much longer. Here's the followup.

Situation

A 1TB hard drive with several partitons, lots of media. The actual root system is on a 10GB partition. Additionally, only 5GB are actually in use.

I want to make a bootable image that I can upload to my virtual server (it has a function to install from a raw image).

The example partition is /dev/sdb5

Create a sparse image of the partition:

  • mount the partition, cd into it.
  • zero-fill the free space: dd if=/dev/zero of=zero_file bs=32M
  • sync
  • rm zero_file
  • unmount
  • create sparse image: dd_rescue -a -b 8M /dev/sdb5 sdb5.raw

Don't be confused, the file still shows up as 10GB. Check with du -h sdb5.raw

Making it bootable (GRUB)

instead.

If you upload the file to a remote server with sftp (e.g. FileZilla) remember to enable compression.

Mount the file: mkdir sdb5; mount sdb5.raw sdb5

We will need to chroot into it, therefore:

cd sdb5
mount --bind /sys sys
mount --bind /proc proc
mount --bind /dev dev
mount --bind /dev/pts dev/pts

From now on

chroot .

You might be getting command not found errors; check $PATH, if necessary add all common locations, e.g.: PATH="/sbin:/usr/sbin:/bin:/usr/bin:$PATH"

The tricky part

Issue fdisk -l - this should show you - even in chroot - that your image is mounted on /dev/loopX.
Assuming it's /dev/loop0, we need to tell grub about it:
echo '(hd0) /dev/loop0' > /boot/grub/device.map

Now it should be possible to issue

grub-install --force /dev/loop0

With a few warnings but no errors.

Unmount

Exit the chroot, unmount:

exit
umount sys proc dev/pts
umount dev
cd ..
umount sdb5

The image should be bootable now, and ready for upload.