From 65cebeda3a2eda72802a46949601ba3e021a0db6 Mon Sep 17 00:00:00 2001 From: Bruce Ashfield Date: Mon, 12 Jan 2026 16:13:45 +0000 Subject: vdkr: add registry configuration and pull fallback Add registry support to vdkr: - vconfig registry command for persistent config - --registry flag for one-off usage - Registry-first, Docker Hub fallback for pulls - Baked-in registry config via CONTAINER_REGISTRY_URL - Image commands (inspect, history, rmi, images) work without transform Signed-off-by: Bruce Ashfield --- .../vcontainer/files/vcontainer-common.sh | 95 ++++++- .../vcontainer/files/vcontainer-init-common.sh | 26 +- recipes-containers/vcontainer/files/vdkr-init.sh | 298 ++++++++++++++++++++- recipes-containers/vcontainer/files/vrunner.sh | 31 +++ recipes-containers/vcontainer/vdkr-rootfs-image.bb | 48 ++++ 5 files changed, 493 insertions(+), 5 deletions(-) (limited to 'recipes-containers') diff --git a/recipes-containers/vcontainer/files/vcontainer-common.sh b/recipes-containers/vcontainer/files/vcontainer-common.sh index b0623164..f10243f1 100755 --- a/recipes-containers/vcontainer/files/vcontainer-common.sh +++ b/recipes-containers/vcontainer/files/vcontainer-common.sh @@ -134,6 +134,7 @@ config_default() { verbose) echo "false" ;; idle-timeout) echo "1800" ;; # 30 minutes auto-daemon) echo "true" ;; # Auto-start daemon by default + registry) echo "" ;; # Default registry for unqualified images *) echo "" ;; esac } @@ -404,11 +405,12 @@ ${BOLD}CONFIGURATION (vconfig):${NC} ${CYAN}vconfig${NC} Set configuration value ${CYAN}vconfig${NC} --reset Reset to default value - Supported keys: arch, timeout, state-dir, verbose, idle-timeout, auto-daemon + Supported keys: arch, timeout, state-dir, verbose, idle-timeout, auto-daemon, registry Config file: \$CONFIG_DIR/config (default: ~/.config/${VCONTAINER_RUNTIME_NAME}/config) idle-timeout: Daemon idle timeout in seconds [default: 1800] auto-daemon: Auto-start daemon on first command [default: true] + registry: Default registry for unqualified images (e.g., 10.0.2.2:5000/yocto) ${BOLD}GLOBAL OPTIONS:${NC} --arch, -a Target architecture: x86_64 or aarch64 [default: ${DEFAULT_ARCH}] @@ -421,6 +423,8 @@ ${BOLD}GLOBAL OPTIONS:${NC} --input-storage Load ${RUNTIME_UPPER} state from tar before command --no-kvm Disable KVM acceleration (use TCG emulation) --no-daemon Run in ephemeral mode (don't auto-start/use daemon) + --registry Default registry for unqualified images (e.g., 10.0.2.2:5000/yocto) + --insecure-registry Mark registry as insecure (HTTP). Can repeat. --verbose, -v Enable verbose output --help, -h Show this help @@ -467,6 +471,13 @@ ${BOLD}EXAMPLES:${NC} # Pull an image from a registry ${PROG_NAME} pull alpine:latest + # Pull from local registry (configure once, use everywhere) + ${PROG_NAME} vconfig registry 10.0.2.2:5000/yocto # Set default registry + ${PROG_NAME} pull container-base # Pulls from 10.0.2.2:5000/yocto/container-base + + # Or use --registry for one-off pulls + ${PROG_NAME} --registry 10.0.2.2:5000/yocto pull container-base + # vrun: convenience wrapper (clears entrypoint when command given) ${PROG_NAME} vrun myapp:latest /bin/ls -la # Runs /bin/ls directly, not via entrypoint @@ -538,6 +549,12 @@ build_runner_args() { args+=("--port-forward" "$pf") done + # Add registry configuration + [ -n "$REGISTRY" ] && args+=("--registry" "$REGISTRY") + for reg in "${INSECURE_REGISTRIES[@]}"; do + args+=("--insecure-registry" "$reg") + done + echo "${args[@]}" } @@ -551,6 +568,8 @@ INTERACTIVE="false" PORT_FORWARDS=() DISABLE_KVM="false" NO_DAEMON="false" +REGISTRY="" +INSECURE_REGISTRIES=() COMMAND="" COMMAND_ARGS=() @@ -611,6 +630,14 @@ while [ $# -gt 0 ]; do NO_DAEMON="true" shift ;; + --registry) + REGISTRY="$2" + shift 2 + ;; + --insecure-registry) + INSECURE_REGISTRIES+=("$2") + shift 2 + ;; -it|--interactive) INTERACTIVE="true" shift @@ -683,6 +710,11 @@ if [ "$STATELESS" != "true" ] && [ -z "$STATE_DIR" ] && [ -z "$INPUT_STORAGE" ]; STATE_DIR="$DEFAULT_STATE_DIR/$TARGET_ARCH" fi +# Read registry from config if not set via CLI +if [ -z "$REGISTRY" ]; then + REGISTRY=$(config_get "registry" "") +fi + # Check runner exists if [ ! -x "$RUNNER" ]; then echo -e "${RED}[$VCONTAINER_RUNTIME_NAME]${NC} Runner script not found: $RUNNER" >&2 @@ -1122,6 +1154,65 @@ parse_and_prepare_volumes() { # Handle commands case "$COMMAND" in + image) + # Handle "docker image *" compound commands + # docker image ls → docker images + # docker image rm → docker rmi + # docker image pull → docker pull + # etc. + if [ ${#COMMAND_ARGS[@]} -lt 1 ]; then + echo -e "${RED}[$VCONTAINER_RUNTIME_NAME]${NC} image requires a subcommand (ls, rm, pull, inspect, tag, push, prune)" >&2 + exit 1 + fi + SUBCMD="${COMMAND_ARGS[0]}" + SUBCMD_ARGS=("${COMMAND_ARGS[@]:1}") + case "$SUBCMD" in + ls|list) + run_runtime_command "$VCONTAINER_RUNTIME_CMD images ${SUBCMD_ARGS[*]}" + ;; + rm|remove) + run_runtime_command "$VCONTAINER_RUNTIME_CMD rmi ${SUBCMD_ARGS[*]}" + ;; + pull) + # Reuse pull logic - set COMMAND_ARGS and fall through + COMMAND_ARGS=("${SUBCMD_ARGS[@]}") + if [ ${#COMMAND_ARGS[@]} -lt 1 ]; then + echo -e "${RED}[$VCONTAINER_RUNTIME_NAME]${NC} image pull requires " >&2 + exit 1 + fi + IMAGE_NAME="${COMMAND_ARGS[0]}" + if daemon_is_running; then + run_runtime_command "$VCONTAINER_RUNTIME_CMD pull $IMAGE_NAME && $VCONTAINER_RUNTIME_CMD images" + else + NETWORK="true" + RUNNER_ARGS=$(build_runner_args) + "$RUNNER" $RUNNER_ARGS -- "$VCONTAINER_RUNTIME_CMD pull $IMAGE_NAME && $VCONTAINER_RUNTIME_CMD images" + fi + ;; + inspect) + run_runtime_command "$VCONTAINER_RUNTIME_CMD inspect ${SUBCMD_ARGS[*]}" + ;; + tag) + run_runtime_command "$VCONTAINER_RUNTIME_CMD tag ${SUBCMD_ARGS[*]}" + ;; + push) + NETWORK="true" + run_runtime_command "$VCONTAINER_RUNTIME_CMD push ${SUBCMD_ARGS[*]}" + ;; + prune) + run_runtime_command "$VCONTAINER_RUNTIME_CMD image prune ${SUBCMD_ARGS[*]}" + ;; + history) + run_runtime_command "$VCONTAINER_RUNTIME_CMD history ${SUBCMD_ARGS[*]}" + ;; + *) + echo -e "${RED}[$VCONTAINER_RUNTIME_NAME]${NC} Unknown image subcommand: $SUBCMD" >&2 + echo -e "${YELLOW}[$VCONTAINER_RUNTIME_NAME]${NC} Valid subcommands: ls, rm, pull, inspect, tag, push, prune, history" >&2 + exit 1 + ;; + esac + ;; + images) # runtime images run_runtime_command "$VCONTAINER_RUNTIME_CMD images ${COMMAND_ARGS[*]}" @@ -1542,7 +1633,7 @@ case "$COMMAND" in vconfig) # Configuration management (runs on host, not in VM) - VALID_KEYS="arch timeout state-dir verbose idle-timeout auto-daemon" + VALID_KEYS="arch timeout state-dir verbose idle-timeout auto-daemon registry" if [ ${#COMMAND_ARGS[@]} -lt 1 ]; then # Show all config diff --git a/recipes-containers/vcontainer/files/vcontainer-init-common.sh b/recipes-containers/vcontainer/files/vcontainer-init-common.sh index 21bbe9db..738d0343 100755 --- a/recipes-containers/vcontainer/files/vcontainer-init-common.sh +++ b/recipes-containers/vcontainer/files/vcontainer-init-common.sh @@ -380,6 +380,25 @@ run_daemon_mode() { log "Command needs input from shared directory" fi + # Check if this is a pull command that needs fallback handling + # (try registry first, fall back to Docker Hub) + USE_PULL_FALLBACK=false + if type is_pull_command >/dev/null 2>&1 && type execute_pull_with_fallback >/dev/null 2>&1; then + if is_pull_command "$CMD"; then + USE_PULL_FALLBACK=true + log "Using pull with registry fallback" + fi + fi + + # Transform command if runtime provides a transform function + # (e.g., vdkr transforms unqualified images to use default registry) + # Note: Pull commands are NOT transformed - they use fallback logic + if [ "$USE_PULL_FALLBACK" != "true" ]; then + if type transform_docker_command >/dev/null 2>&1 && [ -n "$DOCKER_DEFAULT_REGISTRY" ]; then + CMD=$(transform_docker_command "$CMD") + fi + fi + log "Executing: $CMD" # Verify shared directory has content if needed @@ -403,7 +422,12 @@ run_daemon_mode() { # Execute command EXEC_OUTPUT="/tmp/daemon_output.txt" EXEC_EXIT_CODE=0 - eval "$CMD" > "$EXEC_OUTPUT" 2>&1 || EXEC_EXIT_CODE=$? + if [ "$USE_PULL_FALLBACK" = "true" ]; then + # Pull commands use registry-first, Docker Hub fallback + execute_pull_with_fallback "$CMD" > "$EXEC_OUTPUT" 2>&1 || EXEC_EXIT_CODE=$? + else + eval "$CMD" > "$EXEC_OUTPUT" 2>&1 || EXEC_EXIT_CODE=$? + fi # Clean up shared directory if [ "$NEEDS_INPUT" = "true" ]; then diff --git a/recipes-containers/vcontainer/files/vdkr-init.sh b/recipes-containers/vcontainer/files/vdkr-init.sh index efe56049..318ce521 100755 --- a/recipes-containers/vcontainer/files/vdkr-init.sh +++ b/recipes-containers/vcontainer/files/vdkr-init.sh @@ -20,8 +20,10 @@ # 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) +# docker_registry= Default registry for unqualified images (e.g., 10.0.2.2:5000/yocto) +# docker_insecure_registry= Mark registry as insecure (HTTP). Can repeat. # -# Version: 2.3.0 +# Version: 2.4.0 # Set runtime-specific parameters before sourcing common code VCONTAINER_RUNTIME_NAME="vdkr" @@ -29,12 +31,31 @@ VCONTAINER_RUNTIME_CMD="docker" VCONTAINER_RUNTIME_PREFIX="docker" VCONTAINER_STATE_DIR="/var/lib/docker" VCONTAINER_SHARE_NAME="vdkr_share" -VCONTAINER_VERSION="2.3.0" +VCONTAINER_VERSION="2.4.0" + +# Docker-specific: default registry for unqualified image names +# Set via kernel param: docker_registry=10.0.2.2:5000/yocto +# Or baked into rootfs: /etc/vdkr/registry.conf +DOCKER_DEFAULT_REGISTRY="" # Source common init functions # When installed as /init, common file is at /vcontainer-init-common.sh . /vcontainer-init-common.sh +# Load baked-in registry defaults from /etc/vdkr/registry.conf +# These can be overridden by kernel cmdline parameters +load_registry_config() { + if [ -f /etc/vdkr/registry.conf ]; then + . /etc/vdkr/registry.conf + # Map config file variables to our internal variables + if [ -n "$VDKR_DEFAULT_REGISTRY" ]; then + DOCKER_DEFAULT_REGISTRY="$VDKR_DEFAULT_REGISTRY" + log "Loaded baked registry: $DOCKER_DEFAULT_REGISTRY" + fi + # VDKR_INSECURE_REGISTRIES is handled in start_dockerd + fi +} + # ============================================================================ # Docker-Specific Functions # ============================================================================ @@ -100,6 +121,45 @@ start_dockerd() { DOCKER_OPTS="$DOCKER_OPTS --exec-opt native.cgroupdriver=cgroupfs" DOCKER_OPTS="$DOCKER_OPTS --log-level=info" + # Parse default registry from kernel cmdline (docker_registry=host:port/namespace) + # Kernel cmdline OVERRIDES baked config from /etc/vdkr/registry.conf + # This enables: "docker pull container-base" → "docker pull 10.0.2.2:5000/yocto/container-base" + GREP_RESULT=$(grep -o 'docker_registry=[^ ]*' /proc/cmdline 2>/dev/null || true) + if [ -n "$GREP_RESULT" ]; then + DOCKER_DEFAULT_REGISTRY=$(echo "$GREP_RESULT" | sed 's/docker_registry=//') + log "Registry from cmdline: $DOCKER_DEFAULT_REGISTRY" + elif [ -n "$DOCKER_DEFAULT_REGISTRY" ]; then + log "Registry from baked config: $DOCKER_DEFAULT_REGISTRY" + fi + if [ -n "$DOCKER_DEFAULT_REGISTRY" ]; then + # Extract host:port for insecure registry config (strip path/namespace) + REGISTRY_HOST=$(echo "$DOCKER_DEFAULT_REGISTRY" | cut -d'/' -f1) + # Auto-add to insecure registries if it looks like a local/private registry + if echo "$REGISTRY_HOST" | grep -qE '^(localhost|127\.|10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)'; then + DOCKER_OPTS="$DOCKER_OPTS --insecure-registry=$REGISTRY_HOST" + log "Auto-added insecure registry: $REGISTRY_HOST" + fi + fi + + # Add baked insecure registries from /etc/vdkr/registry.conf + if [ -n "$VDKR_INSECURE_REGISTRIES" ]; then + for registry in $VDKR_INSECURE_REGISTRIES; do + DOCKER_OPTS="$DOCKER_OPTS --insecure-registry=$registry" + log "Added baked insecure registry: $registry" + done + fi + + # Check for additional insecure registries from kernel cmdline (docker_insecure_registry=host:port) + # For local registry on build host via QEMU slirp: docker_insecure_registry=10.0.2.2:5000 + # For remote HTTP registry: docker_insecure_registry=registry.company.com:5000 + # Multiple registries can be specified by repeating the parameter + for registry in $(grep -o 'docker_insecure_registry=[^ ]*' /proc/cmdline 2>/dev/null | sed 's/docker_insecure_registry=//' || true); do + if [ -n "$registry" ]; then + DOCKER_OPTS="$DOCKER_OPTS --insecure-registry=$registry" + log "Added insecure registry: $registry" + fi + done + if [ "$CONTAINERD_READY" = "true" ]; then DOCKER_OPTS="$DOCKER_OPTS --containerd=/run/containerd/containerd.sock" fi @@ -164,6 +224,219 @@ stop_runtime_daemons() { fi } +# Execute a pull command with registry fallback +# Tries registry first, falls back to Docker Hub if image not found +# Usage: execute_pull_with_fallback "docker pull alpine:latest" +# Returns: exit code of successful pull, or last failure +execute_pull_with_fallback() { + local cmd="$1" + local image="" + local tag="" + + # Extract image name from pull command + # Handles: docker pull or docker pull :tag + if echo "$cmd" | grep -qE '^docker pull '; then + image=$(echo "$cmd" | awk '{print $3}') + else + # Not a pull command, just execute it + eval "$cmd" + return $? + fi + + # If no registry configured, just run the original command + if [ -z "$DOCKER_DEFAULT_REGISTRY" ]; then + log "No registry configured, pulling from Docker Hub" + eval "$cmd" + return $? + fi + + # Check if image is already qualified (has / in it) + if echo "$image" | grep -q '/'; then + # Already qualified (e.g., docker.io/library/alpine or myregistry/image) + log "Image already qualified: $image" + eval "$cmd" + return $? + fi + + # Unqualified image - try registry first, then Docker Hub + local registry_image="$DOCKER_DEFAULT_REGISTRY/$image" + + log "Trying registry first: $registry_image" + if docker pull "$registry_image" 2>/dev/null; then + log "Successfully pulled from registry: $registry_image" + docker images | grep -E "REPOSITORY|$image" || true + return 0 + fi + + log "Image not in registry, falling back to Docker Hub: $image" + if docker pull "$image"; then + log "Successfully pulled from Docker Hub: $image" + docker images | grep -E "REPOSITORY|$image" || true + return 0 + fi + + log "ERROR: Failed to pull $image from both registry and Docker Hub" + return 1 +} + +# Check if a command is a pull command that needs fallback handling +is_pull_command() { + local cmd="$1" + echo "$cmd" | grep -qE '^docker pull ' +} + +# Helper function to transform an unqualified image name +# Must be defined before transform_docker_command which uses it +transform_image_name() { + local img="$1" + if [ -z "$img" ]; then + echo "" + return + fi + # Check if this is an image ID (hex string) - don't transform + # Short form: 12 hex chars (e7b39c54cdec) + # Long form: sha256:64 hex chars + if echo "$img" | grep -qE '^[0-9a-fA-F]{12,64}$'; then + echo "$img" + return + fi + if echo "$img" | grep -qE '^sha256:[0-9a-fA-F]{64}$'; then + echo "$img" + return + fi + # Check if image is unqualified (no /) + if ! echo "$img" | grep -q '/'; then + echo "$DOCKER_DEFAULT_REGISTRY/$img" + # Check if already has registry with port - don't transform + elif echo "$img" | grep -qE '^[^/]+:[0-9]+/'; then + echo "$img" + # Check if looks like a domain - don't transform + elif echo "$img" | grep -qE '^[a-zA-Z0-9-]+\.[a-zA-Z]'; then + echo "$img" + else + echo "$img" + fi +} + +# Transform docker commands to use default registry for unqualified images +# "docker pull container-base" → "docker pull 10.0.2.2:5000/yocto/container-base" +# "docker pull alpine" → "docker pull 10.0.2.2:5000/yocto/alpine" (if registry set) +# "docker pull docker.io/library/alpine" → unchanged (already qualified) +# Also handles "docker image *" compound commands and other image commands +# +# NOTE: Pull commands are NOT transformed here - they use execute_pull_with_fallback +# which tries registry first, then Docker Hub as fallback. +transform_docker_command() { + local cmd="$1" + + # Handle "docker image *" compound commands - convert to standard form + # docker image pull → docker pull + # docker image rm → docker rmi + # docker image ls → docker images + # docker image inspect → docker inspect (works for images) + if echo "$cmd" | grep -qE '^docker image '; then + local subcmd=$(echo "$cmd" | awk '{print $3}') + local rest=$(echo "$cmd" | cut -d' ' -f4-) + case "$subcmd" in + pull) cmd="docker pull $rest" ;; + rm) cmd="docker rmi $rest" ;; + ls) cmd="docker images $rest" ;; + inspect) cmd="docker inspect $rest" ;; + tag) cmd="docker tag $rest" ;; + push) cmd="docker push $rest" ;; + prune) cmd="docker image prune $rest" ;; # keep as-is, docker supports it + history) cmd="docker history $rest" ;; + *) ;; # pass through unknown subcommands + esac + fi + + # Only transform if default registry is configured + if [ -z "$DOCKER_DEFAULT_REGISTRY" ]; then + echo "$cmd" + return + fi + + # NOTE: docker images, inspect, history, rmi, tag do NOT get transformed. + # These commands operate on local images - the user specifies exactly what they have. + # Transform only applies to pull/run where we're fetching images. + # + # If user has: + # - alpine:latest (from Docker Hub via fallback) + # - 10.0.2.2:5000/yocto/myapp:latest (from registry) + # + # Then: + # - "docker images alpine" → shows alpine:latest (no transform) + # - "docker inspect alpine" → inspects alpine:latest (no transform) + # - "docker rmi alpine" → removes alpine:latest (no transform) + + # Pull commands are handled by execute_pull_with_fallback, not transformed here + if echo "$cmd" | grep -qE '^docker pull '; then + echo "$cmd" + return + fi + + # Check if this is a run command + if echo "$cmd" | grep -qE '^docker run '; then + # Extract the image reference (handles "docker run [opts] img [cmd]") + local docker_cmd="run" + local rest="" + + if [ "$docker_cmd" = "run" ]; then + # docker run [options] [command] + # This is trickier - image is the first non-option argument + # For simplicity, look for image pattern after run + # Skip known options that take arguments + local args=$(echo "$cmd" | cut -d' ' -f3-) + local image="" + local new_args="" + local skip_next=false + + for arg in $args; do + if [ "$skip_next" = "true" ]; then + new_args="$new_args $arg" + skip_next=false + continue + fi + + case "$arg" in + -d|--detach|-i|--interactive|-t|--tty|--rm|--privileged) + new_args="$new_args $arg" + ;; + -p|--publish|-v|--volume|-e|--env|--name|--network|-w|--workdir|--entrypoint) + new_args="$new_args $arg" + skip_next=true + ;; + -p=*|--publish=*|-v=*|--volume=*|-e=*|--env=*|--name=*|--network=*|-w=*|--workdir=*|--entrypoint=*) + new_args="$new_args $arg" + ;; + -*) + # Other options, pass through + new_args="$new_args $arg" + ;; + *) + # First non-option is the image + if [ -z "$image" ]; then + image="$arg" + else + # Rest is the command + rest="$rest $arg" + fi + ;; + esac + done + + if [ -n "$image" ]; then + local transformed=$(transform_image_name "$image") + echo "docker run$new_args $transformed$rest" + return + fi + fi + fi + + # Return unchanged + echo "$cmd" +} + handle_storage_output() { echo "Stopping Docker gracefully..." /usr/bin/docker system prune -f >/dev/null 2>&1 || true @@ -223,15 +496,36 @@ mount_input_disk # Configure networking configure_networking +# Load baked registry config (can be overridden by kernel cmdline) +load_registry_config + # Start containerd and dockerd (Docker-specific) start_containerd start_dockerd # Handle daemon mode or single command execution if [ "$RUNTIME_DAEMON" = "1" ]; then + # Export registry for daemon mode + # Note: Functions (execute_pull_with_fallback, is_pull_command) are already + # available since they're defined in this script before run_daemon_mode is called + export DOCKER_DEFAULT_REGISTRY run_daemon_mode else prepare_input_path + # Check if this is a pull command - use fallback logic + if is_pull_command "$RUNTIME_CMD"; then + # Pull commands use registry-first, Docker Hub fallback + log "Using pull with registry fallback" + execute_pull_with_fallback "$RUNTIME_CMD" + EXEC_EXIT_CODE=$? + echo "===EXIT_CODE=$EXEC_EXIT_CODE===" + graceful_shutdown + exit 0 + fi + # Transform other commands to use default registry for unqualified images + if [ -n "$DOCKER_DEFAULT_REGISTRY" ]; then + RUNTIME_CMD=$(transform_docker_command "$RUNTIME_CMD") + fi execute_command fi diff --git a/recipes-containers/vcontainer/files/vrunner.sh b/recipes-containers/vcontainer/files/vrunner.sh index cf6aafd4..af9b855c 100755 --- a/recipes-containers/vcontainer/files/vrunner.sh +++ b/recipes-containers/vcontainer/files/vrunner.sh @@ -120,6 +120,8 @@ OPTIONS: --output Output file for tar/storage output types --blob-dir Directory containing kernel/initramfs blobs --network, -n Enable networking (slirp user-mode, outbound only) + --registry Default registry for unqualified images (e.g., 10.0.2.2:5000/yocto) + --insecure-registry Mark registry as insecure (HTTP). Can repeat. --interactive, -it Run in interactive mode (connects terminal to container) --timeout QEMU timeout [default: 300] --idle-timeout Daemon idle timeout in seconds [default: 1800] @@ -166,6 +168,11 @@ EXAMPLES: # Pull an image from a registry (requires --network) vrunner.sh --network -- docker pull alpine:latest + # Pull from local registry using default registry prefix + vrunner.sh --network --registry 10.0.2.2:5000/yocto \ + -- docker pull container-base + # This becomes: docker pull 10.0.2.2:5000/yocto/container-base + # Batch import multiple OCI containers in one session vrunner.sh --batch-import --output storage.tar \ -- /path/to/app-oci:myapp:latest /path/to/db-oci:mydb:v1.0 @@ -191,6 +198,10 @@ DISABLE_KVM="false" DOCKER_CMD="" PORT_FORWARDS=() +# Registry configuration +DOCKER_REGISTRY="" +INSECURE_REGISTRIES=() + # Batch import mode BATCH_IMPORT="false" @@ -250,6 +261,16 @@ while [ $# -gt 0 ]; do PORT_FORWARDS+=("$2") shift 2 ;; + --registry) + # Default registry for unqualified images (e.g., 10.0.2.2:5000/yocto) + DOCKER_REGISTRY="$2" + shift 2 + ;; + --insecure-registry) + # Mark a registry as insecure (HTTP) + INSECURE_REGISTRIES+=("$2") + shift 2 + ;; --interactive|-it) INTERACTIVE="true" shift @@ -984,6 +1005,16 @@ if [ "$NETWORK" = "true" ]; then KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_network=1" fi +# Registry configuration for unqualified image names +if [ -n "$DOCKER_REGISTRY" ]; then + KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_registry=$DOCKER_REGISTRY" +fi + +# Insecure registries (HTTP) +for reg in "${INSECURE_REGISTRIES[@]}"; do + KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_insecure_registry=$reg" +done + # Tell init script if interactive mode if [ "$INTERACTIVE" = "true" ]; then KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_interactive=1" diff --git a/recipes-containers/vcontainer/vdkr-rootfs-image.bb b/recipes-containers/vcontainer/vdkr-rootfs-image.bb index 079f4c17..4a0c8a10 100644 --- a/recipes-containers/vcontainer/vdkr-rootfs-image.bb +++ b/recipes-containers/vcontainer/vdkr-rootfs-image.bb @@ -11,6 +11,12 @@ # Build with: # bitbake mc:vruntime-aarch64:vdkr-rootfs-image # bitbake mc:vruntime-x86-64:vdkr-rootfs-image +# +# Optional baked-in registry defaults (can still be overridden via CLI): +# Uses the same variables as container-registry infrastructure: +# CONTAINER_REGISTRY_URL = "10.0.2.2:5000" +# CONTAINER_REGISTRY_NAMESPACE = "yocto" +# CONTAINER_REGISTRY_INSECURE = "1" (or DOCKER_REGISTRY_INSECURE) SUMMARY = "Minimal Docker rootfs for vdkr" DESCRIPTION = "A minimal image containing Docker tools for use with vdkr. \ @@ -51,6 +57,13 @@ IMAGE_FEATURES = "" IMAGE_ROOTFS_SIZE = "524288" IMAGE_ROOTFS_EXTRA_SPACE = "0" +# Registry defaults - reuse common container-registry variables +# Empty URL means no baked config (can still configure via CLI) +CONTAINER_REGISTRY_URL ?= "" +CONTAINER_REGISTRY_NAMESPACE ?= "yocto" +CONTAINER_REGISTRY_INSECURE ?= "0" +DOCKER_REGISTRY_INSECURE ?= "" + # Use squashfs for smaller size (~3x compression) # The preinit mounts squashfs read-only with tmpfs overlay for writes IMAGE_FSTYPES = "squashfs" @@ -72,4 +85,39 @@ install_vdkr_init() { # Create skopeo policy install -d ${IMAGE_ROOTFS}/etc/containers echo '{"default":[{"type":"insecureAcceptAnything"}]}' > ${IMAGE_ROOTFS}/etc/containers/policy.json + + # Create baked-in registry config if specified + # Uses common CONTAINER_REGISTRY_* variables for consistency + # These defaults can be overridden via kernel cmdline (docker_registry=) + # + # NOTE: localhost URLs are auto-translated to 10.0.2.2 for QEMU slirp networking + # This allows CONTAINER_REGISTRY_URL=localhost:5000 to work for both: + # - Host-side operations (registry script, pushing) + # - vdkr inside QEMU (via 10.0.2.2 slirp gateway) + install -d ${IMAGE_ROOTFS}/etc/vdkr + if [ -n "${CONTAINER_REGISTRY_URL}" ]; then + cat > ${IMAGE_ROOTFS}/etc/vdkr/registry.conf << 'VDKR_EOF' +# vdkr registry defaults (baked at build time) +# These can be overridden via: +# - Kernel cmdline: docker_registry=... docker_insecure_registry=... +# - vdkr CLI: vdkr --registry ... or vdkr vconfig registry ... +VDKR_EOF + # Build registry URL with namespace + # Translate localhost to 10.0.2.2 for QEMU slirp networking + QEMU_REGISTRY_URL=$(echo "${CONTAINER_REGISTRY_URL}" | sed 's/^localhost/10.0.2.2/' | sed 's/^127\.0\.0\.1/10.0.2.2/') + echo "VDKR_DEFAULT_REGISTRY=\"${QEMU_REGISTRY_URL}/${CONTAINER_REGISTRY_NAMESPACE}\"" >> ${IMAGE_ROOTFS}/etc/vdkr/registry.conf + + # Handle insecure registries - check both DOCKER_REGISTRY_INSECURE and CONTAINER_REGISTRY_INSECURE + INSECURE_LIST="${DOCKER_REGISTRY_INSECURE}" + if [ "${CONTAINER_REGISTRY_INSECURE}" = "1" ] && [ -n "${QEMU_REGISTRY_URL}" ]; then + # Use the QEMU-translated URL for insecure list + INSECURE_LIST="${INSECURE_LIST} ${QEMU_REGISTRY_URL}" + fi + # Also translate any localhost entries in the insecure list + INSECURE_LIST=$(echo "${INSECURE_LIST}" | sed 's/localhost/10.0.2.2/g' | sed 's/127\.0\.0\.1/10.0.2.2/g') + if [ -n "${INSECURE_LIST}" ]; then + echo "VDKR_INSECURE_REGISTRIES=\"${INSECURE_LIST}\"" >> ${IMAGE_ROOTFS}/etc/vdkr/registry.conf + fi + bbnote "Created vdkr registry config: ${QEMU_REGISTRY_URL}/${CONTAINER_REGISTRY_NAMESPACE}" + fi } -- cgit v1.2.3-54-g00ecf