summaryrefslogtreecommitdiffstats
path: root/recipes-containers/vcontainer
diff options
context:
space:
mode:
authorBruce Ashfield <bruce.ashfield@gmail.com>2026-01-06 20:42:46 +0000
committerBruce Ashfield <bruce.ashfield@gmail.com>2026-02-09 03:32:52 +0000
commit18074e0efe255a43ab9155171d08aa6e0d736b5f (patch)
tree25411491f3a6c3ed7b3460a0bd9f3d4d1c561bc6 /recipes-containers/vcontainer
parentc32db56912b06a89490fda5d554468dbc12a39a2 (diff)
downloadmeta-virtualization-18074e0efe255a43ab9155171d08aa6e0d736b5f.tar.gz
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 <bruce.ashfield@gmail.com>
Diffstat (limited to 'recipes-containers/vcontainer')
-rw-r--r--recipes-containers/vcontainer/files/blobs/vdkr/aarch64/README26
-rw-r--r--recipes-containers/vcontainer/files/blobs/vdkr/x86_64/README26
-rwxr-xr-xrecipes-containers/vcontainer/files/vdkr-init.sh238
-rwxr-xr-xrecipes-containers/vcontainer/files/vdkr.sh25
-rw-r--r--recipes-containers/vcontainer/vdkr-initramfs-create_1.0.bb46
-rw-r--r--recipes-containers/vcontainer/vdkr-native_1.0.bb191
-rw-r--r--recipes-containers/vcontainer/vdkr-rootfs-image.bb74
7 files changed, 626 insertions, 0 deletions
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 @@
1vdkr aarch64 Blobs
2====================
3
4This directory should contain the boot blobs for vdkr aarch64:
5
6Required files:
7 - Image : Linux kernel for aarch64
8 - initramfs.cpio.gz : Tiny initramfs for switch_root
9 - rootfs.img : Ext4 root filesystem with Docker tools
10
11Build instructions:
12 1. Set MACHINE for aarch64:
13 MACHINE=qemuarm64
14
15 2. Build the blobs:
16 bitbake vdkr-initramfs-create
17
18 3. Copy from deploy directory:
19 cp tmp/deploy/images/qemuarm64/vdkr/aarch64/Image .
20 cp tmp/deploy/images/qemuarm64/vdkr/aarch64/initramfs.cpio.gz .
21 cp tmp/deploy/images/qemuarm64/vdkr/aarch64/rootfs.img .
22
23Once these files are present, vdkr-native will automatically include them.
24
25Alternatively, set VDKR_USE_DEPLOY = "1" in local.conf to use blobs
26directly 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 @@
1vdkr x86_64 Blobs
2===================
3
4This directory should contain the boot blobs for vdkr x86_64:
5
6Required files:
7 - bzImage : Linux kernel for x86_64
8 - initramfs.cpio.gz : Tiny initramfs for switch_root
9 - rootfs.img : Ext4 root filesystem with Docker tools
10
11Build instructions:
12 1. Set MACHINE for x86_64:
13 MACHINE=qemux86-64
14
15 2. Build the blobs:
16 bitbake vdkr-initramfs-create
17
18 3. Copy from deploy directory:
19 cp tmp/deploy/images/qemux86-64/vdkr/x86_64/bzImage .
20 cp tmp/deploy/images/qemux86-64/vdkr/x86_64/initramfs.cpio.gz .
21 cp tmp/deploy/images/qemux86-64/vdkr/x86_64/rootfs.img .
22
23Once these files are present, vdkr-native will automatically include them.
24
25Alternatively, set VDKR_USE_DEPLOY = "1" in local.conf to use blobs
26directly 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 @@
1#!/bin/sh
2# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6# vdkr-init.sh
7# Init script for vdkr: execute arbitrary docker commands in QEMU
8#
9# This script runs on a real ext4 filesystem after switch_root from initramfs.
10# The preinit script mounted /dev/vda (rootfs.img) and did switch_root to us.
11#
12# Drive layout (rootfs.img is always /dev/vda, mounted as /):
13# /dev/vda = rootfs.img (this script runs from here, mounted as /)
14# /dev/vdb = input disk (optional, OCI/tar/dir data)
15# /dev/vdc = state disk (optional, persistent Docker storage)
16#
17# Kernel parameters:
18# docker_cmd=<base64> Base64-encoded docker command + args
19# docker_input=<type> Input type: none, oci, tar, dir (default: none)
20# docker_output=<type> Output type: text, tar, storage (default: text)
21# docker_state=<type> State type: none, disk (default: none)
22# docker_network=1 Enable networking (configure eth0, DNS)
23#
24# Version: 2.3.0
25
26# Set runtime-specific parameters before sourcing common code
27VCONTAINER_RUNTIME_NAME="vdkr"
28VCONTAINER_RUNTIME_CMD="docker"
29VCONTAINER_RUNTIME_PREFIX="docker"
30VCONTAINER_STATE_DIR="/var/lib/docker"
31VCONTAINER_SHARE_NAME="vdkr_share"
32VCONTAINER_VERSION="2.3.0"
33
34# Source common init functions
35# When installed as /init, common file is at /vcontainer-init-common.sh
36. /vcontainer-init-common.sh
37
38# ============================================================================
39# Docker-Specific Functions
40# ============================================================================
41
42setup_docker_storage() {
43 mkdir -p /run/containerd /run/lock
44 mkdir -p /var/lib/docker
45 mkdir -p /var/lib/containerd
46
47 # Handle Docker storage
48 if [ -n "$STATE_DISK" ] && [ -b "$STATE_DISK" ]; then
49 log "Mounting state disk $STATE_DISK as /var/lib/docker..."
50 if mount -t ext4 "$STATE_DISK" /var/lib/docker 2>&1; then
51 log "SUCCESS: Mounted $STATE_DISK as Docker storage"
52 log "Docker storage contents:"
53 [ "$QUIET_BOOT" = "0" ] && ls -la /var/lib/docker/ 2>/dev/null || log "(empty)"
54 else
55 log "WARNING: Failed to mount state disk, using tmpfs"
56 RUNTIME_STATE="none"
57 fi
58 fi
59
60 # If no state disk, use tmpfs for Docker storage
61 if [ "$RUNTIME_STATE" != "disk" ]; then
62 log "Using tmpfs for Docker storage (ephemeral)..."
63 mount -t tmpfs -o size=1G tmpfs /var/lib/docker
64 fi
65}
66
67start_containerd() {
68 CONTAINERD_READY=false
69 if [ -x "/usr/bin/containerd" ]; then
70 log "Starting containerd..."
71 mkdir -p /var/lib/containerd
72 mkdir -p /run/containerd
73 /usr/bin/containerd --log-level info --root /var/lib/containerd --state /run/containerd >/tmp/containerd.log 2>&1 &
74 CONTAINERD_PID=$!
75 # Wait for containerd socket
76 for i in 1 2 3 4 5 6 7 8 9 10; do
77 if [ -S /run/containerd/containerd.sock ]; then
78 log "Containerd running (PID: $CONTAINERD_PID)"
79 CONTAINERD_READY=true
80 break
81 fi
82 sleep 1
83 done
84 if [ "$CONTAINERD_READY" != "true" ]; then
85 log "WARNING: Containerd failed to start, check /tmp/containerd.log"
86 [ -f /tmp/containerd.log ] && cat /tmp/containerd.log >&2
87 fi
88 fi
89}
90
91start_dockerd() {
92 log "Starting Docker daemon..."
93 DOCKER_OPTS="--data-root=/var/lib/docker"
94 DOCKER_OPTS="$DOCKER_OPTS --storage-driver=overlay2"
95 DOCKER_OPTS="$DOCKER_OPTS --iptables=false"
96 DOCKER_OPTS="$DOCKER_OPTS --userland-proxy=false"
97 DOCKER_OPTS="$DOCKER_OPTS --bridge=none"
98 DOCKER_OPTS="$DOCKER_OPTS --host=unix:///var/run/docker.sock"
99 DOCKER_OPTS="$DOCKER_OPTS --exec-opt native.cgroupdriver=cgroupfs"
100 DOCKER_OPTS="$DOCKER_OPTS --log-level=info"
101
102 if [ "$CONTAINERD_READY" = "true" ]; then
103 DOCKER_OPTS="$DOCKER_OPTS --containerd=/run/containerd/containerd.sock"
104 fi
105
106 /usr/bin/dockerd $DOCKER_OPTS >/dev/null 2>&1 &
107 DOCKER_PID=$!
108 log "Docker daemon started (PID: $DOCKER_PID)"
109
110 # Wait for Docker to be ready
111 log "Waiting for Docker daemon..."
112 DOCKER_READY=false
113
114 sleep 5
115
116 for i in $(seq 1 60); do
117 if ! kill -0 $DOCKER_PID 2>/dev/null; then
118 echo "===ERROR==="
119 echo "Docker daemon died after $i iterations"
120 cat /var/log/docker.log 2>/dev/null || true
121 dmesg | tail -20 2>/dev/null || true
122 sleep 2
123 reboot -f
124 fi
125
126 if /usr/bin/docker info >/dev/null 2>&1; then
127 log "Docker daemon is ready!"
128 DOCKER_READY=true
129 break
130 fi
131
132 log "Waiting... ($i/60)"
133 sleep 2
134 done
135
136 if [ "$DOCKER_READY" != "true" ]; then
137 echo "===ERROR==="
138 echo "Docker failed to start"
139 sleep 2
140 reboot -f
141 fi
142}
143
144stop_runtime_daemons() {
145 # Stop Docker daemon
146 if [ -n "$DOCKER_PID" ]; then
147 log "Stopping Docker daemon..."
148 kill $DOCKER_PID 2>/dev/null || true
149 for i in $(seq 1 10); do
150 if ! kill -0 $DOCKER_PID 2>/dev/null; then
151 log "Docker daemon stopped"
152 break
153 fi
154 sleep 1
155 done
156 fi
157
158 # Stop containerd
159 if [ -n "$CONTAINERD_PID" ]; then
160 log "Stopping containerd..."
161 kill $CONTAINERD_PID 2>/dev/null || true
162 sleep 2
163 fi
164}
165
166handle_storage_output() {
167 echo "Stopping Docker gracefully..."
168 /usr/bin/docker system prune -f >/dev/null 2>&1 || true
169 kill $DOCKER_PID 2>/dev/null || true
170 [ -n "$CONTAINERD_PID" ] && kill $CONTAINERD_PID 2>/dev/null || true
171 sleep 3
172
173 echo "Packaging Docker storage..."
174 cd /var/lib
175 tar -cf /tmp/storage.tar docker/
176
177 STORAGE_SIZE=$(stat -c%s /tmp/storage.tar 2>/dev/null || echo "0")
178 echo "Storage size: $STORAGE_SIZE bytes"
179
180 if [ "$STORAGE_SIZE" -gt 1000 ]; then
181 dmesg -n 1
182 echo "===STORAGE_START==="
183 base64 /tmp/storage.tar
184 echo "===STORAGE_END==="
185 echo "===EXIT_CODE=$EXEC_EXIT_CODE==="
186 else
187 echo "===ERROR==="
188 echo "Storage too small"
189 fi
190}
191
192# ============================================================================
193# Main
194# ============================================================================
195
196# Initialize base environment
197setup_base_environment
198mount_base_filesystems
199
200# Check for quiet boot mode
201check_quiet_boot
202
203log "=== vdkr Init ==="
204log "Version: $VCONTAINER_VERSION"
205
206# Mount tmpfs directories and cgroups
207mount_tmpfs_dirs
208setup_cgroups
209
210# Parse kernel command line
211parse_cmdline
212
213# Detect and configure disks
214detect_disks
215
216# Set up Docker storage (Docker-specific)
217setup_docker_storage
218
219# Mount input disk
220mount_input_disk
221
222# Configure networking
223configure_networking
224
225# Start containerd and dockerd (Docker-specific)
226start_containerd
227start_dockerd
228
229# Handle daemon mode or single command execution
230if [ "$RUNTIME_DAEMON" = "1" ]; then
231 run_daemon_mode
232else
233 prepare_input_path
234 execute_command
235fi
236
237# Graceful shutdown
238graceful_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 @@
1#!/bin/bash
2# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6# vdkr: Docker-like interface for cross-architecture container operations
7#
8# This provides a familiar docker-like CLI that executes commands inside
9# a QEMU-emulated environment with the target architecture's Docker.
10#
11# Command naming convention:
12# - Commands matching Docker's syntax/semantics use Docker's name (import, load, save, etc.)
13# - Extended commands with non-Docker behavior use 'v' prefix (vimport)
14
15# Set runtime-specific parameters before sourcing common code
16VCONTAINER_RUNTIME_NAME="vdkr"
17VCONTAINER_RUNTIME_CMD="docker"
18VCONTAINER_RUNTIME_PREFIX="VDKR"
19VCONTAINER_IMPORT_TARGET="docker-daemon:"
20VCONTAINER_STATE_FILE="docker-state.img"
21VCONTAINER_OTHER_PREFIX="VPDMN"
22VCONTAINER_VERSION="3.4.0"
23
24# Source common implementation
25source "$(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 @@
1# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield
2#
3# SPDX-License-Identifier: MIT
4#
5# vdkr-initramfs-create_1.0.bb
6# ===========================================================================
7# Builds QEMU boot blobs for vdkr (Docker CLI)
8# ===========================================================================
9#
10# This recipe packages the boot blobs for vdkr:
11# - A tiny initramfs with just busybox for switch_root
12# - The rootfs.img squashfs image (built via multiconfig)
13# - The kernel
14#
15# Boot flow:
16# QEMU boots kernel + tiny initramfs
17# -> preinit mounts rootfs.img from /dev/vda
18# -> switch_root into rootfs.img
19# -> vdkr-init.sh runs with a real root filesystem
20# -> Docker can use pivot_root properly
21#
22# ===========================================================================
23# BUILD INSTRUCTIONS
24# ===========================================================================
25#
26# For aarch64 (multiconfig dependency is automatic):
27# MACHINE=qemuarm64 bitbake vdkr-initramfs-create
28#
29# For x86_64:
30# MACHINE=qemux86-64 bitbake vdkr-initramfs-create
31#
32# Blobs are deployed to: tmp-vruntime-*/deploy/images/${MACHINE}/vdkr/
33#
34# To build the complete standalone tarball (recommended):
35# MACHINE=qemux86-64 bitbake vcontainer-native -c create_tarball
36#
37# ===========================================================================
38
39SUMMARY = "Build QEMU blobs for vdkr"
40DESCRIPTION = "Packages a tiny initramfs for switch_root and bundles the \
41 rootfs.img from multiconfig build for vdkr."
42
43# Set the runtime before including shared code
44VCONTAINER_RUNTIME = "vdkr"
45
46require 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 @@
1# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield
2#
3# SPDX-License-Identifier: MIT
4#
5# vdkr-native_1.0.bb
6# ===========================================================================
7# Emulated Docker for cross-architecture container operations
8# ===========================================================================
9#
10# vdkr provides a Docker-like CLI that executes arbitrary docker commands
11# inside a QEMU-emulated environment with the target architecture's Docker
12# daemon. Commands like "docker load", "docker export", "docker images" etc
13# are passed through to Docker running inside QEMU and results streamed back.
14#
15# vdkr uses its own initramfs (built by vdkr-initramfs-create) which
16# has vdkr-init.sh baked in. This is separate from container-cross-install.
17#
18# USAGE:
19# vdkr images # Uses detected default arch
20# vdkr -a aarch64 images # Explicit arch
21# vdkr-aarch64 images # Symlink (backwards compatible)
22# vdkr-x86_64 load -i myimage.tar
23#
24# Architecture detection (in priority order):
25# 1. --arch / -a flag
26# 2. Executable name (vdkr-aarch64, vdkr-x86_64)
27# 3. VDKR_ARCH environment variable
28# 4. Config file: ~/.config/vdkr/arch
29# 5. Host architecture (uname -m)
30#
31# DEPENDENCIES:
32# - Kernel/initramfs blobs from vdkr-initramfs-create
33# - QEMU system emulator (qemu-system-native)
34#
35# ===========================================================================
36
37SUMMARY = "Emulated Docker for cross-architecture container operations"
38DESCRIPTION = "Provides vdkr CLI that executes docker commands inside \
39 QEMU-emulated environment. Useful for building/manipulating \
40 containers for target architectures on a different host."
41HOMEPAGE = "https://github.com/anthropics/meta-virtualization"
42LICENSE = "MIT"
43LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
44
45inherit native
46
47# Dependencies
48DEPENDS = "qemu-system-native coreutils-native socat-native"
49
50# vdkr-init.sh is now baked into the initramfs, not installed separately
51SRC_URI = "\
52 file://vdkr.sh \
53 file://vrunner.sh \
54"
55
56# Pre-built blobs are optional - they're checked into the layer after being
57# built by vdkr-initramfs-build. If not present, vdkr will still build
58# but will require --blob-dir at runtime.
59#
60# To build blobs:
61# MACHINE=qemuarm64 bitbake vdkr-initramfs-build
62# MACHINE=qemux86-64 bitbake vdkr-initramfs-build
63# Then copy from tmp/deploy/images/<machine>/vdkr-initramfs/ to files/blobs/vdkr/<arch>/
64#
65# For development, set VDKR_USE_DEPLOY = "1" in local.conf to use blobs
66# directly from DEPLOY_DIR instead of copying to layer.
67
68FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
69
70# Layer directory containing optional blobs
71VDKR_LAYER_BLOBS = "${THISDIR}/files/blobs/vdkr"
72
73# Deploy directories (used when VDKR_USE_DEPLOY = "1")
74VDKR_DEPLOY_AARCH64 = "${DEPLOY_DIR}/images/qemuarm64/vdkr-initramfs"
75VDKR_DEPLOY_X86_64 = "${DEPLOY_DIR}/images/qemux86-64/vdkr-initramfs"
76
77# Set to "1" in local.conf to prefer DEPLOY_DIR blobs over layer
78VDKR_USE_DEPLOY ?= "0"
79
80S = "${UNPACKDIR}"
81
82do_install() {
83 # Install vdkr main script and architecture symlinks
84 install -d ${D}${bindir}
85 install -d ${D}${bindir}/vdkr-blobs/aarch64
86 install -d ${D}${bindir}/vdkr-blobs/x86_64
87
88 # Install main vdkr script (arch detected at runtime)
89 install -m 0755 ${S}/vdkr.sh ${D}${bindir}/vdkr
90
91 # Create backwards-compatible symlinks
92 ln -sf vdkr ${D}${bindir}/vdkr-aarch64
93 ln -sf vdkr ${D}${bindir}/vdkr-x86_64
94
95 # Install runner script
96 install -m 0755 ${S}/vrunner.sh ${D}${bindir}/
97
98 # Determine blob source directories based on VDKR_USE_DEPLOY
99 if [ "${VDKR_USE_DEPLOY}" = "1" ]; then
100 AARCH64_SRC="${VDKR_DEPLOY_AARCH64}"
101 X86_64_SRC="${VDKR_DEPLOY_X86_64}"
102 bbwarn "============================================================"
103 bbwarn "VDKR_USE_DEPLOY=1: Using blobs from DEPLOY_DIR"
104 bbwarn "This is for development only. For permanent use, copy blobs:"
105 bbwarn ""
106 bbwarn " # For aarch64:"
107 bbwarn " cp ${VDKR_DEPLOY_AARCH64}/Image \\"
108 bbwarn " ${VDKR_LAYER_BLOBS}/aarch64/"
109 bbwarn " cp ${VDKR_DEPLOY_AARCH64}/initramfs.cpio.gz \\"
110 bbwarn " ${VDKR_LAYER_BLOBS}/aarch64/"
111 bbwarn ""
112 bbwarn " # For x86_64:"
113 bbwarn " cp ${VDKR_DEPLOY_X86_64}/bzImage \\"
114 bbwarn " ${VDKR_LAYER_BLOBS}/x86_64/"
115 bbwarn " cp ${VDKR_DEPLOY_X86_64}/initramfs.cpio.gz \\"
116 bbwarn " ${VDKR_LAYER_BLOBS}/x86_64/"
117 bbwarn ""
118 bbwarn "Then remove VDKR_USE_DEPLOY from local.conf"
119 bbwarn "============================================================"
120 else
121 AARCH64_SRC="${VDKR_LAYER_BLOBS}/aarch64"
122 X86_64_SRC="${VDKR_LAYER_BLOBS}/x86_64"
123 fi
124
125 # Install aarch64 blobs (if available)
126 # Requires: Image, initramfs.cpio.gz, rootfs.img
127 if [ -f "$AARCH64_SRC/Image" ] && [ -f "$AARCH64_SRC/rootfs.img" ]; then
128 install -m 0644 "$AARCH64_SRC/Image" ${D}${bindir}/vdkr-blobs/aarch64/
129 install -m 0644 "$AARCH64_SRC/initramfs.cpio.gz" ${D}${bindir}/vdkr-blobs/aarch64/
130 install -m 0644 "$AARCH64_SRC/rootfs.img" ${D}${bindir}/vdkr-blobs/aarch64/
131 bbnote "Installed aarch64 blobs from $AARCH64_SRC"
132 else
133 bbnote "No aarch64 blobs found at $AARCH64_SRC"
134 bbnote "Required: Image, initramfs.cpio.gz, rootfs.img"
135 fi
136
137 # Install x86_64 blobs (if available)
138 # Requires: bzImage, initramfs.cpio.gz, rootfs.img
139 if [ -f "$X86_64_SRC/bzImage" ] && [ -f "$X86_64_SRC/rootfs.img" ]; then
140 install -m 0644 "$X86_64_SRC/bzImage" ${D}${bindir}/vdkr-blobs/x86_64/
141 install -m 0644 "$X86_64_SRC/initramfs.cpio.gz" ${D}${bindir}/vdkr-blobs/x86_64/
142 install -m 0644 "$X86_64_SRC/rootfs.img" ${D}${bindir}/vdkr-blobs/x86_64/
143 bbnote "Installed x86_64 blobs from $X86_64_SRC"
144 else
145 bbnote "No x86_64 blobs found at $X86_64_SRC"
146 bbnote "Required: bzImage, initramfs.cpio.gz, rootfs.img"
147 fi
148}
149
150# Make available in native sysroot
151SYSROOT_DIRS += "${bindir}"
152
153# Task to print usage instructions for using vdkr from current location
154# Run with: bitbake vdkr-native -c print_usage
155python do_print_usage() {
156 import os
157 bindir = d.getVar('D') + d.getVar('bindir')
158
159 # Find the actual install location
160 image_dir = d.getVar('D')
161 native_sysroot = d.getVar('STAGING_DIR_NATIVE')
162
163 bb.plain("")
164 bb.plain("=" * 70)
165 bb.plain("vdkr Usage Instructions")
166 bb.plain("=" * 70)
167 bb.plain("")
168 bb.plain("Option 1: Add to PATH (recommended)")
169 bb.plain("-" * 40)
170 bb.plain("export PATH=\"%s:$PATH\"" % (native_sysroot + d.getVar('bindir')))
171 bb.plain("")
172 bb.plain("Then use:")
173 bb.plain(" vdkr images # Uses default arch (host or config)")
174 bb.plain(" vdkr -a aarch64 images # Explicit arch")
175 bb.plain(" vdkr-x86_64 images # Symlink (backwards compatible)")
176 bb.plain("")
177 bb.plain("Option 2: Direct invocation")
178 bb.plain("-" * 40)
179 bb.plain("%s/vdkr images" % (native_sysroot + d.getVar('bindir')))
180 bb.plain("")
181 bb.plain("Option 3: Set default architecture")
182 bb.plain("-" * 40)
183 bb.plain("mkdir -p ~/.config/vdkr && echo 'aarch64' > ~/.config/vdkr/arch")
184 bb.plain("")
185 bb.plain("Note: QEMU must be in PATH. If not found, also add:")
186 bb.plain("export PATH=\"%s:$PATH\"" % (d.getVar('STAGING_BINDIR_NATIVE')))
187 bb.plain("")
188 bb.plain("=" * 70)
189}
190addtask print_usage
191do_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 @@
1# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield
2#
3# SPDX-License-Identifier: MIT
4#
5# vdkr-rootfs-image.bb
6# Minimal Docker-capable image for vdkr QEMU environment
7#
8# This image is built via multiconfig and used by vdkr-initramfs-create
9# to provide a proper rootfs for running Docker in QEMU.
10#
11# Build with:
12# bitbake mc:vdkr-aarch64:vdkr-rootfs-image
13# bitbake mc:vdkr-x86-64:vdkr-rootfs-image
14
15SUMMARY = "Minimal Docker rootfs for vdkr"
16DESCRIPTION = "A minimal image containing Docker tools for use with vdkr. \
17 This image runs inside QEMU to provide Docker command execution."
18
19LICENSE = "MIT"
20LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
21
22# Track init script changes via file-checksums
23# This adds the file content hash to the task signature
24do_rootfs[file-checksums] += "${THISDIR}/files/vdkr-init.sh:True"
25do_rootfs[file-checksums] += "${THISDIR}/files/vcontainer-init-common.sh:True"
26
27# Force do_rootfs to always run (no stamp caching)
28# Combined with file-checksums, this ensures init script changes are picked up
29do_rootfs[nostamp] = "1"
30
31# Inherit from core-image-minimal for a minimal base
32inherit core-image
33
34# We need Docker and container tools
35IMAGE_INSTALL = " \
36 packagegroup-core-boot \
37 docker-moby \
38 containerd \
39 runc \
40 skopeo \
41 busybox \
42 iproute2 \
43 util-linux \
44"
45
46# No extra features needed
47IMAGE_FEATURES = ""
48
49# Keep the image small
50IMAGE_ROOTFS_SIZE = "524288"
51IMAGE_ROOTFS_EXTRA_SPACE = "0"
52
53# Use squashfs for smaller size (~3x compression)
54# The preinit mounts squashfs read-only with tmpfs overlay for writes
55IMAGE_FSTYPES = "squashfs"
56
57# Install our init script
58ROOTFS_POSTPROCESS_COMMAND += "install_vdkr_init;"
59
60install_vdkr_init() {
61 # Install vdkr-init.sh as /init and vcontainer-init-common.sh alongside it
62 install -m 0755 ${THISDIR}/files/vdkr-init.sh ${IMAGE_ROOTFS}/init
63 install -m 0755 ${THISDIR}/files/vcontainer-init-common.sh ${IMAGE_ROOTFS}/vcontainer-init-common.sh
64
65 # Create required directories
66 install -d ${IMAGE_ROOTFS}/mnt/input
67 install -d ${IMAGE_ROOTFS}/mnt/state
68 install -d ${IMAGE_ROOTFS}/var/lib/docker
69 install -d ${IMAGE_ROOTFS}/run/containerd
70
71 # Create skopeo policy
72 install -d ${IMAGE_ROOTFS}/etc/containers
73 echo '{"default":[{"type":"insecureAcceptAnything"}]}' > ${IMAGE_ROOTFS}/etc/containers/policy.json
74}