os/ ISO build pipeline #9

Open
opened 2026-07-19 02:31:45 +00:00 by agent · 0 comments
Member

Plan: os/ ISO Build Pipeline

Goal

Build a bootable Alpine-based ISO for residual, starting with a clean Alpine base, then layering in residual customizations and init scripts.

Status

Phase 1 — Alpine base ISO pipeline [DONE]

  • Converted profile files from .conf to Alpine's mkimg.*.sh format with profile_<name>() {} wrappers.
  • Fixed Dockerfile.mkimage (add alpine-conf, fakeroot, build user in abuild group), entrypoint.sh (root setup, su build for mkimage.sh), profile copy target (scripts/), profile naming (underscores).
  • abuild-keygen -a -n then run as build user.
  • First successful ISO: alpine-alpine_base-260702-x86_64.iso (348MB).

Phase 2 — residual profile packages [DONE for console-only base]

  • Fixed /sbin/init boot failure — switched both profiles to openrc (provides /sbin/init).
  • Pinned base off edge to v3.24 (latest stable) — Dockerfile.mkimage FROM alpine:3.24, repo URLs → v3.24/main + v3.24/community.
  • Removed qemu-nbd (ships inside qemu-img).
  • Architecture decision: base ISO is console/tty only. No display server, no GUI, no dev toolchain. Desktop (i3wm + picom + xfce4-panel) is opt-in apk add after persistence mounts. ly display manager now moot.
  • Full --profile residual build succeeds end-to-end, console-only, on v3.24 pin: 360MB (under 512MB target).

Phase 3 — residual overlay configuration [NEXT UP]

  • Add residual overlay (overlayfs/rootfs/) to the ISO via apkovl or overlay section.
  • Wire in residual overlay files (etc/ly/config.ini needs rethinking — no ly in base image; console getty/login config instead).
  • Set default hostname to "residual".
  • Design where canonical desktop dotfiles live in the repo (two paths: auto-copied if desktop chosen during res-os setup; residual reset-config-style command for manual install).

Phase 2.5 — ISO size budget [RESOLVED for now]

Target 512MB max. Final residual profile (console-only): 360MB. modloop-lts (289MB) is the entire remaining size story; 360MB is well under target, no further modloop work needed now.

Phase 4 — persistence initramfs hook [DEFERRED per AGENTS.md §12]

  • Validate how Alpine's mkimage.sh integrates custom initramfs features (mkinitfs features.d inside ISO chroot).
  • Integrate init/residual-init as a proper mkinitfs feature.
  • Add residual to initfs_features in profile.

Important distinction: TWO unrelated "overlay" concepts:

  1. overlayfs/rootfs/ (this repo) — static files baked into ISO at build time. Not runtime persistence.
  2. Actual persistence (docs/os/os.md) — runtime overlay mount (upperdir/lowerdir) backed by btrfs, on a labeled partition or qcow2 via qemu-nbd. Phase 4.

Phase 5 — res-os / suckless binaries [DEFERRED]

  • Dockerfile.build compiles res-os + suckless (st, dmenu, slock).
  • ./build.sh --compile copies them into overlayfs/rootfs/usr/local/bin/.
  • Suckless source trees in os/suckless/ must be populated first.

Key implementation notes

  • Profile files: os/iso/profiles/mkimg.<name>.sh, placed in aports/scripts/ at build time. Function name = profile_<name> (underscores).
  • mkimage.sh runs as build (non-root) via su build -s /bin/sh -c "...". Root only for initial setup.
  • update-kernel comes from alpine-conf package.
  • abuild-keygen -a -n generates key in ~build/.abuild/; mkimage.sh sources it via functions.sh.
  • compose.yml mounts overlayfs/rootfs as /home/build/overlays/residual.

Commands

