diff options
| author | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-01-12 16:09:12 +0000 |
|---|---|---|
| committer | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-02-09 03:32:52 +0000 |
| commit | 87ed625c043e4cdbabf569227b189823cd08db8e (patch) | |
| tree | a307f96f218f3be0e2741fe13079400b24ee8487 /recipes-containers/container-registry/files | |
| parent | 33944038c68d8e497e8dd9861c5ca6c4da7d48e5 (diff) | |
| download | meta-virtualization-87ed625c043e4cdbabf569227b189823cd08db8e.tar.gz | |
container-registry: add local OCI registry infrastructure
Add container registry support for Yocto container workflows:
- container-registry.bbclass with helper functions
- container-registry-index.bb generates helper script with baked paths
- docker-registry-config.bb for Docker daemon on targets
- container-oci-registry-config.bb for Podman/Skopeo/Buildah targets
- IMAGE_FEATURES container-registry for easy target configuration
Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
Diffstat (limited to 'recipes-containers/container-registry/files')
| -rw-r--r-- | recipes-containers/container-registry/files/container-registry-dev.yml | 61 | ||||
| -rw-r--r-- | recipes-containers/container-registry/files/container-registry.sh | 268 |
2 files changed, 329 insertions, 0 deletions
diff --git a/recipes-containers/container-registry/files/container-registry-dev.yml b/recipes-containers/container-registry/files/container-registry-dev.yml new file mode 100644 index 00000000..ed0a7c88 --- /dev/null +++ b/recipes-containers/container-registry/files/container-registry-dev.yml | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | # Container Registry Development Configuration | ||
| 2 | # ============================================ | ||
| 3 | # | ||
| 4 | # This is a simple configuration for running a local container registry | ||
| 5 | # for development purposes. It uses filesystem storage and listens on | ||
| 6 | # port 5000 without TLS. | ||
| 7 | # | ||
| 8 | # Usage: | ||
| 9 | # oe-run-native docker-distribution-native registry serve \ | ||
| 10 | # /path/to/container-registry-dev.yml | ||
| 11 | # | ||
| 12 | # Or with explicit paths: | ||
| 13 | # /path/to/sysroot-native/usr/sbin/registry serve \ | ||
| 14 | # /path/to/container-registry-dev.yml | ||
| 15 | # | ||
| 16 | # For production, consider: | ||
| 17 | # - Enabling TLS | ||
| 18 | # - Adding authentication | ||
| 19 | # - Using cloud storage (S3, GCS, Azure) | ||
| 20 | # - Setting up garbage collection | ||
| 21 | # | ||
| 22 | # See: https://distribution.github.io/distribution/about/configuration/ | ||
| 23 | |||
| 24 | version: 0.1 | ||
| 25 | |||
| 26 | log: | ||
| 27 | level: info | ||
| 28 | formatter: text | ||
| 29 | fields: | ||
| 30 | service: container-registry | ||
| 31 | |||
| 32 | storage: | ||
| 33 | filesystem: | ||
| 34 | # Storage directory - override with REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY env var | ||
| 35 | rootdirectory: /tmp/container-registry | ||
| 36 | # Don't redirect to external storage | ||
| 37 | redirect: | ||
| 38 | disable: true | ||
| 39 | # Maintenance settings | ||
| 40 | maintenance: | ||
| 41 | uploadpurging: | ||
| 42 | enabled: true | ||
| 43 | age: 168h # 1 week | ||
| 44 | interval: 24h | ||
| 45 | dryrun: false | ||
| 46 | |||
| 47 | http: | ||
| 48 | addr: :5000 | ||
| 49 | headers: | ||
| 50 | X-Content-Type-Options: [nosniff] | ||
| 51 | # For development - allow HTTP. In production, use TLS. | ||
| 52 | # tls: | ||
| 53 | # certificate: /path/to/cert.pem | ||
| 54 | # key: /path/to/key.pem | ||
| 55 | |||
| 56 | # Health check endpoint | ||
| 57 | health: | ||
| 58 | storagedriver: | ||
| 59 | enabled: true | ||
| 60 | interval: 10s | ||
| 61 | threshold: 3 | ||
diff --git a/recipes-containers/container-registry/files/container-registry.sh b/recipes-containers/container-registry/files/container-registry.sh new file mode 100644 index 00000000..14684c9a --- /dev/null +++ b/recipes-containers/container-registry/files/container-registry.sh | |||
| @@ -0,0 +1,268 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | # SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield | ||
| 3 | # SPDX-License-Identifier: MIT | ||
| 4 | # | ||
| 5 | # container-registry.sh | ||
| 6 | # ============================================ | ||
| 7 | # Helper script to start/stop a local container registry | ||
| 8 | # ============================================ | ||
| 9 | # | ||
| 10 | # This script manages a local docker-distribution registry server | ||
| 11 | # for development purposes. | ||
| 12 | # | ||
| 13 | # Usage: | ||
| 14 | # container-registry.sh start [config.yml] [storage-dir] | ||
| 15 | # container-registry.sh stop | ||
| 16 | # container-registry.sh status | ||
| 17 | # container-registry.sh logs | ||
| 18 | # | ||
| 19 | # Examples: | ||
| 20 | # # Start with defaults (port 5000, storage in /tmp/container-registry) | ||
| 21 | # container-registry.sh start | ||
| 22 | # | ||
| 23 | # # Start with custom config | ||
| 24 | # container-registry.sh start /path/to/config.yml | ||
| 25 | # | ||
| 26 | # # Start with custom storage | ||
| 27 | # container-registry.sh start /path/to/config.yml /var/lib/registry | ||
| 28 | # | ||
| 29 | # Environment: | ||
| 30 | # REGISTRY_BIN Path to registry binary (auto-detected from oe-run-native) | ||
| 31 | # REGISTRY_CONFIG Path to config file | ||
| 32 | # REGISTRY_STORAGE Storage directory | ||
| 33 | # REGISTRY_PORT Port to listen on (default: 5000) | ||
| 34 | # | ||
| 35 | |||
| 36 | set -e | ||
| 37 | |||
| 38 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| 39 | PID_FILE="/tmp/container-registry.pid" | ||
| 40 | LOG_FILE="/tmp/container-registry.log" | ||
| 41 | |||
| 42 | # Default configuration | ||
| 43 | REGISTRY_PORT="${REGISTRY_PORT:-5000}" | ||
| 44 | REGISTRY_STORAGE="${REGISTRY_STORAGE:-/tmp/container-registry}" | ||
| 45 | |||
| 46 | # Find registry binary | ||
| 47 | find_registry_bin() { | ||
| 48 | # Check if provided via environment | ||
| 49 | if [ -n "$REGISTRY_BIN" ] && [ -x "$REGISTRY_BIN" ]; then | ||
| 50 | echo "$REGISTRY_BIN" | ||
| 51 | return 0 | ||
| 52 | fi | ||
| 53 | |||
| 54 | # Try to find in Yocto native sysroot | ||
| 55 | local builddir="${BUILDDIR:-$(pwd)}" | ||
| 56 | local native_sysroot="$builddir/tmp/work/x86_64-linux/docker-distribution-native" | ||
| 57 | |||
| 58 | if [ -d "$native_sysroot" ]; then | ||
| 59 | local registry=$(find "$native_sysroot" -name "registry" -type f -executable 2>/dev/null | head -1) | ||
| 60 | if [ -n "$registry" ]; then | ||
| 61 | echo "$registry" | ||
| 62 | return 0 | ||
| 63 | fi | ||
| 64 | fi | ||
| 65 | |||
| 66 | # Try system PATH | ||
| 67 | if command -v registry &>/dev/null; then | ||
| 68 | command -v registry | ||
| 69 | return 0 | ||
| 70 | fi | ||
| 71 | |||
| 72 | return 1 | ||
| 73 | } | ||
| 74 | |||
| 75 | # Find config file | ||
| 76 | find_config() { | ||
| 77 | local config="$1" | ||
| 78 | |||
| 79 | if [ -n "$config" ] && [ -f "$config" ]; then | ||
| 80 | echo "$config" | ||
| 81 | return 0 | ||
| 82 | fi | ||
| 83 | |||
| 84 | # Check environment | ||
| 85 | if [ -n "$REGISTRY_CONFIG" ] && [ -f "$REGISTRY_CONFIG" ]; then | ||
| 86 | echo "$REGISTRY_CONFIG" | ||
| 87 | return 0 | ||
| 88 | fi | ||
| 89 | |||
| 90 | # Check script directory | ||
| 91 | if [ -f "$SCRIPT_DIR/container-registry-dev.yml" ]; then | ||
| 92 | echo "$SCRIPT_DIR/container-registry-dev.yml" | ||
| 93 | return 0 | ||
| 94 | fi | ||
| 95 | |||
| 96 | return 1 | ||
| 97 | } | ||
| 98 | |||
| 99 | cmd_start() { | ||
| 100 | local config="$1" | ||
| 101 | local storage="${2:-$REGISTRY_STORAGE}" | ||
| 102 | |||
| 103 | if [ -f "$PID_FILE" ]; then | ||
| 104 | local pid=$(cat "$PID_FILE") | ||
| 105 | if kill -0 "$pid" 2>/dev/null; then | ||
| 106 | echo "Registry already running (PID: $pid)" | ||
| 107 | return 1 | ||
| 108 | fi | ||
| 109 | rm -f "$PID_FILE" | ||
| 110 | fi | ||
| 111 | |||
| 112 | local registry_bin | ||
| 113 | if ! registry_bin=$(find_registry_bin); then | ||
| 114 | echo "Error: Cannot find registry binary" | ||
| 115 | echo "Build it with: bitbake docker-distribution-native" | ||
| 116 | return 1 | ||
| 117 | fi | ||
| 118 | |||
| 119 | local config_file | ||
| 120 | if ! config_file=$(find_config "$config"); then | ||
| 121 | echo "Error: Cannot find config file" | ||
| 122 | echo "Provide config file as argument or set REGISTRY_CONFIG" | ||
| 123 | return 1 | ||
| 124 | fi | ||
| 125 | |||
| 126 | # Create storage directory | ||
| 127 | mkdir -p "$storage" | ||
| 128 | |||
| 129 | echo "Starting container registry..." | ||
| 130 | echo " Binary: $registry_bin" | ||
| 131 | echo " Config: $config_file" | ||
| 132 | echo " Storage: $storage" | ||
| 133 | echo " Port: $REGISTRY_PORT" | ||
| 134 | |||
| 135 | # Export storage directory for config | ||
| 136 | export REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY="$storage" | ||
| 137 | |||
| 138 | # Start registry in background | ||
| 139 | nohup "$registry_bin" serve "$config_file" > "$LOG_FILE" 2>&1 & | ||
| 140 | local pid=$! | ||
| 141 | echo "$pid" > "$PID_FILE" | ||
| 142 | |||
| 143 | # Wait for startup | ||
| 144 | sleep 2 | ||
| 145 | |||
| 146 | if kill -0 "$pid" 2>/dev/null; then | ||
| 147 | echo "Registry started (PID: $pid)" | ||
| 148 | echo "Access at: http://localhost:$REGISTRY_PORT" | ||
| 149 | echo "Logs at: $LOG_FILE" | ||
| 150 | else | ||
| 151 | echo "Failed to start registry. Check logs: $LOG_FILE" | ||
| 152 | cat "$LOG_FILE" | ||
| 153 | return 1 | ||
| 154 | fi | ||
| 155 | } | ||
| 156 | |||
| 157 | cmd_stop() { | ||
| 158 | if [ ! -f "$PID_FILE" ]; then | ||
| 159 | echo "Registry not running (no PID file)" | ||
| 160 | return 0 | ||
| 161 | fi | ||
| 162 | |||
| 163 | local pid=$(cat "$PID_FILE") | ||
| 164 | |||
| 165 | if kill -0 "$pid" 2>/dev/null; then | ||
| 166 | echo "Stopping registry (PID: $pid)..." | ||
| 167 | kill "$pid" | ||
| 168 | sleep 2 | ||
| 169 | |||
| 170 | if kill -0 "$pid" 2>/dev/null; then | ||
| 171 | echo "Force killing..." | ||
| 172 | kill -9 "$pid" 2>/dev/null || true | ||
| 173 | fi | ||
| 174 | fi | ||
| 175 | |||
| 176 | rm -f "$PID_FILE" | ||
| 177 | echo "Registry stopped" | ||
| 178 | } | ||
| 179 | |||
| 180 | cmd_status() { | ||
| 181 | if [ ! -f "$PID_FILE" ]; then | ||
| 182 | echo "Registry not running" | ||
| 183 | return 1 | ||
| 184 | fi | ||
| 185 | |||
| 186 | local pid=$(cat "$PID_FILE") | ||
| 187 | |||
| 188 | if kill -0 "$pid" 2>/dev/null; then | ||
| 189 | echo "Registry running (PID: $pid)" | ||
| 190 | echo "Port: $REGISTRY_PORT" | ||
| 191 | |||
| 192 | # Check if responding | ||
| 193 | if curl -s "http://localhost:$REGISTRY_PORT/v2/" >/dev/null 2>&1; then | ||
| 194 | echo "Status: healthy" | ||
| 195 | |||
| 196 | # List images | ||
| 197 | local catalog=$(curl -s "http://localhost:$REGISTRY_PORT/v2/_catalog" 2>/dev/null) | ||
| 198 | if [ -n "$catalog" ]; then | ||
| 199 | echo "Catalog: $catalog" | ||
| 200 | fi | ||
| 201 | else | ||
| 202 | echo "Status: not responding" | ||
| 203 | fi | ||
| 204 | else | ||
| 205 | echo "Registry not running (stale PID file)" | ||
| 206 | rm -f "$PID_FILE" | ||
| 207 | return 1 | ||
| 208 | fi | ||
| 209 | } | ||
| 210 | |||
| 211 | cmd_logs() { | ||
| 212 | if [ -f "$LOG_FILE" ]; then | ||
| 213 | tail -f "$LOG_FILE" | ||
| 214 | else | ||
| 215 | echo "No log file found" | ||
| 216 | return 1 | ||
| 217 | fi | ||
| 218 | } | ||
| 219 | |||
| 220 | cmd_help() { | ||
| 221 | cat << EOF | ||
| 222 | Usage: $(basename "$0") <command> [options] | ||
| 223 | |||
| 224 | Commands: | ||
| 225 | start [config] [storage] Start the registry | ||
| 226 | stop Stop the registry | ||
| 227 | status Show registry status | ||
| 228 | logs Tail registry logs | ||
| 229 | help Show this help | ||
| 230 | |||
| 231 | Environment: | ||
| 232 | REGISTRY_BIN Path to registry binary | ||
| 233 | REGISTRY_CONFIG Path to config file | ||
| 234 | REGISTRY_STORAGE Storage directory (default: /tmp/container-registry) | ||
| 235 | REGISTRY_PORT Port to listen on (default: 5000) | ||
| 236 | BUILDDIR Yocto build directory (for finding native binaries) | ||
| 237 | |||
| 238 | Examples: | ||
| 239 | $(basename "$0") start | ||
| 240 | $(basename "$0") start /path/to/config.yml | ||
| 241 | $(basename "$0") status | ||
| 242 | $(basename "$0") stop | ||
| 243 | EOF | ||
| 244 | } | ||
| 245 | |||
| 246 | # Main | ||
| 247 | case "${1:-help}" in | ||
| 248 | start) | ||
| 249 | cmd_start "$2" "$3" | ||
| 250 | ;; | ||
| 251 | stop) | ||
| 252 | cmd_stop | ||
| 253 | ;; | ||
| 254 | status) | ||
| 255 | cmd_status | ||
| 256 | ;; | ||
| 257 | logs) | ||
| 258 | cmd_logs | ||
| 259 | ;; | ||
| 260 | help|--help|-h) | ||
| 261 | cmd_help | ||
| 262 | ;; | ||
| 263 | *) | ||
| 264 | echo "Unknown command: $1" | ||
| 265 | cmd_help | ||
| 266 | exit 1 | ||
| 267 | ;; | ||
| 268 | esac | ||
