Skip to main content

max / alloy

build: add image-builder def and build-image.sh Make ISO/disk generation reproducible without re-deriving the bootc-image-builder workarounds: - build/alloy-0.0.yaml: the distro def bib lacks for Alloy's rebranded os-release (ID=alloy, VERSION_ID=0.0) — bib's fedora-42 anaconda-iso package set verbatim, bind-mounted into the builder. - build/build-image.sh: builds the bootc image and an installer ISO (or --type raw), runs rootful so bib shares the container store, and optionally writes the artifact to a USB device behind an explicit confirmation.
Co-Authored-By
Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-18 03:27 UTC
Signed with PGP, not checked
Commit: 39b99c7ce3ba838ef24aea1725e7306f09174a6c
Parent: 1c753b0
2 files changed, +240 insertions, -0 deletions
@@ -1,0 +1,123 @@
1 + # alloy-0.0.yaml — bootc-image-builder distro definition for Alloy.
2 + #
3 + # Alloy re-brands os-release (ID=alloy, VERSION_ID=0.0), so bootc-image-builder
4 + # looks up a distro def named "alloy-0.0" and ships none. This file is bib's own
5 + # fedora-42.yaml anaconda-iso package set verbatim (Alloy is Fedora 42 underneath);
6 + # build/build-image.sh bind-mounts it into the builder's defs directory.
7 + #
8 + # Regenerate from a newer bib with:
9 + # podman run --rm --entrypoint sh <bib-image> -c \
10 + # 'cat /usr/share/bootc-image-builder/defs/fedora-42.yaml'
11 + # then re-add this header.
12 + anaconda-iso:
13 + packages:
14 + - aajohan-comfortaa-fonts
15 + - abattis-cantarell-fonts
16 + - alsa-firmware
17 + - alsa-tools-firmware
18 + - anaconda
19 + - anaconda-dracut
20 + - anaconda-install-img-deps
21 + - anaconda-widgets
22 + - atheros-firmware
23 + - audit
24 + - bind-utils
25 + - bitmap-fangsongti-fonts
26 + - brcmfmac-firmware
27 + - bzip2
28 + - cryptsetup
29 + - curl
30 + - dbus-x11
31 + - dejavu-sans-fonts
32 + - dejavu-sans-mono-fonts
33 + - device-mapper-persistent-data
34 + - dmidecode
35 + - dnf
36 + - dracut-config-generic
37 + - dracut-network
38 + - efibootmgr
39 + - ethtool
40 + - fcoe-utils
41 + - ftp
42 + - gdb-gdbserver
43 + - gdisk
44 + - glibc-all-langpacks
45 + - gnome-kiosk
46 + - google-noto-sans-cjk-ttc-fonts
47 + - grub2-tools
48 + - grub2-tools-extra
49 + - grub2-tools-minimal
50 + - grubby
51 + - gsettings-desktop-schemas
52 + - hdparm
53 + - hexedit
54 + - hostname
55 + - initscripts
56 + - ipmitool
57 + - iwlwifi-dvm-firmware
58 + - iwlwifi-mvm-firmware
59 + - jomolhari-fonts
60 + - kbd
61 + - kbd-misc
62 + - kdump-anaconda-addon
63 + - kernel
64 + - khmeros-base-fonts
65 + - less
66 + - libblockdev-lvm-dbus
67 + - libibverbs
68 + - libreport-plugin-bugzilla
69 + - libreport-plugin-reportuploader
70 + - librsvg2
71 + - linux-firmware
72 + - lldpad
73 + - lsof
74 + - madan-fonts
75 + - mt-st
76 + - mtr
77 + - net-tools
78 + - nfs-utils
79 + - nm-connection-editor
80 + - nmap-ncat
81 + - nss-tools
82 + - openssh-clients
83 + - openssh-server
84 + - ostree
85 + - pciutils
86 + - perl-interpreter
87 + - pigz
88 + - plymouth
89 + - prefixdevname
90 + - python3-pyatspi
91 + - rdma-core
92 + - realtek-firmware
93 + - rit-meera-new-fonts
94 + - rng-tools
95 + - rpcbind
96 + - rpm-ostree
97 + - rsync
98 + - rsyslog
99 + - selinux-policy-targeted
100 + - sg3_utils
101 + - sil-abyssinica-fonts
102 + - sil-padauk-fonts
103 + - smartmontools
104 + - spice-vdagent
105 + - strace
106 + - systemd
107 + - tar
108 + - tigervnc-server-minimal
109 + - tigervnc-server-module
110 + - udisks2
111 + - udisks2-iscsi
112 + - usbutils
113 + - vim-minimal
114 + - volume_key
115 + - wget
116 + - xfsdump
117 + - xfsprogs
118 + - xorg-x11-drivers
119 + - xorg-x11-fonts-misc
120 + - xorg-x11-server-Xorg
121 + - xorg-x11-xauth
122 + - xrdb
123 + - xz
@@ -1,0 +1,117 @@
1 + #!/usr/bin/env bash
2 + #
3 + # build-image.sh — build the Alloy bootc image and a bootable artifact
4 + # (installer ISO by default) with bootc-image-builder.
5 + #
6 + # Alloy re-brands os-release (ID=alloy, VERSION_ID=0.0). Two consequences
7 + # are handled in the Containerfile (pinned $releasever, disabled build-only
8 + # repos) and one here: bootc-image-builder has no distro definition named
9 + # "alloy-0.0", so build/alloy-0.0.yaml is bind-mounted into its defs dir.
10 + #
11 + # Everything runs rootful on purpose: the image build and bib share one
12 + # container store, so bib finds the image at /var/lib/containers/storage
13 + # without a rootless->rootful copy.
14 + #
15 + # Usage:
16 + # build/build-image.sh # build image + installer ISO
17 + # build/build-image.sh --type raw # build image + raw disk image
18 + # build/build-image.sh --skip-build # reuse the current image, just run bib
19 + # build/build-image.sh --write /dev/sdX # also dd the artifact to a device
20 + #
21 + # Writing requires an explicit device path and an interactive confirmation.
22 +
23 + set -euo pipefail
24 +
25 + REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
26 + IMAGE="localhost/alloy:local"
27 + BIB_IMAGE="quay.io/centos-bootc/bootc-image-builder:latest"
28 + DEF="$REPO_ROOT/build/alloy-0.0.yaml"
29 + OUTPUT="$REPO_ROOT/output"
30 +
31 + TYPE="iso"
32 + WRITE_DEV=""
33 + SKIP_BUILD=0
34 +
35 + die() { printf 'error: %s\n' "$*" >&2; exit 1; }
36 +
37 + usage() {
38 + sed -n '2,20p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
39 + exit "${1:-0}"
40 + }
41 +
42 + while [ $# -gt 0 ]; do
43 + case "$1" in
44 + --type) TYPE="${2:?--type needs a value}"; shift 2 ;;
45 + --write) WRITE_DEV="${2:?--write needs a device path}"; shift 2 ;;
46 + --skip-build) SKIP_BUILD=1; shift ;;
47 + -h|--help) usage 0 ;;
48 + *) die "unknown argument: $1 (see --help)" ;;
49 + esac
50 + done
51 +
52 + command -v podman >/dev/null || die "podman not found"
53 + [ -f "$DEF" ] || die "missing distro def: $DEF"
54 + [ -f "$REPO_ROOT/Containerfile" ] || die "no Containerfile at $REPO_ROOT"
55 +
56 + # 1. Build the bootc image (rootful, so bib sees it in the same store).
57 + if [ "$SKIP_BUILD" -eq 0 ]; then
58 + echo "==> Building $IMAGE (rootful)"
59 + sudo podman build -t "$IMAGE" "$REPO_ROOT"
60 + else
61 + echo "==> Skipping image build; reusing $IMAGE"
62 + sudo podman image exists "$IMAGE" || die "$IMAGE not in the root store; drop --skip-build"
63 + fi
64 +
65 + # 2. Make sure the image builder is present.
66 + sudo podman image exists "$BIB_IMAGE" || {
67 + echo "==> Pulling $BIB_IMAGE"
68 + sudo podman pull "$BIB_IMAGE"
69 + }
70 +
71 + # 3. Build the artifact. The alloy-0.0 def is mounted read-only into bib's
72 + # defs directory; librepo (the default) resolves repos from the image.
73 + echo "==> Building --type $TYPE into $OUTPUT"
74 + mkdir -p "$OUTPUT"
75 + sudo rm -rf "${OUTPUT:?}/"* 2>/dev/null || true
76 + sudo podman run --rm --privileged \
77 + --security-opt label=type:unconfined_t \
78 + -v /var/lib/containers/storage:/var/lib/containers/storage \
79 + -v "$OUTPUT":/output \
80 + -v "$DEF":/usr/share/bootc-image-builder/defs/alloy-0.0.yaml:ro \
81 + "$BIB_IMAGE" \
82 + --type "$TYPE" \
83 + --log-level info \
84 + "$IMAGE"
85 +
86 + # 4. Locate the produced artifact.
87 + case "$TYPE" in
88 + iso) ARTIFACT="$OUTPUT/bootiso/install.iso" ;;
89 + raw) ARTIFACT="$OUTPUT/image/disk.raw" ;;
90 + qcow2) ARTIFACT="$OUTPUT/qcow2/disk.qcow2" ;;
91 + *) ARTIFACT="$(sudo find "$OUTPUT" -type f ! -name '*.json' | head -1)" ;;
92 + esac
93 + [ -n "$ARTIFACT" ] && sudo test -f "$ARTIFACT" || die "expected artifact not found for type $TYPE"
94 + echo "==> Built: $ARTIFACT ($(sudo du -h "$ARTIFACT" | cut -f1))"
95 +
96 + # 5. Optionally write to a device.
97 + if [ -n "$WRITE_DEV" ]; then
98 + [ -b "$WRITE_DEV" ] || die "$WRITE_DEV is not a block device"
99 + # Refuse to write to a disk that carries a mounted filesystem (root disk guard).
100 + if lsblk -nro MOUNTPOINT "$WRITE_DEV" | grep -qE '^/$|^/boot'; then
101 + die "$WRITE_DEV has a system mountpoint; refusing to write"
102 + fi
103 + echo
104 + lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,MODEL,SERIAL,TRAN "$WRITE_DEV"
105 + echo
106 + printf 'This ERASES all data on %s. Type the device path to confirm: ' "$WRITE_DEV"
107 + read -r reply
108 + [ "$reply" = "$WRITE_DEV" ] || die "confirmation did not match; not writing"
109 + echo "==> Writing $ARTIFACT to $WRITE_DEV"
110 + sudo dd if="$ARTIFACT" of="$WRITE_DEV" bs=4M oflag=direct conv=fsync status=progress
111 + sync
112 + echo "==> Done. $WRITE_DEV is now a bootable Alloy $TYPE."
113 + else
114 + echo "==> To write it to a USB stick:"
115 + echo " sudo dd if=$ARTIFACT of=/dev/sdX bs=4M oflag=direct conv=fsync status=progress"
116 + echo " (or re-run with --write /dev/sdX to rebuild and write in one step)"
117 + fi