diff options
| author | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-01-06 20:41:53 +0000 |
|---|---|---|
| committer | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-02-09 03:32:52 +0000 |
| commit | c32db56912b06a89490fda5d554468dbc12a39a2 (patch) | |
| tree | 8084bd9c1b56b13354cddf99b39356967f0142ea /recipes-containers/vcontainer/vcontainer-initramfs-create.inc | |
| parent | 4baa3503321fb2ad9edfebc5e89bcd37115e626e (diff) | |
| download | meta-virtualization-c32db56912b06a89490fda5d554468dbc12a39a2.tar.gz | |
vcontainer: add shared infrastructure and runner
Add core vcontainer infrastructure shared by vdkr and vpdmn:
Scripts:
- vrunner.sh: QEMU runner supporting both Docker and Podman runtimes
- vcontainer-common.sh: Shared CLI functions and command handling
- vcontainer-init-common.sh: Shared init script functions for QEMU guest
- vdkr-preinit.sh: Initramfs preinit for switch_root to squashfs overlay
Recipes:
- vcontainer-native: Installs vrunner.sh and shared scripts
- vcontainer-initramfs-create.inc: Shared initramfs build logic
Features:
- Docker/Podman-compatible commands: images, pull, load, save, run, exec
- Memory resident mode for fast command execution
- KVM acceleration when host matches target
- Interactive mode with volume mounts
- Squashfs rootfs with tmpfs overlay
Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
Diffstat (limited to 'recipes-containers/vcontainer/vcontainer-initramfs-create.inc')
| -rw-r--r-- | recipes-containers/vcontainer/vcontainer-initramfs-create.inc | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/recipes-containers/vcontainer/vcontainer-initramfs-create.inc b/recipes-containers/vcontainer/vcontainer-initramfs-create.inc new file mode 100644 index 00000000..a0930a68 --- /dev/null +++ b/recipes-containers/vcontainer/vcontainer-initramfs-create.inc | |||
| @@ -0,0 +1,237 @@ | |||
| 1 | # SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield | ||
| 2 | # | ||
| 3 | # SPDX-License-Identifier: MIT | ||
| 4 | # | ||
| 5 | # vcontainer-initramfs-create.inc | ||
| 6 | # =========================================================================== | ||
| 7 | # Shared code for building QEMU boot blobs (vdkr/vpdmn) | ||
| 8 | # =========================================================================== | ||
| 9 | # | ||
| 10 | # This .inc file contains common code for building boot blobs. | ||
| 11 | # Individual recipes (vdkr-initramfs-create, vpdmn-initramfs-create) | ||
| 12 | # set VCONTAINER_RUNTIME and include this file. | ||
| 13 | # | ||
| 14 | # Required variables from including recipe: | ||
| 15 | # VCONTAINER_RUNTIME - "vdkr" or "vpdmn" | ||
| 16 | # | ||
| 17 | # Boot flow: | ||
| 18 | # QEMU boots kernel + tiny initramfs | ||
| 19 | # -> preinit mounts rootfs.img from /dev/vda | ||
| 20 | # -> switch_root into rootfs.img | ||
| 21 | # -> ${VCONTAINER_RUNTIME}-init.sh runs | ||
| 22 | # | ||
| 23 | # =========================================================================== | ||
| 24 | |||
| 25 | HOMEPAGE = "https://git.yoctoproject.org/meta-virtualization/" | ||
| 26 | LICENSE = "MIT" | ||
| 27 | LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" | ||
| 28 | |||
| 29 | inherit deploy | ||
| 30 | |||
| 31 | # Not built by default - user must explicitly request via bitbake or vcontainer-native | ||
| 32 | EXCLUDE_FROM_WORLD = "1" | ||
| 33 | |||
| 34 | # Need squashfs-tools-native for unsquashfs to extract files from rootfs.img | ||
| 35 | DEPENDS = "squashfs-tools-native" | ||
| 36 | |||
| 37 | # Always rebuild - no sstate caching for this recipe | ||
| 38 | # This ensures source file changes (like init scripts in the rootfs) are picked up | ||
| 39 | SSTATE_SKIP_CREATION = "1" | ||
| 40 | do_compile[nostamp] = "1" | ||
| 41 | do_deploy[nostamp] = "1" | ||
| 42 | |||
| 43 | # Only populate native sysroot, skip target sysroot to avoid libgcc conflicts | ||
| 44 | INHIBIT_DEFAULT_DEPS = "1" | ||
| 45 | |||
| 46 | # Dependencies: | ||
| 47 | # 1. The multiconfig rootfs image from same vruntime-* multiconfig | ||
| 48 | # 2. The kernel from main build (not multiconfig) | ||
| 49 | # | ||
| 50 | # Use regular depends for rootfs-image since both recipes are in the same multiconfig | ||
| 51 | # Use mcdepends for kernel since it's from the main (default) config | ||
| 52 | do_compile[depends] = "${VCONTAINER_RUNTIME}-rootfs-image:do_image_complete" | ||
| 53 | do_compile[mcdepends] = "mc:${VCONTAINER_MULTICONFIG}::virtual/kernel:do_deploy" | ||
| 54 | |||
| 55 | # Preinit is shared between vdkr and vpdmn | ||
| 56 | SRC_URI = "file://vdkr-preinit.sh" | ||
| 57 | |||
| 58 | S = "${UNPACKDIR}" | ||
| 59 | B = "${WORKDIR}/build" | ||
| 60 | |||
| 61 | def get_kernel_image_name(d): | ||
| 62 | arch = d.getVar('TARGET_ARCH') | ||
| 63 | if arch == 'aarch64': | ||
| 64 | return 'Image' | ||
| 65 | elif arch in ['x86_64', 'i686', 'i586']: | ||
| 66 | return 'bzImage' | ||
| 67 | elif arch == 'arm': | ||
| 68 | return 'zImage' | ||
| 69 | return 'Image' | ||
| 70 | |||
| 71 | def get_multiconfig_name(d): | ||
| 72 | arch = d.getVar('TARGET_ARCH') | ||
| 73 | if arch == 'aarch64': | ||
| 74 | return 'vruntime-aarch64' | ||
| 75 | elif arch in ['x86_64', 'i686', 'i586']: | ||
| 76 | return 'vruntime-x86-64' | ||
| 77 | return 'vruntime-aarch64' | ||
| 78 | |||
| 79 | def get_blob_arch(d): | ||
| 80 | """Map TARGET_ARCH to vrunner blob architecture (aarch64 or x86_64)""" | ||
| 81 | arch = d.getVar('TARGET_ARCH') | ||
| 82 | if arch == 'aarch64': | ||
| 83 | return 'aarch64' | ||
| 84 | elif arch in ['x86_64', 'i686', 'i586']: | ||
| 85 | return 'x86_64' | ||
| 86 | return 'aarch64' | ||
| 87 | |||
| 88 | KERNEL_IMAGETYPE_INITRAMFS = "${@get_kernel_image_name(d)}" | ||
| 89 | VCONTAINER_MULTICONFIG = "${@get_multiconfig_name(d)}" | ||
| 90 | BLOB_ARCH = "${@get_blob_arch(d)}" | ||
| 91 | |||
| 92 | # Path to the multiconfig build output | ||
| 93 | VCONTAINER_MC_DEPLOY = "${TOPDIR}/tmp-${VCONTAINER_MULTICONFIG}/deploy/images/${MACHINE}" | ||
| 94 | |||
| 95 | do_compile() { | ||
| 96 | mkdir -p ${B} | ||
| 97 | |||
| 98 | # ========================================================================= | ||
| 99 | # PART 1: BUILD TINY INITRAMFS (just for switch_root) | ||
| 100 | # ========================================================================= | ||
| 101 | INITRAMFS_DIR="${B}/initramfs" | ||
| 102 | rm -rf ${INITRAMFS_DIR} | ||
| 103 | mkdir -p ${INITRAMFS_DIR}/bin | ||
| 104 | mkdir -p ${INITRAMFS_DIR}/proc | ||
| 105 | mkdir -p ${INITRAMFS_DIR}/sys | ||
| 106 | mkdir -p ${INITRAMFS_DIR}/dev | ||
| 107 | mkdir -p ${INITRAMFS_DIR}/mnt/root | ||
| 108 | |||
| 109 | bbnote "Building tiny initramfs for switch_root..." | ||
| 110 | |||
| 111 | # Extract busybox from the multiconfig rootfs image (squashfs) | ||
| 112 | MC_TMPDIR="${TOPDIR}/tmp-${VCONTAINER_MULTICONFIG}" | ||
| 113 | ROOTFS_SRC="${MC_TMPDIR}/deploy/images/${MACHINE}/${VCONTAINER_RUNTIME}-rootfs-image-${MACHINE}.rootfs.squashfs" | ||
| 114 | |||
| 115 | if [ ! -f "${ROOTFS_SRC}" ]; then | ||
| 116 | bbfatal "Rootfs image not found at ${ROOTFS_SRC}. Build it first with: bitbake mc:${VCONTAINER_MULTICONFIG}:${VCONTAINER_RUNTIME}-rootfs-image" | ||
| 117 | fi | ||
| 118 | |||
| 119 | # Extract busybox from rootfs using unsquashfs | ||
| 120 | # In usrmerge layouts, busybox is at usr/bin/busybox | ||
| 121 | BUSYBOX_PATH="usr/bin/busybox" | ||
| 122 | EXTRACT_DIR="${B}/squashfs-extract" | ||
| 123 | |||
| 124 | bbnote "Extracting busybox from $BUSYBOX_PATH" | ||
| 125 | # Try native sysroot first, fall back to system unsquashfs | ||
| 126 | UNSQUASHFS="${WORKDIR}/recipe-sysroot-native/usr/bin/unsquashfs" | ||
| 127 | if [ ! -x "$UNSQUASHFS" ]; then | ||
| 128 | UNSQUASHFS="/usr/bin/unsquashfs" | ||
| 129 | fi | ||
| 130 | if [ ! -x "$UNSQUASHFS" ]; then | ||
| 131 | bbfatal "unsquashfs not found in native sysroot or at /usr/bin/unsquashfs" | ||
| 132 | fi | ||
| 133 | bbnote "Using unsquashfs: $UNSQUASHFS" | ||
| 134 | |||
| 135 | rm -rf "${EXTRACT_DIR}" | ||
| 136 | $UNSQUASHFS -d "${EXTRACT_DIR}" "${ROOTFS_SRC}" "$BUSYBOX_PATH" | ||
| 137 | |||
| 138 | if [ ! -f "${EXTRACT_DIR}/${BUSYBOX_PATH}" ]; then | ||
| 139 | bbfatal "Failed to extract busybox from rootfs image" | ||
| 140 | fi | ||
| 141 | cp "${EXTRACT_DIR}/${BUSYBOX_PATH}" "${INITRAMFS_DIR}/bin/busybox" | ||
| 142 | chmod +x ${INITRAMFS_DIR}/bin/busybox | ||
| 143 | |||
| 144 | # Create minimal symlinks | ||
| 145 | cd ${INITRAMFS_DIR}/bin | ||
| 146 | for cmd in sh mount umount mkdir ls cat echo sleep switch_root reboot; do | ||
| 147 | ln -sf busybox $cmd 2>/dev/null || true | ||
| 148 | done | ||
| 149 | cd - | ||
| 150 | |||
| 151 | # Install preinit script as /init | ||
| 152 | cp ${S}/vdkr-preinit.sh ${INITRAMFS_DIR}/init | ||
| 153 | chmod +x ${INITRAMFS_DIR}/init | ||
| 154 | |||
| 155 | # Create tiny initramfs cpio | ||
| 156 | bbnote "Creating tiny initramfs cpio archive..." | ||
| 157 | cd ${INITRAMFS_DIR} | ||
| 158 | find . | cpio -o -H newc 2>/dev/null | gzip -9 > ${B}/initramfs.cpio.gz | ||
| 159 | cd - | ||
| 160 | |||
| 161 | INITRAMFS_SIZE=$(stat -c%s ${B}/initramfs.cpio.gz) | ||
| 162 | bbnote "Tiny initramfs created: ${INITRAMFS_SIZE} bytes ($(expr ${INITRAMFS_SIZE} / 1024)KB)" | ||
| 163 | |||
| 164 | # ========================================================================= | ||
| 165 | # PART 2: COPY ROOTFS FROM MULTICONFIG BUILD | ||
| 166 | # ========================================================================= | ||
| 167 | bbnote "Looking for multiconfig rootfs at: ${MC_TMPDIR}/deploy/images/${MACHINE}" | ||
| 168 | |||
| 169 | # ROOTFS_SRC already set above when extracting busybox | ||
| 170 | cp "${ROOTFS_SRC}" ${B}/rootfs.img | ||
| 171 | ROOTFS_SIZE=$(stat -c%s ${B}/rootfs.img) | ||
| 172 | bbnote "Rootfs image copied: ${ROOTFS_SIZE} bytes ($(expr ${ROOTFS_SIZE} / 1024 / 1024)MB)" | ||
| 173 | |||
| 174 | # ========================================================================= | ||
| 175 | # PART 3: COPY KERNEL | ||
| 176 | # ========================================================================= | ||
| 177 | bbnote "Copying kernel image..." | ||
| 178 | KERNEL_FILE="${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE_INITRAMFS}" | ||
| 179 | if [ -f "${KERNEL_FILE}" ]; then | ||
| 180 | cp "${KERNEL_FILE}" ${B}/kernel | ||
| 181 | KERNEL_SIZE=$(stat -c%s ${B}/kernel) | ||
| 182 | bbnote "Kernel copied: ${KERNEL_SIZE} bytes ($(expr ${KERNEL_SIZE} / 1024 / 1024)MB)" | ||
| 183 | else | ||
| 184 | bbwarn "Kernel not found at ${KERNEL_FILE}" | ||
| 185 | fi | ||
| 186 | } | ||
| 187 | |||
| 188 | do_install[noexec] = "1" | ||
| 189 | do_package[noexec] = "1" | ||
| 190 | do_packagedata[noexec] = "1" | ||
| 191 | do_package_write_rpm[noexec] = "1" | ||
| 192 | do_package_write_ipk[noexec] = "1" | ||
| 193 | do_package_write_deb[noexec] = "1" | ||
| 194 | do_populate_sysroot[noexec] = "1" | ||
| 195 | |||
| 196 | do_deploy() { | ||
| 197 | # Deploy to ${VCONTAINER_RUNTIME}/<arch> subdirectory | ||
| 198 | install -d ${DEPLOYDIR}/${VCONTAINER_RUNTIME}/${BLOB_ARCH} | ||
| 199 | |||
| 200 | if [ -f ${B}/initramfs.cpio.gz ]; then | ||
| 201 | install -m 0644 ${B}/initramfs.cpio.gz ${DEPLOYDIR}/${VCONTAINER_RUNTIME}/${BLOB_ARCH}/ | ||
| 202 | bbnote "Deployed initramfs.cpio.gz to ${VCONTAINER_RUNTIME}/${BLOB_ARCH}/" | ||
| 203 | fi | ||
| 204 | |||
| 205 | if [ -f ${B}/rootfs.img ]; then | ||
| 206 | install -m 0644 ${B}/rootfs.img ${DEPLOYDIR}/${VCONTAINER_RUNTIME}/${BLOB_ARCH}/ | ||
| 207 | bbnote "Deployed rootfs.img to ${VCONTAINER_RUNTIME}/${BLOB_ARCH}/" | ||
| 208 | fi | ||
| 209 | |||
| 210 | if [ -f ${B}/kernel ]; then | ||
| 211 | install -m 0644 ${B}/kernel ${DEPLOYDIR}/${VCONTAINER_RUNTIME}/${BLOB_ARCH}/${KERNEL_IMAGETYPE_INITRAMFS} | ||
| 212 | bbnote "Deployed kernel as ${VCONTAINER_RUNTIME}/${BLOB_ARCH}/${KERNEL_IMAGETYPE_INITRAMFS}" | ||
| 213 | fi | ||
| 214 | |||
| 215 | cat > ${DEPLOYDIR}/${VCONTAINER_RUNTIME}/${BLOB_ARCH}/README << EOF | ||
| 216 | ${VCONTAINER_RUNTIME} Boot Blobs | ||
| 217 | ================== | ||
| 218 | |||
| 219 | Built for: ${TARGET_ARCH} | ||
| 220 | Machine: ${MACHINE} | ||
| 221 | Multiconfig: ${VCONTAINER_MULTICONFIG} | ||
| 222 | Date: $(date) | ||
| 223 | |||
| 224 | Files: | ||
| 225 | ${KERNEL_IMAGETYPE_INITRAMFS} - Kernel image for QEMU | ||
| 226 | initramfs.cpio.gz - Tiny initramfs (switch_root only) | ||
| 227 | rootfs.img - Root filesystem with container tools | ||
| 228 | |||
| 229 | Boot flow: | ||
| 230 | QEMU boots kernel + initramfs | ||
| 231 | -> preinit mounts rootfs.img from /dev/vda | ||
| 232 | -> switch_root into rootfs.img | ||
| 233 | -> ${VCONTAINER_RUNTIME}-init.sh runs container commands | ||
| 234 | EOF | ||
| 235 | } | ||
| 236 | |||
| 237 | addtask deploy after do_compile before do_build | ||
