diff options
| author | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-01-14 04:46:12 +0000 |
|---|---|---|
| committer | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-01-21 18:00:26 -0500 |
| commit | 2b1fa9e5a62f27186823539e748cc48718cd79e9 (patch) | |
| tree | 61a1a5067dc5028c52fdf01cc8b4bd86c37befde /classes | |
| parent | 08ffbeef62a426193528c539bcb02fa4b8b1c191 (diff) | |
| download | meta-virtualization-2b1fa9e5a62f27186823539e748cc48718cd79e9.tar.gz | |
container-bundle: add CONTAINER_BUNDLE_DEPLOY for base layer use
Add CONTAINER_BUNDLE_DEPLOY variable to enable dual-use of container-bundle:
1. Target packages (existing): Creates installable packages for target
container storage (Docker/Podman)
2. Base layer source (new): When CONTAINER_BUNDLE_DEPLOY = "1", also
deploys the fetched OCI image to DEPLOY_DIR_IMAGE for use as a base
layer via OCI_BASE_IMAGE
This enables fetching external images (docker.io, quay.io) and using them
as base layers for Yocto-built container images.
Example usage:
# recipes-containers/oci-base-images/alpine-oci-base_3.19.bb
inherit container-bundle
CONTAINER_BUNDLES = "docker.io/library/alpine:3.19"
CONTAINER_DIGESTS[docker.io_library_alpine_3.19] = "sha256:..."
CONTAINER_BUNDLE_DEPLOY = "1"
# Then in your app container recipe:
OCI_BASE_IMAGE = "alpine-oci-base"
IMAGE_INSTALL = "myapp"
Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
Diffstat (limited to 'classes')
| -rw-r--r-- | classes/container-bundle.bbclass | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/classes/container-bundle.bbclass b/classes/container-bundle.bbclass index 27aa81ea..3d3f3a16 100644 --- a/classes/container-bundle.bbclass +++ b/classes/container-bundle.bbclass | |||
| @@ -160,6 +160,9 @@ CONTAINER_BUNDLE_RUNTIME ?= "${@get_bundle_runtime(d)}" | |||
| 160 | # Inherit shared functions for multiconfig/machine/arch mapping | 160 | # Inherit shared functions for multiconfig/machine/arch mapping |
| 161 | inherit container-common | 161 | inherit container-common |
| 162 | 162 | ||
| 163 | # Inherit deploy for optional OCI base layer deployment (see CONTAINER_BUNDLE_DEPLOY) | ||
| 164 | inherit deploy | ||
| 165 | |||
| 163 | # Dependencies on native tools | 166 | # Dependencies on native tools |
| 164 | # vcontainer-native provides vrunner.sh | 167 | # vcontainer-native provides vrunner.sh |
| 165 | # Blobs come from multiconfig builds (vdkr-initramfs-create, vpdmn-initramfs-create) | 168 | # Blobs come from multiconfig builds (vdkr-initramfs-create, vpdmn-initramfs-create) |
| @@ -409,3 +412,65 @@ FILES:${PN} = "${datadir}/container-bundles" | |||
| 409 | # from container image recipes. Circular deps only occur if bundle packages are | 412 | # from container image recipes. Circular deps only occur if bundle packages are |
| 410 | # globally added to all images (including container images themselves). | 413 | # globally added to all images (including container images themselves). |
| 411 | do_compile[mcdepends] = "mc::${VRUNTIME_MULTICONFIG}:vdkr-initramfs-create:do_deploy mc::${VRUNTIME_MULTICONFIG}:vpdmn-initramfs-create:do_deploy" | 414 | do_compile[mcdepends] = "mc::${VRUNTIME_MULTICONFIG}:vdkr-initramfs-create:do_deploy mc::${VRUNTIME_MULTICONFIG}:vpdmn-initramfs-create:do_deploy" |
| 415 | |||
| 416 | # =========================================================================== | ||
| 417 | # Optional Deploy for OCI Base Layer Usage | ||
| 418 | # =========================================================================== | ||
| 419 | # | ||
| 420 | # When CONTAINER_BUNDLE_DEPLOY = "1", this class also deploys fetched remote | ||
| 421 | # containers to DEPLOY_DIR_IMAGE for use as base layers with OCI_BASE_IMAGE. | ||
| 422 | # | ||
| 423 | # This enables dual-use recipes that both: | ||
| 424 | # 1. Create installable packages for target container storage | ||
| 425 | # 2. Provide OCI base layers for building layered containers | ||
| 426 | # | ||
| 427 | # Example: | ||
| 428 | # # alpine-oci-base.bb | ||
| 429 | # inherit container-bundle | ||
| 430 | # CONTAINER_BUNDLES = "docker.io/library/alpine:3.19" | ||
| 431 | # CONTAINER_DIGESTS[docker.io_library_alpine_3.19] = "sha256:..." | ||
| 432 | # CONTAINER_BUNDLE_DEPLOY = "1" | ||
| 433 | # | ||
| 434 | # # Then in another recipe: | ||
| 435 | # OCI_BASE_IMAGE = "alpine-oci-base" | ||
| 436 | # | ||
| 437 | CONTAINER_BUNDLE_DEPLOY ?= "" | ||
| 438 | |||
| 439 | python () { | ||
| 440 | if d.getVar('CONTAINER_BUNDLE_DEPLOY') == "1": | ||
| 441 | # Inherit deploy class dynamically | ||
| 442 | bb.build.addtask('do_deploy', 'do_build', 'do_compile', d) | ||
| 443 | } | ||
| 444 | |||
| 445 | do_deploy() { | ||
| 446 | if [ "${CONTAINER_BUNDLE_DEPLOY}" != "1" ]; then | ||
| 447 | bbnote "CONTAINER_BUNDLE_DEPLOY not set, skipping deploy" | ||
| 448 | return 0 | ||
| 449 | fi | ||
| 450 | |||
| 451 | # Deploy fetched OCI directories to DEPLOY_DIR_IMAGE for use as base layers | ||
| 452 | # Format: ${PN}-latest-oci/ (matches what image-oci.bbclass expects) | ||
| 453 | |||
| 454 | if [ ! -d "${WORKDIR}/fetched" ]; then | ||
| 455 | bbwarn "No fetched containers to deploy" | ||
| 456 | return 0 | ||
| 457 | fi | ||
| 458 | |||
| 459 | # Find the first (primary) fetched OCI directory | ||
| 460 | oci_dir=$(ls -d ${WORKDIR}/fetched/*/ 2>/dev/null | head -1) | ||
| 461 | if [ -z "$oci_dir" ] || [ ! -f "$oci_dir/index.json" ]; then | ||
| 462 | bbfatal "No valid OCI directory found in ${WORKDIR}/fetched/" | ||
| 463 | fi | ||
| 464 | |||
| 465 | bbnote "Deploying OCI base layer: $oci_dir -> ${DEPLOYDIR}/${PN}-latest-oci" | ||
| 466 | |||
| 467 | install -d ${DEPLOYDIR} | ||
| 468 | cp -rL "$oci_dir" ${DEPLOYDIR}/${PN}-${PV}-oci | ||
| 469 | |||
| 470 | # Create symlinks for OCI_BASE_IMAGE lookup | ||
| 471 | ln -sfn ${PN}-${PV}-oci ${DEPLOYDIR}/${PN}-latest-oci | ||
| 472 | } | ||
| 473 | do_deploy[dirs] = "${DEPLOYDIR}" | ||
| 474 | |||
| 475 | # Only add sstate for deploy when enabled | ||
| 476 | SSTATE_SKIP_CREATION:task-deploy = "${@'' if d.getVar('CONTAINER_BUNDLE_DEPLOY') == '1' else '1'}" | ||
