Worked examples — the component supply chain¶
Three self-contained, buildable UMF recipes that compose into a bootable image, each an ordinary container build that publishes an OCI artifact:
| Directory | Output | org.imagilux.umf.type |
|---|---|---|
kernel-build-env/ |
gcc + kernel build deps | kernel-build-env |
kernel/ |
vmlinuz + modules from torvalds/linux |
kernel |
rootfs/ |
a neutral FHS 3.0 root filesystem | rootfs |
There is no special "kernel mode" or "rootfs mode": umf build infers the
container shape purely from what FROM resolves to (a base image or scratch,
not a kernel), and the org.imagilux.umf.type label is the only thing that
distinguishes the outputs. Each is a normal OCI image, resolved through the same
registry → cache → source chain as everything else.
Build and publish¶
The chain is ordered — the kernel FROMs the build-env:
# 1. Toolchain (foundation for the kernel build)
umf build --tag registry.bitswalk.net/examples/kernel-build-env:1.0 --push docs/examples/kernel-build-env
# 2. Kernel — FROMs the build-env, clones + compiles Linux
umf build --tag registry.bitswalk.net/examples/linux:7.0 --push docs/examples/kernel
# 3. Neutral rootfs (independent of the other two)
umf build --tag registry.bitswalk.net/examples/rootfs-fhs:1.0 --push docs/examples/rootfs
Composing them into a bootable image¶
A downstream bootable build references the kernel via FROM and the rootfs via
a bare ADD <oci-ref> /. FROM resolving to a type=kernel artifact is what
marks the build bootable; boot packaging is chosen with a stock
LABEL org.imagilux.umf.flavor (systemd-boot or uki):
FROM registry.bitswalk.net/examples/linux:7.0
ADD registry.bitswalk.net/examples/rootfs-fhs:1.0 /
LABEL org.imagilux.umf.flavor=systemd-boot
ENTRYPOINT systemd
umf build emits a plain type=bootable OCI image; umf compile / umf run
projects it to a disk and boots it (QEMU/Cloud Hypervisor or bare metal).
Reproducing the bootable flow locally¶
The registry.bitswalk.net/examples/* tags above are illustrative: they show
the canonical publish-and-compose shape, but they are not guaranteed pullable
from a public registry, and the kernel/ recipe needs a multi-hour upstream
compile. For a reproducible, minimal end-to-end bootable run that needs neither,
the repository ships a fixture builder:
scripts/make-boot-fixture.sh /tmp/umf-boot-fixture # Alpine linux-virt kernel + static-busybox rootfs
It writes a kernel/ + rootfs/ pair (a real vmlinuz plus modules and a
busybox /sbin/init). The boot-smoke test (tests/boot_smoke.rs) seeds that pair as OCI artifacts, runs umf build into a
type=bootable image, umf compiles it to a UKI disk, and boots it under
QEMU/KVM to a userspace marker:
This is the minimal, reproducible demo set; the kernel-build-env → kernel →
rootfs chain above is the production-shaped equivalent (real toolchain, real
compile).
FROM scratch vs. a base image¶
The recipes here build on real base images (debian:bookworm-slim,
busybox:1.36-musl) because each wants what the base ships (a toolchain, or
busybox binaries). FROM scratch is equally supported: a producer build can
start from nothing and pull its userland with a bare ADD <oci-ref> /. Reach
for a base image when you want its contents; reach for scratch when you are
assembling the filesystem yourself.
Network during RUN¶
The kernel-build-env and kernel recipes fetch over the network during RUN
(apt-get, git clone), the conventional shape and the same one the
apt-based recipes in ../examples.md use. umf build runs
each RUN step in an isolated network namespace with compartmentalized NAT'd
egress (a veth pair plus a host nft masquerade rule, programmed in-process by
umf-networking), so those fetches work on a build that has the privileges
egress needs (CAP_NET_ADMIN, the rootful path CI's NAT-egress lane exercises).
Where that egress is unavailable (no host forwarding, or insufficient
privileges), pre-vendor the toolchain and kernel source into the build context
and ADD them instead of fetching.
Validation status¶
- All three pass
umf parse(lexing + grammar + structural validation). rootfs/builds end-to-end with noRUNnetwork access, so it is the quickest to reproduce.kernel-build-env/andkernel/build on a host that providesRUNegress (see above).kernel/additionally needs an existing upstream tag (thev7.0placeholder isn't on torvalds/linux yet, so substitute e.g.v6.12/ release6.12.0) and a multi-hour compile.