diff options
| author | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-05-10 13:58:10 +0000 |
|---|---|---|
| committer | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-05-10 13:58:10 +0000 |
| commit | 3d431848b32caae67b9dcbf7fe04f08ddcd448b5 (patch) | |
| tree | ab48eaceb7931a73159348e0bf67d93beda3256d | |
| parent | 84e81eea1a581e10528b2ba95f9c34ee67c8ad3c (diff) | |
| download | meta-virtualization-3d431848b32caae67b9dcbf7fe04f08ddcd448b5.tar.gz | |
oci-multiarch: fix MC defaults, deploy dependency, and OCI layout
Three issues prevented oci-multiarch.bbclass from producing usable
multi-architecture container images:
1. MC defaults pointed to vruntime-* multiconfigs, whose BBMASK blocks
OCI tooling. Changed to container-* multiconfigs which use the new
vcontainer distro without BBMASK.
2. mcdepends targeted do_image_oci, but the OCI output is only deployed
to deploy/images/ by the later do_image_complete task. The bbclass
then failed to find the OCI directory at the expected deploy path.
The original implementation assumed do_image_oci was the final step,
but OE-core's image pipeline has a separate deploy phase.
3. The OCI Image Index was written directly into index.json with
multiple manifest entries. This is valid per the OCI spec but skopeo
requires index.json to reference a single entry when there are
multiple images. The fix writes the multi-platform image index as a
blob in blobs/sha256/ and has index.json reference it with a single
entry of mediaType application/vnd.oci.image.index.v1+json. This
nested layout is what tools like buildah and crane produce for
multi-arch images, and is required for 'skopeo copy --all' to work.
Also adds container-base-multiarch.bb recipe that wires up container-base
for aarch64 + x86_64 builds via the oci-multiarch class.
Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
| -rw-r--r-- | classes/oci-multiarch.bbclass | 47 | ||||
| -rw-r--r-- | recipes-extended/images/container-base-multiarch.bb | 9 |
2 files changed, 44 insertions, 12 deletions
diff --git a/classes/oci-multiarch.bbclass b/classes/oci-multiarch.bbclass index 9960b7cc..3923a52e 100644 --- a/classes/oci-multiarch.bbclass +++ b/classes/oci-multiarch.bbclass | |||
| @@ -17,9 +17,9 @@ | |||
| 17 | # OCI_MULTIARCH_RECIPE = "myapp-container" | 17 | # OCI_MULTIARCH_RECIPE = "myapp-container" |
| 18 | # OCI_MULTIARCH_PLATFORMS = "aarch64 x86_64" | 18 | # OCI_MULTIARCH_PLATFORMS = "aarch64 x86_64" |
| 19 | # | 19 | # |
| 20 | # # Optional: custom multiconfig mapping | 20 | # # Optional: custom multiconfig mapping (defaults use vcontainer distro) |
| 21 | # OCI_MULTIARCH_MC[aarch64] = "vruntime-aarch64" | 21 | # OCI_MULTIARCH_MC[aarch64] = "container-aarch64" |
| 22 | # OCI_MULTIARCH_MC[x86_64] = "vruntime-x86-64" | 22 | # OCI_MULTIARCH_MC[x86_64] = "container-x86-64" |
| 23 | # | 23 | # |
| 24 | # OUTPUT: | 24 | # OUTPUT: |
| 25 | # ${DEPLOY_DIR_IMAGE}/${PN}-multiarch-oci/ | 25 | # ${DEPLOY_DIR_IMAGE}/${PN}-multiarch-oci/ |
| @@ -28,8 +28,8 @@ | |||
| 28 | # blobs/sha256/ - Combined blobs from all architectures | 28 | # blobs/sha256/ - Combined blobs from all architectures |
| 29 | # | 29 | # |
| 30 | # REQUIREMENTS: | 30 | # REQUIREMENTS: |
| 31 | # - Multiconfig must be enabled in local.conf: | 31 | # - Multiconfig must be enabled (meta-virt-host.conf provides defaults): |
| 32 | # BBMULTICONFIG = "vruntime-aarch64 vruntime-x86-64" | 32 | # BBMULTICONFIG = "... container-aarch64 container-x86-64" |
| 33 | # - OCI_MULTIARCH_RECIPE must inherit image-oci or produce OCI output | 33 | # - OCI_MULTIARCH_RECIPE must inherit image-oci or produce OCI output |
| 34 | # | 34 | # |
| 35 | # =========================================================================== | 35 | # =========================================================================== |
| @@ -42,9 +42,9 @@ INHIBIT_DEFAULT_DEPS = "1" | |||
| 42 | OCI_MULTIARCH_RECIPE ?= "" | 42 | OCI_MULTIARCH_RECIPE ?= "" |
| 43 | OCI_MULTIARCH_PLATFORMS ?= "" | 43 | OCI_MULTIARCH_PLATFORMS ?= "" |
| 44 | 44 | ||
| 45 | # Default multiconfig mapping (uses existing vruntime-* configs) | 45 | # Default multiconfig mapping (uses vcontainer distro -- no BBMASK) |
| 46 | OCI_MULTIARCH_MC[aarch64] ?= "vruntime-aarch64" | 46 | OCI_MULTIARCH_MC[aarch64] ?= "container-aarch64" |
| 47 | OCI_MULTIARCH_MC[x86_64] ?= "vruntime-x86-64" | 47 | OCI_MULTIARCH_MC[x86_64] ?= "container-x86-64" |
| 48 | 48 | ||
| 49 | # Machine mapping for deploy directory paths | 49 | # Machine mapping for deploy directory paths |
| 50 | OCI_MULTIARCH_MACHINE[aarch64] ?= "qemuarm64" | 50 | OCI_MULTIARCH_MACHINE[aarch64] ?= "qemuarm64" |
| @@ -87,7 +87,7 @@ python __anonymous() { | |||
| 87 | mc = d.getVarFlag('OCI_MULTIARCH_MC', platform) | 87 | mc = d.getVarFlag('OCI_MULTIARCH_MC', platform) |
| 88 | if not mc: | 88 | if not mc: |
| 89 | bb.fatal(f"No multiconfig defined for platform '{platform}'. Set OCI_MULTIARCH_MC[{platform}]") | 89 | bb.fatal(f"No multiconfig defined for platform '{platform}'. Set OCI_MULTIARCH_MC[{platform}]") |
| 90 | mcdepends.append(f"mc::{mc}:{recipe}:do_image_oci") | 90 | mcdepends.append(f"mc::{mc}:{recipe}:do_image_complete") |
| 91 | 91 | ||
| 92 | # Set the mcdepends for our main task | 92 | # Set the mcdepends for our main task |
| 93 | d.setVarFlag('do_create_multiarch_index', 'mcdepends', ' '.join(mcdepends)) | 93 | d.setVarFlag('do_create_multiarch_index', 'mcdepends', ' '.join(mcdepends)) |
| @@ -191,17 +191,40 @@ python do_create_multiarch_index() { | |||
| 191 | if not index_manifests: | 191 | if not index_manifests: |
| 192 | bb.fatal("No manifests collected - cannot create multi-arch index") | 192 | bb.fatal("No manifests collected - cannot create multi-arch index") |
| 193 | 193 | ||
| 194 | # Create the OCI Image Index | 194 | # Create the OCI Image Index as a blob (not directly in index.json). |
| 195 | # skopeo requires index.json to reference a single entry; the actual | ||
| 196 | # multi-platform manifest list lives in blobs/sha256/ and index.json | ||
| 197 | # points to it. | ||
| 195 | image_index = { | 198 | image_index = { |
| 196 | 'schemaVersion': 2, | 199 | 'schemaVersion': 2, |
| 197 | 'mediaType': 'application/vnd.oci.image.index.v1+json', | 200 | 'mediaType': 'application/vnd.oci.image.index.v1+json', |
| 198 | 'manifests': index_manifests | 201 | 'manifests': index_manifests |
| 199 | } | 202 | } |
| 200 | 203 | ||
| 201 | # Write index.json | 204 | image_index_json = json.dumps(image_index, indent=2).encode('utf-8') |
| 205 | image_index_digest = hashlib.sha256(image_index_json).hexdigest() | ||
| 206 | image_index_size = len(image_index_json) | ||
| 207 | |||
| 208 | # Write the image index as a blob | ||
| 209 | blob_path = os.path.join(output_dir, 'blobs', 'sha256', image_index_digest) | ||
| 210 | with open(blob_path, 'wb') as f: | ||
| 211 | f.write(image_index_json) | ||
| 212 | |||
| 213 | # Write index.json pointing to the image index blob | ||
| 214 | top_index = { | ||
| 215 | 'schemaVersion': 2, | ||
| 216 | 'manifests': [ | ||
| 217 | { | ||
| 218 | 'mediaType': 'application/vnd.oci.image.index.v1+json', | ||
| 219 | 'digest': f'sha256:{image_index_digest}', | ||
| 220 | 'size': image_index_size | ||
| 221 | } | ||
| 222 | ] | ||
| 223 | } | ||
| 224 | |||
| 202 | index_path = os.path.join(output_dir, 'index.json') | 225 | index_path = os.path.join(output_dir, 'index.json') |
| 203 | with open(index_path, 'w') as f: | 226 | with open(index_path, 'w') as f: |
| 204 | json.dump(image_index, f, indent=2) | 227 | json.dump(top_index, f, indent=2) |
| 205 | 228 | ||
| 206 | # Write oci-layout | 229 | # Write oci-layout |
| 207 | layout_path = os.path.join(output_dir, 'oci-layout') | 230 | layout_path = os.path.join(output_dir, 'oci-layout') |
diff --git a/recipes-extended/images/container-base-multiarch.bb b/recipes-extended/images/container-base-multiarch.bb new file mode 100644 index 00000000..220e3555 --- /dev/null +++ b/recipes-extended/images/container-base-multiarch.bb | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | SUMMARY = "Multi-architecture OCI container base image" | ||
| 2 | DESCRIPTION = "Builds container-base for multiple architectures and \ | ||
| 3 | combines them into a single OCI Image Index (manifest list)." | ||
| 4 | LICENSE = "MIT" | ||
| 5 | |||
| 6 | inherit oci-multiarch | ||
| 7 | |||
| 8 | OCI_MULTIARCH_RECIPE = "container-base" | ||
| 9 | OCI_MULTIARCH_PLATFORMS = "aarch64 x86_64" | ||