cd os/
PROFILE=alpine_base docker compose run --rm mkimage   # fast validation
docker compose run --rm mkimage                        # full residual build
./build.sh --compile --profile residual                # with binaries compiled first
# Plan: os/ ISO Build Pipeline ## Goal Build a bootable Alpine-based ISO for residual, starting with a clean Alpine base, then layering in residual customizations and init scripts. ## Status ### Phase 1 — Alpine base ISO pipeline [DONE] - Converted profile files from `.conf` to Alpine's `mkimg.*.sh` format with `profile_<name>() {}` wrappers. - Fixed Dockerfile.mkimage (add `alpine-conf`, `fakeroot`, `build` user in `abuild` group), entrypoint.sh (root setup, `su build` for mkimage.sh), profile copy target (`scripts/`), profile naming (underscores). - abuild-keygen `-a -n` then run as `build` user. - First successful ISO: `alpine-alpine_base-260702-x86_64.iso` (348MB). ### Phase 2 — residual profile packages [DONE for console-only base] - Fixed `/sbin/init` boot failure — switched both profiles to `openrc` (provides `/sbin/init`). - Pinned base off `edge` to `v3.24` (latest stable) — `Dockerfile.mkimage FROM alpine:3.24`, repo URLs → `v3.24/main` + `v3.24/community`. - Removed `qemu-nbd` (ships inside `qemu-img`). - **Architecture decision: base ISO is console/tty only.** No display server, no GUI, no dev toolchain. Desktop (i3wm + picom + xfce4-panel) is opt-in `apk add` after persistence mounts. `ly` display manager now moot. - Full `--profile residual` build succeeds end-to-end, console-only, on v3.24 pin: **360MB** (under 512MB target). ### Phase 3 — residual overlay configuration [NEXT UP] - [ ] Add residual overlay (overlayfs/rootfs/) to the ISO via apkovl or overlay section. - [ ] Wire in residual overlay files (etc/ly/config.ini needs rethinking — no `ly` in base image; console getty/login config instead). - [ ] Set default hostname to "residual". - [ ] Design where canonical desktop dotfiles live in the repo (two paths: auto-copied if desktop chosen during `res-os setup`; `residual reset-config`-style command for manual install). ### Phase 2.5 — ISO size budget [RESOLVED for now] Target 512MB max. Final `residual` profile (console-only): **360MB**. modloop-lts (289MB) is the entire remaining size story; 360MB is well under target, no further modloop work needed now. ### Phase 4 — persistence initramfs hook [DEFERRED per AGENTS.md §12] - [ ] Validate how Alpine's mkimage.sh integrates custom initramfs features (mkinitfs features.d inside ISO chroot). - [ ] Integrate `init/residual-init` as a proper mkinitfs feature. - [ ] Add `residual` to `initfs_features` in profile. **Important distinction:** TWO unrelated "overlay" concepts: 1. `overlayfs/rootfs/` (this repo) — static files baked into ISO at build time. Not runtime persistence. 2. Actual persistence (docs/os/os.md) — runtime `overlay` mount (upperdir/lowerdir) backed by btrfs, on a labeled partition or qcow2 via qemu-nbd. Phase 4. ### Phase 5 — res-os / suckless binaries [DEFERRED] - [ ] Dockerfile.build compiles res-os + suckless (st, dmenu, slock). - [ ] `./build.sh --compile` copies them into `overlayfs/rootfs/usr/local/bin/`. - [ ] Suckless source trees in `os/suckless/` must be populated first. ## Key implementation notes - Profile files: `os/iso/profiles/mkimg.<name>.sh`, placed in `aports/scripts/` at build time. Function name = `profile_<name>` (underscores). - mkimage.sh runs as `build` (non-root) via `su build -s /bin/sh -c "..."`. Root only for initial setup. - `update-kernel` comes from `alpine-conf` package. - `abuild-keygen -a -n` generates key in `~build/.abuild/`; mkimage.sh sources it via `functions.sh`. - `compose.yml` mounts `overlayfs/rootfs` as `/home/build/overlays/residual`. ## Commands ```sh cd os/ PROFILE=alpine_base docker compose run --rm mkimage # fast validation docker compose run --rm mkimage # full residual build ./build.sh --compile --profile residual # with binaries compiled first ```
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
residual/.agent#9
No description provided.