docs: add three LiveCD/embedded patterns from bee project

- alpine-livecd: mkimage profile rules, apkovl mechanics, workdir caching,
  squashfs compression, NIC firmware, long build survival via screen
- vendor-installer-verification: checksum-before-download, cache validation,
  version URL verification before writing build scripts
- unattended-boot-services: OpenRC invariants for headless environments,
  network-independent SSH, persistent DHCP, graceful degradation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 18:18:22 +03:00
parent c73ece6c7c
commit a38c35ce2d
3 changed files with 357 additions and 0 deletions

View File

@@ -0,0 +1,142 @@
# Contract: Alpine LiveCD Build
Version: 1.0
## Purpose
Rules for building bootable Alpine Linux ISO images with custom overlays using `mkimage.sh`.
Applies to any project that needs a LiveCD: hardware audit, rescue environments, kiosks.
---
## mkimage Profile
Every project must have a profile file `mkimg.<name>.sh` defining:
```sh
profile_<name>() {
arch="x86_64" # REQUIRED — without this mkimage silently skips the profile
hostname="<hostname>"
apkovl="genapkovl-<name>.sh"
image_ext="iso"
output_format="iso"
kernel_flavors="lts"
initfs_cmdline="modules=loop,squashfs,sd-mod,usb-storage quiet"
initfs_features="ata base cdrom ext4 mmc nvme raid scsi squashfs usb virtio"
grub_mod="all_video disk part_gpt part_msdos linux normal configfile search search_label efi_gop fat iso9660 cat echo ls test true help gzio"
apks="alpine-base linux-lts linux-firmware-none ..."
}
```
**`arch` is mandatory.** If missing, mkimage silently builds nothing and exits 0.
---
## apkovl Mechanism
The apkovl is a `.tar.gz` overlay extracted by initramfs at boot, overlaying `/etc`, `/usr`, `/root`.
`genapkovl-<name>.sh` generates the tarball:
- Must be in the **CWD** when mkimage runs — not only in `~/.mkimage/`
- `~/.mkimage/` is searched for mkimg profiles only, not genapkovl scripts
```sh
# Copy both scripts to ~/.mkimage AND to CWD (typically /var/tmp)
cp "genapkovl-<name>.sh" ~/.mkimage/
cp "genapkovl-<name>.sh" /var/tmp/
cd /var/tmp
sh mkimage.sh --workdir /var/tmp/work ...
```
---
## Build Environment
**Always use `/var/tmp`, not `/tmp`:**
```sh
export TMPDIR=/var/tmp
cd /var/tmp
sh mkimage.sh ...
```
`/tmp` on Alpine builder VMs is typically a 1GB tmpfs. Kernel firmware squashfs alone exceeds this.
`/var/tmp` uses actual disk space.
---
## Workdir Caching
mkimage stores each ISO section in a hash-named subdirectory. Preserve expensive sections across builds:
```sh
# Delete everything EXCEPT cached sections
if [ -d /var/tmp/bee-iso-work ]; then
find /var/tmp/bee-iso-work -maxdepth 1 -mindepth 1 \
-not -name 'apks_*' \ # downloaded packages
-not -name 'kernel_*' \ # modloop squashfs
-not -name 'syslinux_*' \ # syslinux bootloader
-not -name 'grub_*' \ # grub EFI
-exec rm -rf {} +
fi
```
The apkovl section is always regenerated (contains project-specific config that changes per build).
---
## Squashfs Compression
Default compression is `xz` — slow but small. For RAM-loaded modloops, size rarely matters.
Use `lz4` for faster builds:
```sh
mkdir -p /etc/mkinitfs
grep -q 'MKSQUASHFS_OPTS' /etc/mkinitfs/mkinitfs.conf 2>/dev/null || \
echo 'MKSQUASHFS_OPTS="-comp lz4 -Xhc"' >> /etc/mkinitfs/mkinitfs.conf
```
Apply before running mkimage. Rebuilds modloop only when kernel version changes.
---
## Long Builds
NVIDIA driver downloads, kernel compiles, and package fetches can take 1030 minutes.
Run in a `screen` session so builds survive SSH disconnects:
```sh
apk add screen
screen -dmS build sh -c "sh build.sh > /var/log/build.log 2>&1"
tail -f /var/log/build.log
```
---
## NIC Firmware
`linux-firmware-none` (default) contains zero firmware files. Real hardware NICs often require firmware.
Include firmware packages matching expected hardware:
```
linux-firmware-intel # Intel NICs (X710, E810, etc.)
linux-firmware-mellanox # Mellanox/NVIDIA ConnectX
linux-firmware-bnx2x # Broadcom NetXtreme
linux-firmware-rtl_nic # Realtek
linux-firmware-other # catch-all
```
---
## Versioning
Pin all versions in a single `VERSIONS` file sourced by all build scripts:
```sh
ALPINE_VERSION=3.21
KERNEL_VERSION=6.12
GO_VERSION=1.23.6
NVIDIA_DRIVER_VERSION=590.48.01
```
Never hardcode versions inside build scripts.