An Ubuntu 26.04 LTS ("Resolute Raccoon") bootable container image with cloud-init and podman built-in, designed for use with bootc and bcvk.
- Ubuntu 26.04 LTS base image with bootc support
- Cloud-init for automatic instance configuration (generator-controlled, does not block boot when no datasource is present)
- Podman for running containers (Quadlet support)
- Snap compatibility (bind mount units for composefs)
- systemd-networkd (DHCP) and systemd-resolved for networking/DNS
- OpenSSH server enabled
- Kernel 6.17 from Ubuntu 25.10 (workaround for Linux 7.0 fsverity regression)
- Standard bootc tooling (ostree, composefs, dracut)
The easiest way to run this image is with bcvk, which handles disk creation, installation, and SSH key injection automatically.
podman build -t ubuntu-bootc:latest -f Containerfile .bcvk libvirt run --composefs-backend --filesystem ext4 --firmware uefi-insecure \
localhost/ubuntu-bootcNote:
--firmware uefi-insecureis required because the kernel 6.17 from Ubuntu 25.10 (questing) is not signed for secure boot. See Known Issues.
bcvk libvirt ssh ubuntu-bootcbcvk injects an SSH key via systemd SMBIOS credentials (tmpfiles.extra), so no password or cloud-init datasource is needed for SSH access.
# List running VMs
bcvk libvirt list
# Stop the VM
bcvk libvirt stop ubuntu-bootc
# Remove the VM and its disk
bcvk libvirt rm ubuntu-bootcYou can also convert an existing Ubuntu 26.04 VM in-place to a bootc-managed system. All commands below should be run as root (sudo -i or prefix with sudo).
apt update && apt install -y podmanpodman pull ghcr.io/jmarrero/ubuntu-bootc:latestROOT_DEV=$(findmnt -no SOURCE /)
tune2fs -O verity "${ROOT_DEV}"
umount /boot/efi 2>/dev/null
umount /bootpodman run --privileged --pid=host --ipc=host --rm \
-v /var/lib/containers:/var/lib/containers \
-v /dev:/dev \
--security-opt label=type:unconfined_t \
-v /:/target \
ghcr.io/jmarrero/ubuntu-bootc:latest \
bootc install to-existing-root \
--acknowledge-destructive \
--skip-fetch-check \
--composefs-backend \
--allow-missing-verity \
--bootloader systemd \
--root-ssh-authorized-keys /target/root/.ssh/authorized_keys \
--karg console=tty0 \
--karg console=ttyS0,115200ESP_PART=$(lsblk -nlo NAME,PARTTYPE /dev/vda | grep -i c12a7328 | grep -o 'vda[0-9]*' | grep -o '[0-9]*')
efibootmgr --create --disk /dev/vda --part "${ESP_PART}" \
--label "Linux Boot Manager" \
--loader "\EFI\systemd\systemd-bootx64.efi"
NEW=$(efibootmgr | grep "Linux Boot Manager" | head -1 | sed 's/Boot\([0-9A-F]*\).*/\1/')
OLD=$(efibootmgr | grep "Ubuntu" | head -1 | sed 's/Boot\([0-9A-F]*\).*/\1/')
efibootmgr --bootorder "${NEW},${OLD}"rebootpodman build -t ubuntu-bootc:latest -f ./Containerfile .just build-containerfilejust generate-bootable-imageThis creates a bootable.img that can be booted directly in QEMU or another hypervisor.
Cloud-init is included but configured to be generator-controlled: the cloud-init-generator runs ds-identify at early boot to detect available datasources. If no datasource is found (e.g. when running locally with bcvk), cloud-init disables itself and boot continues normally without blocking.
This differs from the ubuntu-bootc base image, which force-enables cloud-init.target in default.target.wants and will block boot when no datasource is present.
When a cloud datasource is available (EC2, GCE, OpenStack, NoCloud, etc.), cloud-init runs normally and handles user creation, SSH key injection, and instance configuration.
This image replaces the standard ostree symlinks (/home, /root, /opt, /mnt, /srv) with real directories backed by systemd bind mount units. This is required because snap-confine cannot rbind-mount through symlinks on composefs. A snap.mount unit also bind-mounts /var/lib/snapd/snap onto /snap.
- PAX tar headers (composefs-rs bug): Ubuntu 26.04 is the first release built with Canonical's Rockcraft/umoci tooling, which produces PAX format tars. composefs-rs cannot round-trip these, causing
Layer has incorrect checksumduring install. This image uses a squashed base image that strips PAX headers. (composefs-rs#290) - Linux 7.0 fsverity regression (kernel bug): Ubuntu 26.04 ships kernel 7.0 which has a regression breaking composefs boot with
Failed to execute /sbin/init. This image uses kernel 6.17 from Ubuntu 25.10 (questing) as a workaround. (bootc#2174)
The kernel 6.17 from Ubuntu 25.10 (questing) is not signed for secure boot. When using bcvk, pass --firmware uefi-insecure to disable secure boot. This is only needed until the fsverity regression is fixed in a future Ubuntu kernel.
- EFI boot order:
bootc install to-existing-rootdoes not update EFI variables (runs in a container). You must manually create a systemd-boot EFI entry and update the boot order after install. - arm64: Disabled in CI pending bootc#1703 and composefs-rs#210
This project was co-authored with OpenCode (Claude Opus 4.6), which assisted with Containerfile development, upstream bug investigation, PAX tar header analysis, kernel regression diagnosis, and documentation.
Apache License, Version 2.0