Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

module-ubuntu — wrapping prebuilt Ubuntu packages

module-ubuntu wraps prebuilt Ubuntu .deb files as yoe units, mirroring the role module-debian plays for Debian and module-alpine plays for Alpine. A unit fetches a binary .deb from a pinned Ubuntu release, verifies its SHA256 against the upstream-signed Packages catalog, and republishes it through yoe’s project repo. The unit’s “build” is just extracting the deb’s data.tar into $DESTDIR.

The module lives at https://github.com/yoebuild/module-ubuntu. Open it to browse the bootstrap keyring, the in-tree Packages snapshots, or to send a PR adding a new feed/component.

Ubuntu shares Debian’s apt/dpkg/glibc machinery, so this module is thin: it declares feeds with the same apt_feed() builtin module-debian uses, ships an Ubuntu/glibc build toolchain, and rides the shared mmdebstrap rootfs assembly, .deb packaging, and on-device apt that yoe applies to the whole apt family. Read module-debian for the apt-family mechanics that aren’t repeated here; this page covers what is Ubuntu-specific.

When to reach for it

The same “yoe builds the small stuff, the distro module ships the hard-to-build complexity” rubric from module-debian applies. The only axis that picks Ubuntu over Debian is the target: choose module-ubuntu when an image must match Ubuntu’s userland, ABI, or vendor BSP expectations. Source units in module-core compile against either glibc toolchain through the container = "toolchain" virtual reference, so most of a closure is shared regardless of which apt distro the image targets.

Ubuntu is its own distro

apt_feed(distro = "ubuntu", ...) tags every materialized unit with Distro = "ubuntu", and the images set distro = "ubuntu". That makes Ubuntu a first-class distro in yoe’s resolver — an Ubuntu image’s closure sees only Ubuntu-tagged units, so a single project can declare both module-debian and module-ubuntu and the two never collide. Under the hood Ubuntu rides the shared apt/dpkg/glibc backend; only the feed identity, suite, and mirror differ.

Ubuntu release coupling

The suite pinned in MODULE.star (_UBUNTU_SUITE, tracking Resolute Raccoon / 26.04 LTS at the time of writing) must match the FROM ubuntu:<release> line in containers/toolchain-ubuntu-26.04/Dockerfile. The same three couplings Debian documents apply: the glibc ABI between toolchain headers and target runtime libs, the per-release archive signing key in keys/ubuntu-archive-keyring.gpg, and the full cache invalidation that a suite bump rolls through every source-unit hash. Plan a suite bump for a rebuild cycle.

The Ubuntu and Debian glibc toolchains are not interchangeable. apt is not forward-compatible across suites, so Debian-trixie’s apt crashes when it reads Ubuntu-resolute’s repository metadata — an Ubuntu rootfs must be assembled by the Ubuntu toolchain, and vice versa. Because the container image tag is yoe/<unit-name>:<version>-<arch>, each toolchain carries its release in its name (toolchain-ubuntu-26.04, Debian’s toolchain-debian-13) so the two never share a tag and overwrite each other’s image.

Split mirrors (amd64 + arm64)

Ubuntu serves its architectures from two hosts: amd64/i386 live on http://archive.ubuntu.com/ubuntu, while arm64 and the other ports arches live on http://ports.ubuntu.com/ubuntu-ports. A single apt_feed spans both via the optional arch_urls map, which overrides the base url per architecture — used both when yoe update-feeds fetches each arch’s Packages and when the build downloads each .deb. The InRelease is fetched once from url for signature verification; both mirrors ship an InRelease signed by the same Ubuntu archive key. Debian’s single mirror serves every arch and needs no such override.

Networking

Ubuntu images use NetworkManager as the connection manager, the same choice the Debian images make. It self-enables via its postinst, integrates with the systemd-resolved already in the image for DNS, and is the foundation for adding wifi and cellular to a device image later.

Ubuntu needs one extra piece Debian does not. Ubuntu’s network-manager package ships /usr/lib/NetworkManager/conf.d/10-globally-managed-devices.conf, which restricts NetworkManager to wifi and cellular and delegates wired ethernet to netplan. yoe images carry no netplan configuration, so out of the box the wired NIC is brought up by nothing — NetworkManager sees the device and then ignores it (nmcli device status shows it unmanaged). To restore the zero-config wired-DHCP behavior Debian has by default, the Ubuntu images include the nm-manage-ethernet unit. It lays down a higher-priority drop-in at /etc/NetworkManager/conf.d/15-yoe-manage-ethernet.conf that re-includes ethernet in NetworkManager’s managed set, so the wired NIC auto-DHCPs with no connection profile.

If a custom Ubuntu image lists network-manager but has no connectivity, confirm nm-manage-ethernet is also in its closure. On the device console, nmcli device status should show the ethernet device connected (not unmanaged), and ip addr should show a DHCP lease.

Verifying an Ubuntu image

End-to-end verification mirrors the Debian flow in module-debian — build the ubuntu-base-image (or ubuntu-dev-image) fixture under testdata/e2e-project/, boot it under QEMU, and confirm SSH lands over the forwarded port. The image is reachable on first boot with no connection profile because nm-manage-ethernet brings the wired NIC up automatically.

Layout

MODULE.star                # apt_feed(distro="ubuntu", ...) declaration
feeds/main/<arch>/Packages # checked-in catalog snapshots (archive + ports)
keys/                      # bootstrap keyring + fingerprint allow-list
containers/toolchain-ubuntu-26.04  # Ubuntu/glibc build toolchain (provides "toolchain")
classes/kernel.star        # ubuntu_kernel() -> linux-image-generic
images/                    # base-image, ssh-image, dev-image