From 18074e0efe255a43ab9155171d08aa6e0d736b5f Mon Sep 17 00:00:00 2001 From: Bruce Ashfield Date: Tue, 6 Jan 2026 20:42:46 +0000 Subject: vcontainer: add vdkr Docker support Add vdkr - Docker CLI wrapper for cross-architecture container operations: Scripts: - vdkr.sh: Docker CLI entry point (vdkr-x86_64, vdkr-aarch64) - vdkr-init.sh: Docker init script for QEMU guest Recipes: - vdkr-native: Installs vdkr CLI wrappers - vdkr-rootfs-image: Builds Docker rootfs with containerd, runc, skopeo - vdkr-initramfs-create: Creates bootable initramfs blob The vdkr CLI provides Docker-compatible commands executed inside a QEMU-emulated environment, enabling cross-architecture container operations during Yocto builds. Signed-off-by: Bruce Ashfield --- .../vcontainer/files/blobs/vdkr/aarch64/README | 26 +++ .../vcontainer/files/blobs/vdkr/x86_64/README | 26 +++ recipes-containers/vcontainer/files/vdkr-init.sh | 238 +++++++++++++++++++++ recipes-containers/vcontainer/files/vdkr.sh | 25 +++ .../vcontainer/vdkr-initramfs-create_1.0.bb | 46 ++++ recipes-containers/vcontainer/vdkr-native_1.0.bb | 191 +++++++++++++++++ recipes-containers/vcontainer/vdkr-rootfs-image.bb | 74 +++++++ 7 files changed, 626 insertions(+) create mode 100644 recipes-containers/vcontainer/files/blobs/vdkr/aarch64/README create mode 100644 recipes-containers/vcontainer/files/blobs/vdkr/x86_64/README create mode 100755 recipes-containers/vcontainer/files/vdkr-init.sh create mode 100755 recipes-containers/vcontainer/files/vdkr.sh create mode 100644 recipes-containers/vcontainer/vdkr-initramfs-create_1.0.bb create mode 100644 recipes-containers/vcontainer/vdkr-native_1.0.bb create mode 100644 recipes-containers/vcontainer/vdkr-rootfs-image.bb diff --git a/recipes-containers/vcontainer/files/blobs/vdkr/aarch64/README b/recipes-containers/vcontainer/files/blobs/vdkr/aarch64/README new file mode 100644 index 00000000..cabb5100 --- /dev/null +++ b/recipes-containers/vcontainer/files/blobs/vdkr/aarch64/README @@ -0,0 +1,26 @@ +vdkr aarch64 Blobs +==================== + +This directory should contain the boot blobs for vdkr aarch64: + +Required files: + - Image : Linux kernel for aarch64 + - initramfs.cpio.gz : Tiny initramfs for switch_root + - rootfs.img : Ext4 root filesystem with Docker tools + +Build instructions: + 1. Set MACHINE for aarch64: + MACHINE=qemuarm64 + + 2. Build the blobs: + bitbake vdkr-initramfs-create + + 3. Copy from deploy directory: + cp tmp/deploy/images/qemuarm64/vdkr/aarch64/Image . + cp tmp/deploy/images/qemuarm64/vdkr/aarch64/initramfs.cpio.gz . + cp tmp/deploy/images/qemuarm64/vdkr/aarch64/rootfs.img . + +Once these files are present, vdkr-native will automatically include them. + +Alternatively, set VDKR_USE_DEPLOY = "1" in local.conf to use blobs +directly from DEPLOY_DIR without copying to the layer. diff --git a/recipes-containers/vcontainer/files/blobs/vdkr/x86_64/README b/recipes-containers/vcontainer/files/blobs/vdkr/x86_64/README new file mode 100644 index 00000000..6902f729 --- /dev/null +++ b/recipes-containers/vcontainer/files/blobs/vdkr/x86_64/README @@ -0,0 +1,26 @@ +vdkr x86_64 Blobs +=================== + +This directory should contain the boot blobs for vdkr x86_64: + +Required files: + - bzImage : Linux kernel for x86_64 + - initramfs.cpio.gz : Tiny initramfs for switch_root + - rootfs.img : Ext4 root filesystem with Docker tools + +Build instructions: + 1. Set MACHINE for x86_64: + MACHINE=qemux86-64 + + 2. Build the blobs: + bitbake vdkr-initramfs-create + + 3. Copy from deploy directory: + cp tmp/deploy/images/qemux86-64/vdkr/x86_64/bzImage . + cp tmp/deploy/images/qemux86-64/vdkr/x86_64/initramfs.cpio.gz . + cp tmp/deploy/images/qemux86-64/vdkr/x86_64/rootfs.img . + +Once these files are present, vdkr-native will automatically include them. + +Alternatively, set VDKR_USE_DEPLOY = "1" in local.conf to use blobs +directly from DEPLOY_DIR without copying to the layer. diff --git a/recipes-containers/vcontainer/files/vdkr-init.sh b/recipes-containers/vcontainer/files/vdkr-init.sh new file mode 100755 index 00000000..7cfe12af --- /dev/null +++ b/recipes-containers/vcontainer/files/vdkr-init.sh @@ -0,0 +1,238 @@ +#!/bin/sh +# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield +# +# SPDX-License-Identifier: GPL-2.0-only +# +# vdkr-init.sh +# Init script for vdkr: execute arbitrary docker commands in QEMU +# +# This script runs on a real ext4 filesystem after switch_root from initramfs. +# The preinit script mounted /dev/vda (rootfs.img) and did switch_root to us. +# +# Drive layout (rootfs.img is always /dev/vda, mounted as /): +# /dev/vda = rootfs.img (this script runs from here, mounted as /) +# /dev/vdb = input disk (optional, OCI/tar/dir data) +# /dev/vdc = state disk (optional, persistent Docker storage) +# +# Kernel parameters: +# docker_cmd= Base64-encoded docker command + args +# docker_input= Input type: none, oci, tar, dir (default: none) +# docker_output= Output type: text, tar, storage (default: text) +# docker_state= State type: none, disk (default: none) +# docker_network=1 Enable networking (configure eth0, DNS) +# +# Version: 2.3.0 + +# Set runtime-specific parameters before sourcing common code +VCONTAINER_RUNTIME_NAME="vdkr" +VCONTAINER_RUNTIME_CMD="docker" +VCONTAINER_RUNTIME_PREFIX="docker" +VCONTAINER_STATE_DIR="/var/lib/docker" +VCONTAINER_SHARE_NAME="vdkr_share" +VCONTAINER_VERSION="2.3.0" + +# Source common init functions +# When installed as /init, common file is at /vcontainer-init-common.sh +. /vcontainer-init-common.sh + +# ============================================================================ +# Docker-Specific Functions +# ============================================================================ + +setup_docker_storage() { + mkdir -p /run/containerd /run/lock + mkdir -p /var/lib/docker + mkdir -p /var/lib/containerd + + # Handle Docker storage + if [ -n "$STATE_DISK" ] && [ -b "$STATE_DISK" ]; then + log "Mounting state disk $STATE_DISK as /var/lib/docker..." + if mount -t ext4 "$STATE_DISK" /var/lib/docker 2>&1; then + log "SUCCESS: Mounted $STATE_DISK as Docker storage" + log "Docker storage contents:" + [ "$QUIET_BOOT" = "0" ] && ls -la /var/lib/docker/ 2>/dev/null || log "(empty)" + else + log "WARNING: Failed to mount state disk, using tmpfs" + RUNTIME_STATE="none" + fi + fi + + # If no state disk, use tmpfs for Docker storage + if [ "$RUNTIME_STATE" != "disk" ]; then + log "Using tmpfs for Docker storage (ephemeral)..." + mount -t tmpfs -o size=1G tmpfs /var/lib/docker + fi +} + +start_containerd() { + CONTAINERD_READY=false + if [ -x "/usr/bin/containerd" ]; then + log "Starting containerd..." + mkdir -p /var/lib/containerd + mkdir -p /run/containerd + /usr/bin/containerd --log-level info --root /var/lib/containerd --state /run/containerd >/tmp/containerd.log 2>&1 & + CONTAINERD_PID=$! + # Wait for containerd socket + for i in 1 2 3 4 5 6 7 8 9 10; do + if [ -S /run/containerd/containerd.sock ]; then + log "Containerd running (PID: $CONTAINERD_PID)" + CONTAINERD_READY=true + break + fi + sleep 1 + done + if [ "$CONTAINERD_READY" != "true" ]; then + log "WARNING: Containerd failed to start, check /tmp/containerd.log" + [ -f /tmp/containerd.log ] && cat /tmp/containerd.log >&2 + fi + fi +} + +start_dockerd() { + log "Starting Docker daemon..." + DOCKER_OPTS="--data-root=/var/lib/docker" + DOCKER_OPTS="$DOCKER_OPTS --storage-driver=overlay2" + DOCKER_OPTS="$DOCKER_OPTS --iptables=false" + DOCKER_OPTS="$DOCKER_OPTS --userland-proxy=false" + DOCKER_OPTS="$DOCKER_OPTS --bridge=none" + DOCKER_OPTS="$DOCKER_OPTS --host=unix:///var/run/docker.sock" + DOCKER_OPTS="$DOCKER_OPTS --exec-opt native.cgroupdriver=cgroupfs" + DOCKER_OPTS="$DOCKER_OPTS --log-level=info" + + if [ "$CONTAINERD_READY" = "true" ]; then + DOCKER_OPTS="$DOCKER_OPTS --containerd=/run/containerd/containerd.sock" + fi + + /usr/bin/dockerd $DOCKER_OPTS >/dev/null 2>&1 & + DOCKER_PID=$! + log "Docker daemon started (PID: $DOCKER_PID)" + + # Wait for Docker to be ready + log "Waiting for Docker daemon..." + DOCKER_READY=false + + sleep 5 + + for i in $(seq 1 60); do + if ! kill -0 $DOCKER_PID 2>/dev/null; then + echo "===ERROR===" + echo "Docker daemon died after $i iterations" + cat /var/log/docker.log 2>/dev/null || true + dmesg | tail -20 2>/dev/null || true + sleep 2 + reboot -f + fi + + if /usr/bin/docker info >/dev/null 2>&1; then + log "Docker daemon is ready!" + DOCKER_READY=true + break + fi + + log "Waiting... ($i/60)" + sleep 2 + done + + if [ "$DOCKER_READY" != "true" ]; then + echo "===ERROR===" + echo "Docker failed to start" + sleep 2 + reboot -f + fi +} + +stop_runtime_daemons() { + # Stop Docker daemon + if [ -n "$DOCKER_PID" ]; then + log "Stopping Docker daemon..." + kill $DOCKER_PID 2>/dev/null || true + for i in $(seq 1 10); do + if ! kill -0 $DOCKER_PID 2>/dev/null; then + log "Docker daemon stopped" + break + fi + sleep 1 + done + fi + + # Stop containerd + if [ -n "$CONTAINERD_PID" ]; then + log "Stopping containerd..." + kill $CONTAINERD_PID 2>/dev/null || true + sleep 2 + fi +} + +handle_storage_output() { + echo "Stopping Docker gracefully..." + /usr/bin/docker system prune -f >/dev/null 2>&1 || true + kill $DOCKER_PID 2>/dev/null || true + [ -n "$CONTAINERD_PID" ] && kill $CONTAINERD_PID 2>/dev/null || true + sleep 3 + + echo "Packaging Docker storage..." + cd /var/lib + tar -cf /tmp/storage.tar docker/ + + STORAGE_SIZE=$(stat -c%s /tmp/storage.tar 2>/dev/null || echo "0") + echo "Storage size: $STORAGE_SIZE bytes" + + if [ "$STORAGE_SIZE" -gt 1000 ]; then + dmesg -n 1 + echo "===STORAGE_START===" + base64 /tmp/storage.tar + echo "===STORAGE_END===" + echo "===EXIT_CODE=$EXEC_EXIT_CODE===" + else + echo "===ERROR===" + echo "Storage too small" + fi +} + +# ============================================================================ +# Main +# ============================================================================ + +# Initialize base environment +setup_base_environment +mount_base_filesystems + +# Check for quiet boot mode +check_quiet_boot + +log "=== vdkr Init ===" +log "Version: $VCONTAINER_VERSION" + +# Mount tmpfs directories and cgroups +mount_tmpfs_dirs +setup_cgroups + +# Parse kernel command line +parse_cmdline + +# Detect and configure disks +detect_disks + +# Set up Docker storage (Docker-specific) +setup_docker_storage + +# Mount input disk +mount_input_disk + +# Configure networking +configure_networking + +# Start containerd and dockerd (Docker-specific) +start_containerd +start_dockerd + +# Handle daemon mode or single command execution +if [ "$RUNTIME_DAEMON" = "1" ]; then + run_daemon_mode +else + prepare_input_path + execute_command +fi + +# Graceful shutdown +graceful_shutdown diff --git a/recipes-containers/vcontainer/files/vdkr.sh b/recipes-containers/vcontainer/files/vdkr.sh new file mode 100755 index 00000000..818c831e --- /dev/null +++ b/recipes-containers/vcontainer/files/vdkr.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield +# +# SPDX-License-Identifier: GPL-2.0-only +# +# vdkr: Docker-like interface for cross-architecture container operations +# +# This provides a familiar docker-like CLI that executes commands inside +# a QEMU-emulated environment with the target architecture's Docker. +# +# Command naming convention: +# - Commands matching Docker's syntax/semantics use Docker's name (import, load, save, etc.) +# - Extended commands with non-Docker behavior use 'v' prefix (vimport) + +# Set runtime-specific parameters before sourcing common code +VCONTAINER_RUNTIME_NAME="vdkr" +VCONTAINER_RUNTIME_CMD="docker" +VCONTAINER_RUNTIME_PREFIX="VDKR" +VCONTAINER_IMPORT_TARGET="docker-daemon:" +VCONTAINER_STATE_FILE="docker-state.img" +VCONTAINER_OTHER_PREFIX="VPDMN" +VCONTAINER_VERSION="3.4.0" + +# Source common implementation +source "$(dirname "${BASH_SOURCE[0]}")/vcontainer-common.sh" "$@" diff --git a/recipes-containers/vcontainer/vdkr-initramfs-create_1.0.bb b/recipes-containers/vcontainer/vdkr-initramfs-create_1.0.bb new file mode 100644 index 00000000..0d665f4a --- /dev/null +++ b/recipes-containers/vcontainer/vdkr-initramfs-create_1.0.bb @@ -0,0 +1,46 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield +# +# SPDX-License-Identifier: MIT +# +# vdkr-initramfs-create_1.0.bb +# =========================================================================== +# Builds QEMU boot blobs for vdkr (Docker CLI) +# =========================================================================== +# +# This recipe packages the boot blobs for vdkr: +# - A tiny initramfs with just busybox for switch_root +# - The rootfs.img squashfs image (built via multiconfig) +# - The kernel +# +# Boot flow: +# QEMU boots kernel + tiny initramfs +# -> preinit mounts rootfs.img from /dev/vda +# -> switch_root into rootfs.img +# -> vdkr-init.sh runs with a real root filesystem +# -> Docker can use pivot_root properly +# +# =========================================================================== +# BUILD INSTRUCTIONS +# =========================================================================== +# +# For aarch64 (multiconfig dependency is automatic): +# MACHINE=qemuarm64 bitbake vdkr-initramfs-create +# +# For x86_64: +# MACHINE=qemux86-64 bitbake vdkr-initramfs-create +# +# Blobs are deployed to: tmp-vruntime-*/deploy/images/${MACHINE}/vdkr/ +# +# To build the complete standalone tarball (recommended): +# MACHINE=qemux86-64 bitbake vcontainer-native -c create_tarball +# +# =========================================================================== + +SUMMARY = "Build QEMU blobs for vdkr" +DESCRIPTION = "Packages a tiny initramfs for switch_root and bundles the \ + rootfs.img from multiconfig build for vdkr." + +# Set the runtime before including shared code +VCONTAINER_RUNTIME = "vdkr" + +require vcontainer-initramfs-create.inc diff --git a/recipes-containers/vcontainer/vdkr-native_1.0.bb b/recipes-containers/vcontainer/vdkr-native_1.0.bb new file mode 100644 index 00000000..a6a56ecb --- /dev/null +++ b/recipes-containers/vcontainer/vdkr-native_1.0.bb @@ -0,0 +1,191 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield +# +# SPDX-License-Identifier: MIT +# +# vdkr-native_1.0.bb +# =========================================================================== +# Emulated Docker for cross-architecture container operations +# =========================================================================== +# +# vdkr provides a Docker-like CLI that executes arbitrary docker commands +# inside a QEMU-emulated environment with the target architecture's Docker +# daemon. Commands like "docker load", "docker export", "docker images" etc +# are passed through to Docker running inside QEMU and results streamed back. +# +# vdkr uses its own initramfs (built by vdkr-initramfs-create) which +# has vdkr-init.sh baked in. This is separate from container-cross-install. +# +# USAGE: +# vdkr images # Uses detected default arch +# vdkr -a aarch64 images # Explicit arch +# vdkr-aarch64 images # Symlink (backwards compatible) +# vdkr-x86_64 load -i myimage.tar +# +# Architecture detection (in priority order): +# 1. --arch / -a flag +# 2. Executable name (vdkr-aarch64, vdkr-x86_64) +# 3. VDKR_ARCH environment variable +# 4. Config file: ~/.config/vdkr/arch +# 5. Host architecture (uname -m) +# +# DEPENDENCIES: +# - Kernel/initramfs blobs from vdkr-initramfs-create +# - QEMU system emulator (qemu-system-native) +# +# =========================================================================== + +SUMMARY = "Emulated Docker for cross-architecture container operations" +DESCRIPTION = "Provides vdkr CLI that executes docker commands inside \ + QEMU-emulated environment. Useful for building/manipulating \ + containers for target architectures on a different host." +HOMEPAGE = "https://github.com/anthropics/meta-virtualization" +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" + +inherit native + +# Dependencies +DEPENDS = "qemu-system-native coreutils-native socat-native" + +# vdkr-init.sh is now baked into the initramfs, not installed separately +SRC_URI = "\ + file://vdkr.sh \ + file://vrunner.sh \ +" + +# Pre-built blobs are optional - they're checked into the layer after being +# built by vdkr-initramfs-build. If not present, vdkr will still build +# but will require --blob-dir at runtime. +# +# To build blobs: +# MACHINE=qemuarm64 bitbake vdkr-initramfs-build +# MACHINE=qemux86-64 bitbake vdkr-initramfs-build +# Then copy from tmp/deploy/images//vdkr-initramfs/ to files/blobs/vdkr// +# +# For development, set VDKR_USE_DEPLOY = "1" in local.conf to use blobs +# directly from DEPLOY_DIR instead of copying to layer. + +FILESEXTRAPATHS:prepend := "${THISDIR}/files:" + +# Layer directory containing optional blobs +VDKR_LAYER_BLOBS = "${THISDIR}/files/blobs/vdkr" + +# Deploy directories (used when VDKR_USE_DEPLOY = "1") +VDKR_DEPLOY_AARCH64 = "${DEPLOY_DIR}/images/qemuarm64/vdkr-initramfs" +VDKR_DEPLOY_X86_64 = "${DEPLOY_DIR}/images/qemux86-64/vdkr-initramfs" + +# Set to "1" in local.conf to prefer DEPLOY_DIR blobs over layer +VDKR_USE_DEPLOY ?= "0" + +S = "${UNPACKDIR}" + +do_install() { + # Install vdkr main script and architecture symlinks + install -d ${D}${bindir} + install -d ${D}${bindir}/vdkr-blobs/aarch64 + install -d ${D}${bindir}/vdkr-blobs/x86_64 + + # Install main vdkr script (arch detected at runtime) + install -m 0755 ${S}/vdkr.sh ${D}${bindir}/vdkr + + # Create backwards-compatible symlinks + ln -sf vdkr ${D}${bindir}/vdkr-aarch64 + ln -sf vdkr ${D}${bindir}/vdkr-x86_64 + + # Install runner script + install -m 0755 ${S}/vrunner.sh ${D}${bindir}/ + + # Determine blob source directories based on VDKR_USE_DEPLOY + if [ "${VDKR_USE_DEPLOY}" = "1" ]; then + AARCH64_SRC="${VDKR_DEPLOY_AARCH64}" + X86_64_SRC="${VDKR_DEPLOY_X86_64}" + bbwarn "============================================================" + bbwarn "VDKR_USE_DEPLOY=1: Using blobs from DEPLOY_DIR" + bbwarn "This is for development only. For permanent use, copy blobs:" + bbwarn "" + bbwarn " # For aarch64:" + bbwarn " cp ${VDKR_DEPLOY_AARCH64}/Image \\" + bbwarn " ${VDKR_LAYER_BLOBS}/aarch64/" + bbwarn " cp ${VDKR_DEPLOY_AARCH64}/initramfs.cpio.gz \\" + bbwarn " ${VDKR_LAYER_BLOBS}/aarch64/" + bbwarn "" + bbwarn " # For x86_64:" + bbwarn " cp ${VDKR_DEPLOY_X86_64}/bzImage \\" + bbwarn " ${VDKR_LAYER_BLOBS}/x86_64/" + bbwarn " cp ${VDKR_DEPLOY_X86_64}/initramfs.cpio.gz \\" + bbwarn " ${VDKR_LAYER_BLOBS}/x86_64/" + bbwarn "" + bbwarn "Then remove VDKR_USE_DEPLOY from local.conf" + bbwarn "============================================================" + else + AARCH64_SRC="${VDKR_LAYER_BLOBS}/aarch64" + X86_64_SRC="${VDKR_LAYER_BLOBS}/x86_64" + fi + + # Install aarch64 blobs (if available) + # Requires: Image, initramfs.cpio.gz, rootfs.img + if [ -f "$AARCH64_SRC/Image" ] && [ -f "$AARCH64_SRC/rootfs.img" ]; then + install -m 0644 "$AARCH64_SRC/Image" ${D}${bindir}/vdkr-blobs/aarch64/ + install -m 0644 "$AARCH64_SRC/initramfs.cpio.gz" ${D}${bindir}/vdkr-blobs/aarch64/ + install -m 0644 "$AARCH64_SRC/rootfs.img" ${D}${bindir}/vdkr-blobs/aarch64/ + bbnote "Installed aarch64 blobs from $AARCH64_SRC" + else + bbnote "No aarch64 blobs found at $AARCH64_SRC" + bbnote "Required: Image, initramfs.cpio.gz, rootfs.img" + fi + + # Install x86_64 blobs (if available) + # Requires: bzImage, initramfs.cpio.gz, rootfs.img + if [ -f "$X86_64_SRC/bzImage" ] && [ -f "$X86_64_SRC/rootfs.img" ]; then + install -m 0644 "$X86_64_SRC/bzImage" ${D}${bindir}/vdkr-blobs/x86_64/ + install -m 0644 "$X86_64_SRC/initramfs.cpio.gz" ${D}${bindir}/vdkr-blobs/x86_64/ + install -m 0644 "$X86_64_SRC/rootfs.img" ${D}${bindir}/vdkr-blobs/x86_64/ + bbnote "Installed x86_64 blobs from $X86_64_SRC" + else + bbnote "No x86_64 blobs found at $X86_64_SRC" + bbnote "Required: bzImage, initramfs.cpio.gz, rootfs.img" + fi +} + +# Make available in native sysroot +SYSROOT_DIRS += "${bindir}" + +# Task to print usage instructions for using vdkr from current location +# Run with: bitbake vdkr-native -c print_usage +python do_print_usage() { + import os + bindir = d.getVar('D') + d.getVar('bindir') + + # Find the actual install location + image_dir = d.getVar('D') + native_sysroot = d.getVar('STAGING_DIR_NATIVE') + + bb.plain("") + bb.plain("=" * 70) + bb.plain("vdkr Usage Instructions") + bb.plain("=" * 70) + bb.plain("") + bb.plain("Option 1: Add to PATH (recommended)") + bb.plain("-" * 40) + bb.plain("export PATH=\"%s:$PATH\"" % (native_sysroot + d.getVar('bindir'))) + bb.plain("") + bb.plain("Then use:") + bb.plain(" vdkr images # Uses default arch (host or config)") + bb.plain(" vdkr -a aarch64 images # Explicit arch") + bb.plain(" vdkr-x86_64 images # Symlink (backwards compatible)") + bb.plain("") + bb.plain("Option 2: Direct invocation") + bb.plain("-" * 40) + bb.plain("%s/vdkr images" % (native_sysroot + d.getVar('bindir'))) + bb.plain("") + bb.plain("Option 3: Set default architecture") + bb.plain("-" * 40) + bb.plain("mkdir -p ~/.config/vdkr && echo 'aarch64' > ~/.config/vdkr/arch") + bb.plain("") + bb.plain("Note: QEMU must be in PATH. If not found, also add:") + bb.plain("export PATH=\"%s:$PATH\"" % (d.getVar('STAGING_BINDIR_NATIVE'))) + bb.plain("") + bb.plain("=" * 70) +} +addtask print_usage +do_print_usage[nostamp] = "1" diff --git a/recipes-containers/vcontainer/vdkr-rootfs-image.bb b/recipes-containers/vcontainer/vdkr-rootfs-image.bb new file mode 100644 index 00000000..a9bbb9fa --- /dev/null +++ b/recipes-containers/vcontainer/vdkr-rootfs-image.bb @@ -0,0 +1,74 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield +# +# SPDX-License-Identifier: MIT +# +# vdkr-rootfs-image.bb +# Minimal Docker-capable image for vdkr QEMU environment +# +# This image is built via multiconfig and used by vdkr-initramfs-create +# to provide a proper rootfs for running Docker in QEMU. +# +# Build with: +# bitbake mc:vdkr-aarch64:vdkr-rootfs-image +# bitbake mc:vdkr-x86-64:vdkr-rootfs-image + +SUMMARY = "Minimal Docker rootfs for vdkr" +DESCRIPTION = "A minimal image containing Docker tools for use with vdkr. \ + This image runs inside QEMU to provide Docker command execution." + +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" + +# Track init script changes via file-checksums +# This adds the file content hash to the task signature +do_rootfs[file-checksums] += "${THISDIR}/files/vdkr-init.sh:True" +do_rootfs[file-checksums] += "${THISDIR}/files/vcontainer-init-common.sh:True" + +# Force do_rootfs to always run (no stamp caching) +# Combined with file-checksums, this ensures init script changes are picked up +do_rootfs[nostamp] = "1" + +# Inherit from core-image-minimal for a minimal base +inherit core-image + +# We need Docker and container tools +IMAGE_INSTALL = " \ + packagegroup-core-boot \ + docker-moby \ + containerd \ + runc \ + skopeo \ + busybox \ + iproute2 \ + util-linux \ +" + +# No extra features needed +IMAGE_FEATURES = "" + +# Keep the image small +IMAGE_ROOTFS_SIZE = "524288" +IMAGE_ROOTFS_EXTRA_SPACE = "0" + +# Use squashfs for smaller size (~3x compression) +# The preinit mounts squashfs read-only with tmpfs overlay for writes +IMAGE_FSTYPES = "squashfs" + +# Install our init script +ROOTFS_POSTPROCESS_COMMAND += "install_vdkr_init;" + +install_vdkr_init() { + # Install vdkr-init.sh as /init and vcontainer-init-common.sh alongside it + install -m 0755 ${THISDIR}/files/vdkr-init.sh ${IMAGE_ROOTFS}/init + install -m 0755 ${THISDIR}/files/vcontainer-init-common.sh ${IMAGE_ROOTFS}/vcontainer-init-common.sh + + # Create required directories + install -d ${IMAGE_ROOTFS}/mnt/input + install -d ${IMAGE_ROOTFS}/mnt/state + install -d ${IMAGE_ROOTFS}/var/lib/docker + install -d ${IMAGE_ROOTFS}/run/containerd + + # Create skopeo policy + install -d ${IMAGE_ROOTFS}/etc/containers + echo '{"default":[{"type":"insecureAcceptAnything"}]}' > ${IMAGE_ROOTFS}/etc/containers/policy.json +} -- cgit v1.2.3-54-g00ecf