live iso generation
TunaOS generates bootable Live ISOs from its bootc container images using tacklebox, a Go-based ISO and disk image builder.
Overviewβ
The generation process:
- Container image β a TunaOS image is built (or pulled from GHCR)
- tacklebox β converts the OCI image into a bootable ISO with
mksquashfs - Output β a hybrid ISO bootable via UEFI, suitable for
ddto USB or VM boot
OCI Image (ghcr.io/tuna-os/yellowfin:gnome)
β
βΌ
tacklebox build --iso
β
βΌ
yellowfin-gnome.iso
Prerequisitesβ
podman(rootful required for loopback device access)justcommand runnerlima(optional, for verification)rclone(optional, for R2 upload)
tacklebox is automatically downloaded if not installed (ghcr.io/tuna-os/tacklebox:latest).
Building a Live ISOβ
# Build from local image
just iso yellowfin gnome
# Build from GHCR (no local build needed)
just iso yellowfin gnome repo=ghcr
# Build with a specific tag
just iso yellowfin gnome repo=ghcr tag=gnome-hwe
This runs scripts/build-iso-tacklebox.sh which:
- Builds or pulls the container image
- Downloads tacklebox if not present
- Invokes
tacklebox build --isowith the image reference - Outputs the ISO to
.build/live-iso/<variant>-<flavor>/
Demo and Testingβ
Boot ISO in browser via QEMUβ
just demo-iso skipjack gnome
This builds the ISO, starts a QEMU VM, and opens a noVNC browser window.
Boot ISO in Lima VMβ
just _lima-novnc myvm iso path/to/image.iso
Verify ISO bootsβ
just verify-iso path/to/image.iso
ISO Contentsβ
A TunaOS live ISO contains:
- bootc container rootfs β the full TunaOS image as a squashfs filesystem
- Kernel + initramfs β dracut-generated with live boot modules
- systemd-boot (sd-boot) β UEFI bootloader
- Live environment β boots directly to the desktop (gdm/sddm login screen)
Troubleshootingβ
"tacklebox: command not found"β
tacklebox is auto-downloaded. If the download fails, build from source:
export TACKLEBOX_FROM_SOURCE=1
just iso yellowfin gnome
"No more mirrors to try" during package installβ
This typically happens in unstable network environments. Solutions:
- Use GHCR images:
just iso yellowfin gnome repo=ghcr(skips local package install) - Retry: The build scripts use
dnf_retrywith exponential backoff (4 attempts) - Run in CI: GitHub Actions runners have reliable network access
SELinux denialsβ
Builds require --security-opt label=disable on SELinux-enabled hosts. This is applied automatically by the Justfile. If you encounter AVC denials, ensure you're running via just rather than raw podman build.
Disk spaceβ
- ISO builds require ~20 GB free space
- The
.build/directory caches intermediate artifacts - Clean up with
just clean(preserves RPM cache) orjust clean-cache(removes all)
"image not known" after loadβ
The build pipeline prunes unused images (podman system prune -af) to work around a BTRFS storage index bug. If you encounter this:
- Ensure you're on BTRFS or overlay storage drivers
- Run
podman system resetand rebuild
Publishing to Cloudflare R2β
ISOs are published bi-weekly via publish-isos.yml. Manual upload:
export UPLOAD_R2=true
just iso yellowfin gnome repo=ghcr
Requires rclone configured with R2 credentials.
Architecture Notesβ
- tacklebox replaced the previous
bootc-image-builder(osbuild) pipeline - Old pipeline:
Containerfileβimage-builder-cliβosbuildβ ISO - New pipeline:
Containerfileβtackleboxβ ISO - tacklebox is faster (~10 min vs ~30 min) and simpler (no osbuild dependency)
- Multi-env ISOs (multiple desktop environments on one media) are supported by tacklebox but not yet used by TunaOS