linux · February 10, 2021·

MKOSI (Make Operating System Image)

Definition

MKOSI is a tool designed to create bootable operating system trees or images. It is tailored for developers who need to build, test, and debug operating system images. Additionally, it supports generating production images with cryptographic protection. A typical use case involves adding a mkosi.default file to an existing project (e.g., written in C or Python) to facilitate creating an operating system image.

MKOSI compiles your code with the necessary development headers and tools to generate a new image. This image contains only your application and a minimal set of required packages. The resulting image can be deployed to any device using tools like casync.

MKOSI is designed to be legacy-free, which means:

  • It creates GPT partition tables instead of MBR/DOS tables.
  • Bootable images are designed for EFI systems, not BIOS.
  • The /etc/fstab file is left empty, allowing tools like systemd-nspawn to handle automatic partitioning and booting.

Image Types

Using MKOSI, the following types of images can be created:

  1. Raw GPT disk image with ext4 as root.
  2. Raw GPT disk image with btrfs as root.
  3. Raw GPT disk image with a read-only squashfs as root.
  4. A plain directory on disk containing the OS tree directly (useful for container images).
  5. A btrfs subvolume on disk, similar to the plain directory.
  6. A tarball of a plain directory.

Additional Features

For GPT-based images, the following features can be configured:

  1. Add a swap partition.
  2. Make the system bootable on EFI systems.
  3. Add separate partitions for /home and /srv.
  4. Encrypt partitions like root, /home, and /srv using LUKS.
  5. Protect the root partition with dm-verity to prevent offline attacks.
  6. If the image is bootable, the dm-verity root hash is automatically added to the kernel command line. The kernel, initial RAM disk, and kernel command line can also be cryptographically signed for UEFI Secure Boot.

MKOSI is distribution-agnostic and can create images based on various Linux distributions.


How It Works

To run MKOSI with minimal configuration, use:

$ sudo mkosi

This command creates a image.raw GPT disk image in the current directory. Note that the default distribution matches the host machine's operating system.

For more advanced control over image features, specify options via the command line. Testing different configurations in separate directories is recommended.

MKOSI File/Directory Structure

  1. mkosi.default: The main configuration file. Specify image type, distribution, packages, etc.

  2. mkosi.extra: If this directory exists, its contents are copied into the image. Useful for adding static files or overriding distribution defaults.

  3. mkosi.build: A script file executed during the build process. Two images are created:

    • A "build" image with compilation tools and headers.
    • A final image based on the build output.

    The script is executed in the build image, and the build image is discarded afterward.

  4. mkosi.postinst: A script executed within the image (via systemd-nspawn) at the final stages of image preparation. If mkosi.build is used, this script runs twice: once in the build image and once in the final image.

  5. mkosi.nspawn: A configuration file for systemd-nspawn, included with the final image and its checksum.

  6. mkosi.cache/: A directory used as a package cache for builds, speeding up subsequent runs.

  7. mkosi.passphrase: Contains the passphrase for LUKS encryption. Ensure this file is not readable by other users.

  8. mkosi.secure-boot.crt and mkosi.secure-boot.key: X.509 key pair used for signing the kernel and initrd for UEFI Secure Boot.


Usage Examples

Creating a Simple Image

Run the following command to generate a raw GPT disk image:

$ sudo mkosi

This creates an image.raw file in the current directory.

To boot the image:

$ sudo systemd-nspawn -bi image.raw

Creating a Btrfs Image

Generate a bootable GPT+Btrfs image named foobar.raw:

$ sudo mkosi -t raw_btrfs --bootable -o foobar.raw
$ sudo systemd-nspawn -bi foobar.raw

Running the Image in QEMU

Run the foobar.raw image in a QEMU virtual machine:

$ qemu-kvm -m 512 -smp 2 -bios /usr/share/edk2/ovmf/OVMF_CODE.fd -drive format=raw,file=foobar.raw

Creating a Plain Directory Image

Generate and run a plain directory image:

$ mkosi -d fedora -t directory -o quux
$ sudo systemd-nspawn -bD quux

Overwriting Existing Images

By default, MKOSI refuses to overwrite existing images. Use --force or -f to replace an existing image:

$ sudo mkosi --force

Installing Additional Packages

Specify repositories and packages during the build process:

--repositories=<url> --package <package_name>

Example Command

Generate a Debian image with specific options:

$ sudo mkosi -d debian --bootable -o ugur_mkosi --checksum --hostname ugur_mkosi \
  --password 1234 --package vim -t raw_gpt --verity

Using MKOSI with Python

Installation

$ python3 -m pip install --user git+https://github.com/systemd/mkosi.git
$ git clone https://github.com/systemd/mkosi/
$ cd mkosi
$ python3 -m pip install --user --no-use-pep517 --editable .

Running MKOSI with Python

$ python3 -m mkosi -i
$ sudo systemd-nspawn -b -i image.raw

Running QEMU

Run the image in QEMU:

$ qemu-system-x86_64 -m 512 -smp 2 -bios /usr/share/ovmf/OVMF.fd -drive format=raw,file=image.raw

For faster performance, use KVM:

$ kvm -m 8192 -smp 8 -bios /usr/share/ovmf/OVMF.fd -drive format=raw,file=image.raw