OCI Layers and Image Assembly#
Load when understanding how packages flow into the final OCI image, modifying layer assembly, or debugging why files appear or are missing from the built image.
When NOT to Use#
- Writing individual element files →
buildstream.md - Debugging individual element build failures →
debugging.md - Understanding the CI build pipeline →
ci.md
Assembly Architecture#
elements/bluefin/deps.bst ← kind: stack (dep aggregator, no filesystem output)
└── lists all bluefin/*.bst elements
elements/oci/layers/bluefin.bst ← kind: compose (filters deps into /layer filesystem)
└── depends on: deps.bst + base image
└── compose: produces actual filesystem content under /layer
elements/oci/bluefin.bst ← kind: script (final OCI assembly)
└── depends on: layers/bluefin.bst + tooling
└── runs: build-oci script to assemble the image
Historical path note: the bluefin filenames above are Dakota's OCI assembly
paths. They are not a sign to switch to the separate bluefin repo's
Containerfile-overlay workflow.
Critical: kind: compose vs kind: stack#
This is the most common layer bug:
# ✅ Correct — produces filesystem content under /layer
kind: compose
# ❌ Wrong — produces ZERO filesystem output (dep aggregator only)
kind: stack
A layer element that is kind: stack will build successfully but the OCI image layer will be silently empty. Everything looks fine until you inspect the image contents.
Verify layer type before touching elements/oci/layers/:
grep "^kind:" elements/oci/layers/bluefin.bst
# Must show: kind: compose
Compose Element Structure#
kind: compose
description: Dakota image layer (historical bluefin path name)
depends:
- deps.bst
- filename: freedesktop-sdk.bst:elements/base/base.bst
junction: true
compose:
include:
- /usr
- /etc
exclude:
- /usr/include
- /usr/lib/debug
- /usr/share/man
- /usr/share/gtk-doc
The compose: block filters the staging area — only listed paths appear in /layer.
OCI Script Assembly#
elements/oci/bluefin.bst is a kind: script element. Key operations in order:
- Merge
/usr/etcinto/etc— GNOME OS convention; all config goes to/usr/etc, must be merged for bootc - Run
dconf update— compile dconf databases from installed keyfiles - Run
ldconfig -r /layer— rebuild library cache after all installs - Run
build-oci— assemble the final OCI image
ldconfig must run after all installs, before build-oci. Missing ldconfig causes subtle runtime library failures.
BST Weak-Key Caching Bug#
Symptom: A package is added to deps.bst and just bst build succeeds, but the package is missing from the final image.
Cause: BST's non-strict mode computes weak keys for kind: stack elements from direct dependency names only. Adding a new element to deps.bst changes the list but does not change the stack's weak key → BST considers oci/layers/bluefin.bst a cache hit → skips rebuild → layer has stale content.
Workaround:
# Force strict mode build — ignores weak key cache
just bst --no-cache-buildtrees build oci/bluefin.bst
When to expect this: After adding any new package to deps.bst and running a non-strict build.
Verifying Layer Content#
After a successful build, confirm your package is in the layer:
just bst artifact list-contents oci/layers/bluefin.bst | grep <package-name>
If the package binary is missing:
- Confirm the element is in
deps.bst - Confirm compose
include:covers the binary path - Force strict rebuild:
just bst --no-cache-buildtrees build oci/bluefin.bst
Inspecting the Exported Image#
After just export, the image is in podman:
sudo podman images # find the image name
sudo podman run --rm <image> which <binary> # check binary exists
sudo podman run --rm <image> find /usr/lib/systemd -name "<service>.service"
Lessons Learned#
New package in deps.bst missing from image after a successful build (2026-06-07)#
This is always the BST weak-key caching bug. The package was built but the OCI layer was not rebuilt. Symptom: just bst artifact list-contents bluefin/<name>.bst shows files, but just bst artifact list-contents oci/layers/bluefin.bst | grep <name> returns nothing.
Fix — force strict-mode rebuild:
just bst --no-cache-buildtrees build oci/bluefin.bst
This is the only reliable fix. Do not spend time debugging the element itself; the element is fine.
dconf update must run before ldconfig, ldconfig must run before build-oci (2026-06-07)#
The OCI assembly script in elements/oci/bluefin.bst must run steps in this exact order:
- Merge
/usr/etc→/etc dconf update(compile keyfiles into GVariant databases)ldconfig -r /layer(rebuild library cache)build-oci(assemble image)
Running ldconfig after build-oci has no effect. Running build-oci before dconf update produces an image with stale/missing dconf databases.