~bigbes/sourcehut-root

sourcehut-root/skills/sourcehut-ci/references/images.md -rw-r--r-- 10.4 KiB
72581ff9 — Eugene Blikh docs(sourcehut-ci): fix factual errors found in full audit 3 days ago

#Choosing an image:

Pick the smallest, fastest image that has the packages you need. This page is a quick selector.

#Default recommendation

alpine/edge unless you have a specific reason otherwise. Boot is fast (~5 seconds), apk install is fast, packages are recent. Most projects work on Alpine.

alpine/latest is also fine if you want the latest stable rather than edge (rolling).

#When to switch off Alpine

  • glibc-required binaries (you have a pre-built binary that depends on glibc). Alpine uses musl. Switch to debian/stable or ubuntu/lts.
  • Distro-specific packaging — building a .debdebian/stable; building a .rpmfedora/latest; AUR things → archlinux.
  • The package you need is in this distro and not Alpine — happens occasionally. Search the relevant distro's package index.
  • Reproducing a customer's environment — match their distro.

#Self-hosted instances (*.srht.bigb.es and similar)

Upstream builds.sr.ht.org ships a large pre-built image catalog. A self-hosted instance ships only:

  1. Recipes — shell scripts under /var/lib/images/<distro>/<version>/ installed by the builds.sr.ht-images Alpine package. These describe how to build a qcow2 but are not themselves bootable.
  2. Whatever the operator has actually built with genimg. Each recipe must be run once (and re-run when you want a fresh base) to produce /var/lib/images/<distro>/<version>/<arch>/root.img.qcow2.

Submitting image: <distro>/<version> against a self-hosted instance fails with "no such image" until the qcow2 has been built. Before recommending an image for someone's self-hosted instance, check whether they've built it. The skill's surrounding phoebe-lab/srht repo exposes just list-built-images for this.

Self-hosted instances also commonly ship a subset of the upstream catalog. The builds.sr.ht-images apk package (the source of recipes) does not include 9front or gentoo; instances that want those have to add them manually. Don't assume an image exists on a self-hosted instance just because it works on builds.sr.ht.org.

#Per-distro notes

#Alpine (alpine/*)

  • Package manager: apk. Install: apk add <pkg> (the manifest's packages: does this).
  • musl libc, BusyBox utils. Some scripts assume GNU coreutils — install coreutils if a script uses --features not in BusyBox.
  • Aliases (as of upstream compatibility matrix, 2026):
    • alpine/edge — rolling, daily refresh.
    • alpine/latest = alpine/3.23 (current stable).
    • alpine/old = alpine/3.22, alpine/older = alpine/3.21, alpine/oldest = alpine/3.20.
  • alpine/edge boots in ~5 seconds. Tiny image.
  • python3 requires py3-pip separately. Go is go. Node is nodejs + npm. Rust is rust + cargo.
  • Custom apk repositories use the three-word form repo-url key-url key-name in repositories:.

#Arch (archlinux)

  • Package manager: pacman. Rolling release.
  • AUR not available out of the box; install yay or paru via packages, then build.
  • Often the cleanest for "I just need a recent version of " because rolling.
  • Hugo is the extended (Sass-capable) build here, unlike Alpine.

#Debian (debian/<codename>)

  • Package manager: apt. Older but stable packages.
  • apt-get install needs -y to skip prompts; the manifest's packages: handles this.
  • Build essentials are in build-essential.
  • Python is python3 + python3-pip. Node is nodejs + npm (modern Debian).
  • Aliases (2026):
    • debian/stable = debian/trixie (Debian 13).
    • debian/oldstable = debian/bookworm (Debian 12).
    • debian/testing = debian/forky.
    • debian/unstable = debian/sid.
  • Both debian/stable / debian/testing and the codenames are valid; pick whichever you'd rather not have to update in two years.
  • Default arch is amd64, not x86_64.

#Ubuntu (ubuntu/<codename>)

  • Like Debian, but Canonical's spin. apt for packages.
  • Aliases (2026):
    • ubuntu/lts = ubuntu/resolute (26.04 LTS).
    • ubuntu/oldlts = ubuntu/noble (24.04 LTS).
    • Other shipped: focal (20.04 LTS), jammy (22.04 LTS), oracular (24.10), plucky (25.04), questing (25.10).
  • Default arch is amd64, not x86_64. Slower boot than Alpine. Larger image.

#Fedora (fedora/<version>)

  • Package manager: dnf. Recent packages.
  • Aliases (2026):
    • fedora/latest = fedora/43.
    • fedora/rawhide = fedora/44 (pre-release).
    • Older shipped: fedora/42.
  • The repositories: invocation differs between Fedora 41+ (dnf config-manager addrepo) and Fedora 40- (dnf config-manager --add-repo); the worker handles it but the .repo file format varies.
  • Common for RPM packaging and Red Hat-adjacent workflows.

#Rocky Linux (rockylinux/<version>)

  • Package manager: dnf. RHEL-compatible (replaces CentOS for RHEL-clone testing).
  • Versions shipped: rockylinux/8, rockylinux/9.
  • Use when you need to validate against RHEL-like userspace without RHEL licensing.

#FreeBSD (freebsd/<version>)

  • Package manager: pkg. BSD make and BSD coreutils.
  • Aliases (2026):
    • freebsd/latest = freebsd/15.x.
    • freebsd/current = freebsd/16.0-CURRENT (pre-release).
    • Also shipped: freebsd/14.x (14.4-RELEASE).
  • Default arch is amd64, not x86_64. Custom package repositories are not supported — only the standard pkg repos work.
  • Useful for cross-platform testing or BSD-targeted builds.
  • Some GNU tools have different flag syntax; check before relying on them.

#OpenBSD (openbsd/<version>)

  • Package manager: pkg_add. Base system gets syspatch for binary patches.
  • Aliases (2026): openbsd/latest = openbsd/7.8, openbsd/old = openbsd/7.7.
  • Custom package repositories are not supported.
  • Similar use case to FreeBSD; smaller, tighter system.

#NetBSD (netbsd/<version>)

  • pkgsrc via pkgin.
  • Aliases (2026): netbsd/latest = netbsd/10.x (10.0). Also: netbsd/9.x (9.3).
  • Custom package repositories are not supported.
  • Useful for portability testing across all the BSDs.

#NixOS (nixos/<channel>)

  • Nix works out of the box; flakes are not enabled by default — set NIX_CONFIG: "experimental-features = nix-command flakes" in environment: to opt in.
  • packages: uses nix-env -iA, so you need a selection path: nixos.hello, not bare hello.
  • Channels shipped (2026): nixos/unstable, nixos/latest = nixos/25.05, also nixos/24.11.
  • Custom channels via repositories: (channel-name: channel-url) run nix-channel --add + --update for you. The pre-installed root channel is nixos, pointing at the image's release (or nixos-unstable for nixos/unstable).
  • Best image for reproducible builds; once flakes are on, nix build .#mypackage is the whole task.

#Guix (guix)

  • Similar to NixOS but with Guile-based config. Niche but supported.
  • No version segment — single rolling recipe.

#Gentoo and 9front

The upstream sr.ht-docs compatibility matrix (2026) lists these distros for builds.sr.ht:

Alpine, Arch, Debian, Fedora, FreeBSD, Guix, NetBSD, NixOS, OpenBSD, Rocky Linux, Ubuntu.

It does not list Gentoo or 9front. The builds.sr.ht repo's images/ directory contains recipes for the distros above plus qemu and a control script — no gentoo/ or 9front/ directories. Submitting image: gentoo or image: 9front will fail on every standard sr.ht instance (upstream included) with "no such image" until an operator adds and builds those recipes by hand. Do not generate manifests targeting them by default.

#Architecture support

Default is x86_64. Other architectures are available on a subset of images:

  • aarch64 — available on alpine/*, recent debian/*, recent freebsd/*, archlinux (varies).
  • riscv64alpine/edge typically.
  • Others (armv7, ppc64le) — case-by-case, check the compatibility page.

To use:

image: alpine/edge
arch: aarch64

Not every image+arch combination exists. If submission fails with "no such image", the combination isn't supported.

#How arch routing actually works

On the worker, qcow2 disks live at /var/lib/images/<distro>/<version>/<arch>/root.img.qcow2. The /var/lib/images/control script reads arch: from the job, checks that path, and:

  • If host arch matches guest arch and /dev/kvm exists → KVM acceleration (~native speed).
  • If they differ → QEMU TCG software emulation (~5–20× slower).

Recipes (<distro>/<version>/functions) gate which archs they support. Most upstream recipes default to x86_64 and explicitly reject other arches — e.g. Alpine's functions has default_arch=x86_64 and a hard error otherwise. So "this distro supports aarch64" depends on the recipe, not just the worker's QEMU binaries.

For self-hosted instances: adding a new arch means (a) installing qemu-system-<arch> in the worker, (b) patching each recipe's functions to drop the arch guard and fetch arch-specific bootstrap, and (c) rebuilding the qcow2 under the new arch directory. Performance on a mismatched host (e.g. aarch64 on x86_64 hardware) makes this mostly useful for "does it compile?" CI, not real workloads.

For real cross-arch CI, the right pattern is a separate worker on native hardware — builds.sr.ht is multi-worker and the scheduler routes jobs by the arch: field to the worker that has a matching built image.

#Trade-off summary

Image Boot speed Image size Package recency Best for
alpine/edge ★★★★★ Tiny Recent Default
archlinux ★★★★ Medium Bleeding-edge Rolling deps, AUR
debian/stable ★★★ Medium Stable, older Debian packaging, glibc
ubuntu/lts ★★ Larger Stable Canonical workflows
fedora/latest ★★★ Medium Recent RPM packaging
freebsd/latest ★★ Medium Recent BSD testing
nixos/unstable ★★ Larger Rolling Reproducible builds

#Verifying package availability

Before committing a manifest, verify the package name in the target image's repos:

Package names vary: ninja (Alpine, Arch, Fedora) vs ninja-build (Debian, Ubuntu). When in doubt, look it up — the failure mode of guessing is a wasted CI run, but the lookup takes 5 seconds.