diff options
| author | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-01-01 17:14:05 +0000 |
|---|---|---|
| committer | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-02-09 03:32:52 +0000 |
| commit | 79d03d5350c446223c847135c7115a656adc01d9 (patch) | |
| tree | 4c988222e2de61d49ce592de0d40175ee61400cd /recipes-extended | |
| parent | 0cdb55047d352ccfffcf76d242ca132315bd0659 (diff) | |
| download | meta-virtualization-79d03d5350c446223c847135c7115a656adc01d9.tar.gz | |
container-bundle: add package-based container bundling support
This class creates installable packages that bundle pre-processed
container images. When installed via IMAGE_INSTALL, containers are
automatically merged into the target image's container storage.
Component relationships for bundling a local container:
1. Application Recipe (builds the software)
recipes-demo/myapp/myapp_1.0.bb
- Compiles application binaries
- Creates installable package (myapp)
2. Container Image Recipe (creates OCI image containing the app)
recipes-demo/images/myapp-container.bb
- inherit image image-oci
- IMAGE_INSTALL = "myapp"
- Produces: ${DEPLOY_DIR_IMAGE}/myapp-container-latest-oci/
3. Bundle Recipe (packages container images for deployment)
recipes-demo/bundles/my-bundle_1.0.bb
- inherit container-bundle
- CONTAINER_BUNDLES = "myapp-container:autostart"
- Creates installable package with OCI data
Flow: application recipe -> container image recipe -> bundle recipe
-> IMAGE_INSTALL in host image -> container deployed on target
Usage:
inherit container-bundle
CONTAINER_BUNDLES = "myapp-container:autostart redis-container"
CONTAINER_BUNDLES format: source[:autostart-policy]
- source: Container IMAGE recipe name or remote registry URL
- autostart-policy: Optional (autostart, always, unless-stopped, on-failure)
Features:
- Auto-generates dependencies on container image recipes (do_image_complete)
- Supports remote containers via skopeo (requires CONTAINER_DIGESTS)
- Runtime auto-detected from CONTAINER_PROFILE (docker/podman)
- Produces OCI directories and metadata for container-cross-install
Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
Diffstat (limited to 'recipes-extended')
| -rw-r--r-- | recipes-extended/container-bundles/example-container-bundle_1.0.bb | 68 | ||||
| -rw-r--r-- | recipes-extended/container-bundles/remote-container-bundle_1.0.bb | 50 |
2 files changed, 118 insertions, 0 deletions
diff --git a/recipes-extended/container-bundles/example-container-bundle_1.0.bb b/recipes-extended/container-bundles/example-container-bundle_1.0.bb new file mode 100644 index 00000000..a91e4609 --- /dev/null +++ b/recipes-extended/container-bundles/example-container-bundle_1.0.bb | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | # example-container-bundle_1.0.bb | ||
| 2 | # =========================================================================== | ||
| 3 | # Example container bundle recipe demonstrating container-bundle.bbclass | ||
| 4 | # =========================================================================== | ||
| 5 | # | ||
| 6 | # This recipe shows how to create a package that bundles containers. | ||
| 7 | # When installed via IMAGE_INSTALL, the containers are automatically | ||
| 8 | # merged into the target image's container storage. | ||
| 9 | # | ||
| 10 | # Usage in image recipe (e.g., container-image-host.bb): | ||
| 11 | # IMAGE_INSTALL += "example-container-bundle" | ||
| 12 | # | ||
| 13 | # Or in local.conf (use pn- override for specific images): | ||
| 14 | # IMAGE_INSTALL:append:pn-container-image-host = " example-container-bundle" | ||
| 15 | # | ||
| 16 | # IMPORTANT: Do NOT use global IMAGE_INSTALL:append without pn- override! | ||
| 17 | # This causes circular dependencies when container images try to include | ||
| 18 | # the bundle that depends on them. | ||
| 19 | # | ||
| 20 | # =========================================================================== | ||
| 21 | |||
| 22 | SUMMARY = "Example container bundle" | ||
| 23 | DESCRIPTION = "Demonstrates container-bundle.bbclass by bundling the \ | ||
| 24 | container-base image. Use this as a template for your \ | ||
| 25 | own container bundles." | ||
| 26 | HOMEPAGE = "https://github.com/anthropics/meta-virtualization" | ||
| 27 | LICENSE = "MIT" | ||
| 28 | LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" | ||
| 29 | |||
| 30 | inherit container-bundle | ||
| 31 | |||
| 32 | # Define containers to bundle | ||
| 33 | # Format: source[:autostart-policy] | ||
| 34 | # | ||
| 35 | # source: Either a local recipe name or registry URL | ||
| 36 | # - Local: "container-base" (simple recipe name) | ||
| 37 | # - Remote: "docker.io/library/alpine:3.19" (registry URL) | ||
| 38 | # | ||
| 39 | # autostart: (optional) autostart | always | unless-stopped | on-failure | ||
| 40 | # | ||
| 41 | # Runtime is determined automatically from CONTAINER_PROFILE (or CONTAINER_BUNDLE_RUNTIME) | ||
| 42 | |||
| 43 | # Bundle the test containers we've been using: | ||
| 44 | # - container-base: minimal busybox container | ||
| 45 | # - container-app-base: busybox with app structure | ||
| 46 | # - autostart-test-container: container that logs startup for autostart testing | ||
| 47 | CONTAINER_BUNDLES = "\ | ||
| 48 | container-base \ | ||
| 49 | container-app-base \ | ||
| 50 | autostart-test-container:autostart \ | ||
| 51 | " | ||
| 52 | |||
| 53 | # Override runtime if needed (uncomment to force a specific runtime): | ||
| 54 | # CONTAINER_BUNDLE_RUNTIME = "podman" | ||
| 55 | |||
| 56 | # For remote containers (not used in this example), you MUST provide digests: | ||
| 57 | # CONTAINER_DIGESTS[docker.io/library/redis:7] = "sha256:e422889e156e..." | ||
| 58 | # | ||
| 59 | # Get the digest with: | ||
| 60 | # skopeo inspect docker://docker.io/library/redis:7 | jq -r '.Digest' | ||
| 61 | |||
| 62 | # Example with multiple containers and autostart: | ||
| 63 | # CONTAINER_BUNDLES = "\ | ||
| 64 | # myapp:autostart \ | ||
| 65 | # mydb \ | ||
| 66 | # docker.io/library/redis:7 \ | ||
| 67 | # " | ||
| 68 | # CONTAINER_DIGESTS[docker.io/library/redis:7] = "sha256:e422889..." | ||
diff --git a/recipes-extended/container-bundles/remote-container-bundle_1.0.bb b/recipes-extended/container-bundles/remote-container-bundle_1.0.bb new file mode 100644 index 00000000..7da267e5 --- /dev/null +++ b/recipes-extended/container-bundles/remote-container-bundle_1.0.bb | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | # SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield | ||
| 2 | # | ||
| 3 | # SPDX-License-Identifier: MIT | ||
| 4 | # | ||
| 5 | # remote-container-bundle_1.0.bb | ||
| 6 | # =========================================================================== | ||
| 7 | # Test recipe for remote container fetching via container-bundle.bbclass | ||
| 8 | # =========================================================================== | ||
| 9 | # | ||
| 10 | # This recipe demonstrates and tests fetching containers from a remote | ||
| 11 | # registry during the Yocto build. The container is pulled via skopeo | ||
| 12 | # and bundled into a package that can be installed into target images. | ||
| 13 | # | ||
| 14 | # Usage in image recipe: | ||
| 15 | # IMAGE_INSTALL += "remote-container-bundle" | ||
| 16 | # | ||
| 17 | # Or in local.conf: | ||
| 18 | # IMAGE_INSTALL:append:pn-container-image-host = " remote-container-bundle" | ||
| 19 | # | ||
| 20 | # The container will be available as "busybox:1.36" in the target's | ||
| 21 | # Docker/Podman storage after boot. | ||
| 22 | # | ||
| 23 | # =========================================================================== | ||
| 24 | |||
| 25 | SUMMARY = "Remote container bundle test" | ||
| 26 | DESCRIPTION = "Tests container-bundle.bbclass remote container fetching. \ | ||
| 27 | Pulls busybox from docker.io and bundles it for installation." | ||
| 28 | HOMEPAGE = "https://github.com/anthropics/meta-virtualization" | ||
| 29 | LICENSE = "MIT" | ||
| 30 | LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" | ||
| 31 | |||
| 32 | inherit container-bundle | ||
| 33 | |||
| 34 | # Remote container from Docker Hub | ||
| 35 | # Using busybox as it's small (~2MB) and available for multiple architectures | ||
| 36 | CONTAINER_BUNDLES = "\ | ||
| 37 | docker.io/library/busybox:1.36 \ | ||
| 38 | " | ||
| 39 | |||
| 40 | # REQUIRED: Pinned digest for reproducible builds | ||
| 41 | # Get with: skopeo inspect docker://docker.io/library/busybox:1.36 | jq -r '.Digest' | ||
| 42 | # Note: This is the multi-arch manifest digest, skopeo will select the correct arch | ||
| 43 | # Key format: Replace / and : with _ for BitBake variable flag compatibility | ||
| 44 | CONTAINER_DIGESTS[docker.io_library_busybox_1.36] = "sha256:768e5c6f5cb6db0794eec98dc7a967f40631746c32232b78a3105fb946f3ab83" | ||
| 45 | |||
| 46 | # Note: busybox is GPL-licensed, so no LICENSE_FLAGS needed. | ||
| 47 | # For containers with commercial licenses, you would add: | ||
| 48 | # LICENSE_FLAGS:append = " commercial" | ||
| 49 | # And accept in local.conf: | ||
| 50 | # LICENSE_FLAGS_ACCEPTED:append = " commercial" | ||
