Skip to content

feat(iso): embed installer payload as OCI layout, drop install-time RAM staging - #4

Merged
leandromqrs merged 3 commits into
mainfrom
feat/oci-payload-no-tmpfs-staging
Jul 20, 2026
Merged

feat(iso): embed installer payload as OCI layout, drop install-time RAM staging#4
leandromqrs merged 3 commits into
mainfrom
feat/oci-payload-no-tmpfs-staging

Conversation

@leandromqrs

Copy link
Copy Markdown
Member

Summary

The bootc-generic-iso image type embeds the bootc installer payload into the ISO as a containers-storage blob. Because containers/storage keeps layers already unpacked, bootc install to-filesystem has to re-diff and re-tar every layer into a /var/tmp staging area (~2.5 GiB compressed) before deploying them. On a live ISO, /var/tmp has nowhere to go but RAM, which forced a dedicated tmpfs mount (var-tmp.mount, 75% of RAM) and a ~5 GiB minimum-RAM gate in the installer.

This PR switches the embedded payload to an OCI layout (/usr/lib/luminusos/payload.oci), ready-made layer blobs that bootc install --source-imgref oci:... streams straight to the target disk, with no re-tar and no staging. The minimum RAM gate drops from 5 to 2 GiB, which only needs to cover the live GNOME session itself.

Implementation

  • image-builder-cli has no flag to select the payload embed format, so the build generates the bootc-generic-iso osbuild manifest, patches the single org.osbuild.skopeo stage in the os-tree pipeline from containers-storage to oci, and runs osbuild directly on the patched manifest (tools/patch-iso-payload-to-oci.sh). The jq patch fails loudly if the stage is missing, so an upstream manifest shape change breaks the build instead of silently reverting to the old embed.
  • The destination path deliberately carries the :latest tag: skopeo copy oci:... strips it from the on-disk directory name and records it as the org.opencontainers.image.ref.name annotation in index.json. Without it the layout has no ref name and bootc fails with no descriptor found for reference "latest" (found the hard way).
  • distro.toml now points bootc at the fixed oci:/usr/lib/luminusos/payload.oci:latest path.
  • Removed the now-unneeded var-tmp.mount unit and the image_copy_tmp_dir containers.conf.d drop-in.
  • The same manifest patch is applied by both the local Justfile flow and the CI packaging script (ci-package.sh), the first version of this change only patched the local flow, which would have produced CI ISOs whose installer config pointed at a non-existent OCI path.

Upstream status (what would make this patch unnecessary)

The manifest patch is a bridge until the payload embed format becomes a first-class option in osbuild/images / image-builder-cli. Relevant upstream work:

Reference Status Relevance
osbuild/image-builder#2138 — bootc-generic-iso: add container embedding merged 2026-01 Introduced the containers-storage payload embed we are working around; the author already notes the mechanism should be generalized.
osbuild/image-builder#2271 — bootc manifests with remote (skopeo) container sources merged 2026-03 Refactored how bootc manifests source containers (local storage vs org.osbuild.skopeo); touches the exact stage we patch.
osbuild/image-builder-cli#341 — add support for bootc-installer image types merged The CLI exposes no flag for the embed destination; this is where such a flag would land.
osbuild/osbuild#952 / #1752 — skopeo stage container embedding + destination types merged The stage capability our patch relies on (destination: {type:oci, path: ...}).
bootc-dev/bootc#1884 — digest computation hits "No space left on device" open Independent evidence that the containers-storage re-tar-to-tmp cost keeps biting bootc workflows.

As of this PR there is no dedicated upstream issue for selecting an OCI layout embed for the bootc installer ISO (the Anaconda installer already consumes payloads in this ready-made-blob model).

Testing

  • tests/run.sh: new unit tests assert the patch produces exactly {type: oci, path: /usr/lib/luminusos/payload.oci:latest} and rejects manifests whose shape changed.
  • Local ISO build verified end-to-end: patched manifest, skopeo copy embeds the payload as an OCI layout, ISO boots to the Sirius installer, and bootc install resolves the oci:...:latest reference.
  • Running via QEMU and test installing in a VM with 2 GB ram
  • CI boot smoke test (QEMU screendumps + color/OCR heuristics) passes.

bootc-generic-iso embeds the payload as a containers-storage blob, which
forces `bootc install` to re-diff/re-tar each layer into /var/tmp
(~2.5 GiB) at install time. On a live ISO that has nowhere to go but
RAM, hence the var-tmp.mount tmpfs and the 5 GiB min_ram_gib gate.

osbuild's skopeo stage also supports an "oci" destination (ready-made
layer blobs, no re-tar) — the same model Anaconda uses for ostree-native
container payloads. image-builder-cli has no flag to pick it, so
package_iso() now generates the bootc-generic-iso manifest, patches the
one org.osbuild.skopeo stage in the os-tree pipeline from
containers-storage to oci, and runs osbuild directly against the
patched manifest. The jq patch fails loudly if that stage isn't found,
so an upstream manifest shape change breaks the build instead of
silently reverting to the old embed.

distro.toml now points bootc at the fixed oci:/usr/lib/luminusos/
payload.oci:latest path; the var-tmp.mount unit and the
image_copy_tmp_dir containers.conf.d drop-in are gone (unneeded);
min_ram_gib drops from 5 to 2, matching the live GNOME session's own
floor.
… patch with CI

skopeo copy to an oci: destination without a tag writes no
org.opencontainers.image.ref.name annotation into index.json, so
bootc install failed with 'no descriptor found for reference "latest"'
even though the payload was embedded. Append :latest to the destination
path: skopeo strips it from the on-disk directory name (still
payload.oci) and records it as the ref name annotation.

The OCI embed patch also only existed in the local Justfile flow; the
CI packaging script kept building the ISO with a plain image-builder
run, embedding containers-storage while distro.toml already pointed at
the oci: path. Extract the patch into tools/patch-iso-payload-to-oci.sh
and use it from both package_iso() and .github/scripts/ci-package.sh
(which now installs jq/osbuild, generates the manifest with
--with-manifest, patches it, and runs osbuild directly).
- drop --bootc-default-fs btrfs: the image's disk.yaml already defines
  the btrfs root and takes precedence, so the flag only produced an
  'ignoring --bootc-default-fs' warning
- remove the duplicated 'no post-build squash needed' echo in
  package_iso()
- mv -f when moving the generated manifest and ISO so reruns do not
  prompt interactively when artifacts from a previous run exist
- docs: disk.yaml is now described as the source of truth for the
  install storage layout (AGENTS.md, ARCHITECTURE.md)
@leandromqrs

Copy link
Copy Markdown
Member Author

Created an issue in osbuild/image-builder#2536

@leandromqrs
leandromqrs merged commit 70c5a12 into main Jul 20, 2026
6 checks passed
@leandromqrs
leandromqrs deleted the feat/oci-payload-no-tmpfs-staging branch July 20, 2026 21:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant