Creating bootable Debian image with debootstrap

Kept at it and figured it out, relatively straight forward from here, but not just a matter of setting up /etc/fstab, here is the rest:

not necessary but a good idea to clean things up

apt-get autoclean

set up /etc/fstab - check with mount to ensure you are on the right filesystem type

echo "/dev/sda1 / ext4 defaults,errors=remount-ro 0 1" > /etc/fstab

this will rebuild the initramfs and allow it to boot clean

update-initramfs -u -k all

Do that and the machine boots clean, tested in QEMU and then I am running it right now on hardware.


Automated Debian 9 setup without any systemd errors

This setup does not have any systemd errors or warnings, and I get the Internet connection and a shell at the end.

This setup is just not perfect as I'm not using the Debian kernel, errors when I tried explained in a later section. I then just tried a kernel I had lying around, with config based on Buildroot and it worked. The config is provided in this setup. Therefore, it is possible that some packages that rely on missing kernel configs will fail, although I haven't observed any errors so far.

An analogous setup worked perfectly with the Ubuntu kernel however: https://askubuntu.com/questions/281763/is-there-any-prebuilt-qemu-ubuntu-image32bit-online/1081171#1081171 The Ubuntu kernel must have the missing configs compared to the Debian one. The Debian kernel failures can likely be fixed by compiling the Debian kernel with extra options like CONFIG_VIRTIO_BLK=y as I've done for Ubuntu.

#!/usr/bin/env bash

set -eux

debootstrap_dir=debootstrap
root_filesystem=img.ext2.qcow2

sudo apt-get install \
  debootstrap \
  libguestfs-tools \
  git \
  qemu-system-x86 \
;

if [ ! -d "$debootstrap_dir" ]; then
  # Create debootstrap directory.
  # - linux-image-amd64: downloads the kernel image
  sudo debootstrap \
    --include linux-image-amd64 \
    stretch \
    "$debootstrap_dir" \
    http://deb.debian.org/debian/ \
  ;
  sudo rm -f "$root_filesystem"
fi

if [ ! -f "$root_filesystem" ]; then
  # Set root password.
  echo 'root:root' | sudo chroot "$debootstrap_dir" chpasswd

  # Remount root filesystem as rw.
  # Otherwise, systemd shows:
  #     [FAILED] Failed to start Create Volatile Files and Directories.
  # and then this leads to further failures in the network setup.
  cat << EOF | sudo tee "${debootstrap_dir}/etc/fstab"
/dev/sda / ext4 errors=remount-ro,acl 0 1
EOF

  # Network.
  # We use enp0s3 because the kernel boot prints:
  #     8139cp 0000:00:03.0 enp0s3: renamed from eth0
  # This can also be observed with:
  #     ip link show
  # Without this, systemd shows many network errors, the first of which is:
  #     [FAILED] Failed to start Network Time Synchronization.
  cat << EOF | sudo tee "${debootstrap_dir}/etc/network/interfaces.d/00mytest"
auto lo
iface lo inet loopback
auto enp0s3
iface enp0s3 inet dhcp
EOF

  # Generate image file from debootstrap directory.
  # Leave 1Gb extra empty space in the image.
  sudo virt-make-fs \
    --format qcow2 \
    --size +1G \
    --type ext2 \
    "$debootstrap_dir" \
    "$root_filesystem" \
  ;
  sudo chmod 666 "$root_filesystem"
fi

# linux_image="$(printf "${debootstrap_dir}/boot/vmlinuz-"*)"

linux_img=linux/arch/x86_64/boot/bzImage
if [ ! -f "$linux_img" ]; then
  # Build the Linux kernel.
  git clone --depth 1 --branch v4.18 git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
  cd linux
  wget https://gist.githubusercontent.com/cirosantilli/6e2f4975c1929162a86be09f839874ca/raw/6d151d231a233408a6e1b541bf4a92fd55bf5338/.config
  make olddefconfig
  make -j`nproc`
  cd -
fi

qemu-system-x86_64 \
  -append 'console=ttyS0 root=/dev/sda' \
  -drive "file=${root_filesystem},format=qcow2" \
  -enable-kvm \
  -serial mon:stdio \
  -m 2G \
  -kernel "$linux_img" \
  -device rtl8139,netdev=net0 \
  -netdev user,id=net0 \
;

GitHub upstream.

Now from the terminal, login with root / root, and then check that the Internet works with the following commands:

printf 'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n' | nc example.com 80
apt-get update
apt-get install hello
hello

We used nc as explained at https://stackoverflow.com/questions/32341518/how-to-make-an-http-get-request-manually-with-netcat/52662497#52662497 because:

  • wget and curl are not installed by default
  • ping does not work from QEMU by default: How to ping from the QEMU guest to an external URL?

Tested on an Ubuntu 18.04 host.

What happens if I try to use the Debian kernel

TODO understand and fix. If I replace the Linux kernel compilation above with the Debian packaged Linux kernel:

linux_img="${debootstrap_dir}/boot/vmlinuz-"*

then boot fails with:

Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

and an empty list for:

List of all partitions:

so the disk is not being recognized at all. I've also tried to use the exact same kernel that the Debian ISO installer installs as done here but for Debian, and it fails in the same way, even though the Debian ISO install worked fine with the same QEMU options (it generates GRUB install in a disk with multiple partitions, the root one being ext4).


Can't comment, but your "guide" worked wonders for making a Minimal Ubuntu 16 thumbdrive. The only things I changed were the debootstrap and I had to manually get networking working (networkd).

My debootstrap line was:

#> sudo debootstrap --components=main,contrib,nonfree  --variant=minbase \
                    --include=linux-generic,grub-pc --arch=i386 xenial /mnt