Installing (Linux) operating systems is a time consuming and, even worse, repetitive task. The whole “burning to disk” era is definitely over and bootable USB sticks are useful in some cases (eg. installing a new workstation) but let’s be honest, most of the time one installs an OS to be used in some kind of VM or container. For this use case live systems with crude installer software are just not the right tool. PXE based setups with preseed or kickstart are, in my humble opinion the even more wrong since they try to automatically operate an installer which is meant for human interaction.

There are some more modern approaches like cloud-init which are way better to handle but they still expect some kind of machine to boot and then do the installation steps.

What defines a OS installation?

When someone wants to install an operating system they basically want to define the following things:

  1. Where? What kind of storage/filesystem is used?
  2. What? Which kernel, distribution and arbitrary software should be installed?
  3. How? How should it boot and how can I reach it afterwards?

For virtual machines the whole setup can be pre-defined and there is no need for interactive options or guided installers. I just want to define the result, generate it and be able to start it right away. Doing all of that manually is properly annoying, so I wrote a lot of Ansible code to automatically generate container filesystems or full VMs.

mkosi is what I was missing!

A while ago I stumbled upon mkosi, a tool from the systemd suite which solves exactly that expectation. It can generate OS filesystem trees of many different distributions by using there native bootstrapping tools (eg. debootstrap) and can additionally package the result in an image file with a filesystem and bootloader. You can use mkosi as a single command or feed it configuration files. So it does solve the whole “Where?” and “What?” questions and even the “How?” by being able to set passwords, hostname and SSH keys inside the resulting OS to ensure a user can login after boot.

That’s exactly how I want to install a operating system in 2022! No matter if I’m generating a container for testing or if I want to install a Linux on a physical machine from a arbitrary live system.

Usage

The usage is quite straight forward. Although there aren’t many howtos and examples available yet. Of course the manpage is worth a look but also the Archlinux Wiki and Lennarts blogpost have some really interesting informations.

Creating a Debian container (systemd-nspawn)

First a simple task, we create a filesystem tree containing a bootable Debian and run it as a container

# create a directory with a debian system
mkosi --format directory --distribution debian --release buster --output test-container --cache /tmp/cache --hostname reality-check.example.com --password foobar

# boot it as container with systemd-nspawn
systemd-nspawn --boot --directory test-container
Creating a Archlinux VM from config file (qemu)

Now we create a full featured image which can be run as a QEMU instance. Since we cannot simply create a shell inside such a VM, we have to establish a SSH connection. mkosi does all of that for us.

# create a image with GPT and BTRFS and install ssh
[Distribution]
Distribution=arch

[Output]
Format=gpt_btrfs
Bootable=yes
Output=test-image.img

[Packages]
Packages=openssh

[Validation]
Password=foobar

[Host]
Ssh=yes
Netdev=yes
# build the image from the default config file but use hosts package repos and cache
# hint: parameters must come before command, otherwise they're ignored
mkosi --cache /var/cache/pacman/pkg/ --use-host-repositories build

# run the generated image with QEMU
mkosi qemu &

# connect to it via SSH
# hint: the created network interface on the host is automatically configured by systemd-networkd
# hint: the password is also used as password for the SSH key
mkosi ssh

I’ve never felt so satisfied after an OS installation ever before

Installing Fedora in a squashfs (qemu)

Now inside the new VM we just overwrite the whole image :-P

# install dependencies
pacman -Sy mkosi dnf squashfs-tools

# create a new OS image with another password and a Fedora system
mkosi --cache /tmp -d fedora --password test -o image.raw --force --format gpt_squashfs

# move it to the 
# ATTENTION: make sure you run this inside the right shell!
dd if=image.raw of=/dev/sda; sync
poweroff

Afterwards when the VM stopped we can start the image again and voilà a Fedora is booting:

mkosi boot

I feel kinda prepared for any upcoming install parties. Remember the multiboot USB sticks with different OSs on it? Those were times.

Looking forward

Knowing about mkosi will probably change the way how I’ll setup machines in future. It looks like the tool is still in updraft and I expect a whole lot of new supported systems and features. For example nixOS is not yet supported but might fit perfectly.
Another interesting area might be the creation of images for embedded devices like my favorite APU boards or might one even squint in direction of postmarketOS?!