summaryrefslogtreecommitdiffstats
path: root/recipes-containers
diff options
context:
space:
mode:
authorBruce Ashfield <bruce.ashfield@gmail.com>2026-01-12 20:14:29 +0000
committerBruce Ashfield <bruce.ashfield@gmail.com>2026-02-09 03:32:52 +0000
commit1d8968199aa812d5c9bdc8089e0eb53da25cd877 (patch)
treec4d4d71a383bd0d430ffbf2cfed0485a3f16b4a0 /recipes-containers
parent45a4f2aa1a69bbf2f084d8d56a4c2812aea26b51 (diff)
downloadmeta-virtualization-1d8968199aa812d5c9bdc8089e0eb53da25cd877.tar.gz
container-registry: add industry-standard tag strategies
Add comprehensive tag support for registry push operations: Tag strategies (CONTAINER_REGISTRY_TAG_STRATEGY): - sha/git: short git commit hash for traceability - branch: git branch name (sanitized) for dev workflows - semver: nested SemVer tags (1.2.3 -> 1.2.3, 1.2, 1) - timestamp: YYYYMMDD-HHMMSS format - version: single version tag from PV - latest: the "latest" tag - arch: append architecture suffix Helper script enhancements: - push --tag <tag>: explicit tags (repeatable) - push --strategy <strategies>: override tag strategy - push --version <ver>: version for semver strategy - Baked-in defaults from bitbake variables - Environment variable overrides supported This aligns with industry practices: - Git SHA for CI/CD traceability - SemVer nested tags for release management - Branch tags for feature development Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
Diffstat (limited to 'recipes-containers')
-rw-r--r--recipes-containers/container-registry/README.md54
-rw-r--r--recipes-containers/container-registry/container-registry-index.bb182
2 files changed, 215 insertions, 21 deletions
diff --git a/recipes-containers/container-registry/README.md b/recipes-containers/container-registry/README.md
index 11db39bb..82932706 100644
--- a/recipes-containers/container-registry/README.md
+++ b/recipes-containers/container-registry/README.md
@@ -34,12 +34,61 @@ Script location: `${TOPDIR}/container-registry/container-registry.sh` (outside t
34| `start` | Start the container registry server | 34| `start` | Start the container registry server |
35| `stop` | Stop the container registry server | 35| `stop` | Stop the container registry server |
36| `status` | Check if registry is running | 36| `status` | Check if registry is running |
37| `push` | Push all OCI images from deploy/ to registry | 37| `push [options]` | Push all OCI images from deploy/ to registry |
38| `import <image> [name]` | Import 3rd party image to registry | 38| `import <image> [name]` | Import 3rd party image to registry |
39| `list` | List all images with their tags | 39| `list` | List all images with their tags |
40| `tags <image>` | List tags for a specific image | 40| `tags <image>` | List tags for a specific image |
41| `catalog` | Raw API catalog output | 41| `catalog` | Raw API catalog output |
42 42
43### Push Options
44
45```bash
46# Explicit tags
47container-registry.sh push --tag v1.0.0
48container-registry.sh push --tag latest --tag v1.0.0
49
50# Strategy-based (see Tag Strategies below)
51container-registry.sh push --strategy "sha branch latest"
52container-registry.sh push --strategy semver --version 1.2.3
53
54# Environment variable override
55CONTAINER_REGISTRY_TAG_STRATEGY="sha latest" container-registry.sh push
56```
57
58## Tag Strategies
59
60Configure tag generation via `CONTAINER_REGISTRY_TAG_STRATEGY` (space-separated):
61
62| Strategy | Output | Description |
63|----------|--------|-------------|
64| `timestamp` | `20260112-143022` | Build timestamp |
65| `sha` / `git` | `8a3f2b1` | Short git commit hash |
66| `branch` | `main`, `feature-login` | Git branch name (sanitized) |
67| `semver` | `1.2.3`, `1.2`, `1` | Nested SemVer from PV |
68| `version` | `1.2.3` | Single version tag |
69| `latest` | `latest` | The "latest" tag |
70| `arch` | `*-x86_64` | Append architecture suffix |
71
72### Example Workflows
73
74**Development builds** (track code changes):
75```bitbake
76CONTAINER_REGISTRY_TAG_STRATEGY = "sha branch latest"
77```
78Result: `my-app:8a3f2b1`, `my-app:feature-login`, `my-app:latest`
79
80**Release builds** (semantic versioning):
81```bitbake
82CONTAINER_REGISTRY_TAG_STRATEGY = "semver latest"
83PV = "1.2.3"
84```
85Result: `my-app:1.2.3`, `my-app:1.2`, `my-app:1`, `my-app:latest`
86
87**CI/CD** (traceability):
88```bash
89IMAGE_VERSION=1.2.3 container-registry.sh push --strategy "semver sha latest"
90```
91
43## Configuration (local.conf) 92## Configuration (local.conf)
44 93
45```bitbake 94```bitbake
@@ -52,6 +101,9 @@ CONTAINER_REGISTRY_NAMESPACE = "yocto"
52# Mark as insecure (HTTP) 101# Mark as insecure (HTTP)
53CONTAINER_REGISTRY_INSECURE = "1" 102CONTAINER_REGISTRY_INSECURE = "1"
54 103
104# Tag strategy (default: "timestamp latest")
105CONTAINER_REGISTRY_TAG_STRATEGY = "sha branch latest"
106
55# For Docker targets 107# For Docker targets
56DOCKER_REGISTRY_INSECURE = "localhost:5000" 108DOCKER_REGISTRY_INSECURE = "localhost:5000"
57 109
diff --git a/recipes-containers/container-registry/container-registry-index.bb b/recipes-containers/container-registry/container-registry-index.bb
index c3a48e94..f865bfaa 100644
--- a/recipes-containers/container-registry/container-registry-index.bb
+++ b/recipes-containers/container-registry/container-registry-index.bb
@@ -112,6 +112,8 @@ python do_generate_registry_script() {
112 registry_url = d.getVar('CONTAINER_REGISTRY_URL') 112 registry_url = d.getVar('CONTAINER_REGISTRY_URL')
113 registry_namespace = d.getVar('CONTAINER_REGISTRY_NAMESPACE') 113 registry_namespace = d.getVar('CONTAINER_REGISTRY_NAMESPACE')
114 registry_storage = d.getVar('CONTAINER_REGISTRY_STORAGE') 114 registry_storage = d.getVar('CONTAINER_REGISTRY_STORAGE')
115 tag_strategy = d.getVar('CONTAINER_REGISTRY_TAG_STRATEGY') or 'latest'
116 target_arch = d.getVar('TARGET_ARCH') or ''
115 117
116 os.makedirs(deploy_dir, exist_ok=True) 118 os.makedirs(deploy_dir, exist_ok=True)
117 119
@@ -122,14 +124,19 @@ python do_generate_registry_script() {
122# This script has all paths pre-configured for your build. 124# This script has all paths pre-configured for your build.
123# 125#
124# Usage: 126# Usage:
125# {script_path} start # Start registry server 127# {script_path} start # Start registry server
126# {script_path} stop # Stop registry server 128# {script_path} stop # Stop registry server
127# {script_path} status # Check if running 129# {script_path} status # Check if running
128# {script_path} push # Push OCI images to registry 130# {script_path} push [options] # Push OCI images to registry
129# {script_path} import <image> # Import 3rd party image 131# {script_path} import <image> # Import 3rd party image
130# {script_path} list # List all images with tags 132# {script_path} list # List all images with tags
131# {script_path} tags <image> # List tags for an image 133# {script_path} tags <image> # List tags for an image
132# {script_path} catalog # List image names (raw API) 134# {script_path} catalog # List image names (raw API)
135#
136# Push options:
137# --tag <tag> Explicit tag (can be repeated)
138# --strategy <strats> Tag strategy: timestamp, sha, branch, semver, latest, arch
139# --version <ver> Version for semver strategy (e.g., 1.2.3)
133 140
134set -e 141set -e
135 142
@@ -142,9 +149,77 @@ REGISTRY_URL="{registry_url}"
142REGISTRY_NAMESPACE="{registry_namespace}" 149REGISTRY_NAMESPACE="{registry_namespace}"
143DEPLOY_DIR_IMAGE="{deploy_dir_image}" 150DEPLOY_DIR_IMAGE="{deploy_dir_image}"
144 151
152# Baked-in defaults from bitbake (can be overridden by CLI or env vars)
153DEFAULT_TAG_STRATEGY="{tag_strategy}"
154DEFAULT_TARGET_ARCH="{target_arch}"
155
145PID_FILE="/tmp/container-registry.pid" 156PID_FILE="/tmp/container-registry.pid"
146LOG_FILE="/tmp/container-registry.log" 157LOG_FILE="/tmp/container-registry.log"
147 158
159# Generate tags based on strategy
160# Usage: generate_tags "strategy1 strategy2 ..."
161# Strategies: timestamp, sha/git, branch, semver, version, latest, arch
162generate_tags() {{
163 local strategy="${{1:-latest}}"
164 local version="${{IMAGE_VERSION:-}}"
165 local arch="${{TARGET_ARCH:-$DEFAULT_TARGET_ARCH}}"
166 local tags=""
167
168 for strat in $strategy; do
169 case "$strat" in
170 timestamp)
171 tags="$tags $(date +%Y%m%d-%H%M%S)"
172 ;;
173 sha|git)
174 local sha=$(git rev-parse --short HEAD 2>/dev/null || true)
175 [ -n "$sha" ] && tags="$tags $sha"
176 ;;
177 branch)
178 local branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)
179 if [ -n "$branch" ] && [ "$branch" != "HEAD" ]; then
180 # Sanitize: feature/login -> feature-login
181 tags="$tags $(echo $branch | tr '/_' '--')"
182 fi
183 ;;
184 semver)
185 if [ -n "$version" ]; then
186 local v="$version"
187 # Strip any suffix like +gitAUTOINC
188 v=$(echo "$v" | cut -d'+' -f1)
189 local major=$(echo "$v" | cut -d. -f1)
190 local minor=$(echo "$v" | cut -d. -f2)
191 local patch=$(echo "$v" | cut -d. -f3)
192 [ -n "$patch" ] && tags="$tags $major.$minor.$patch"
193 [ -n "$minor" ] && tags="$tags $major.$minor"
194 [ -n "$major" ] && [ "$major" != "$v" ] && tags="$tags $major"
195 fi
196 ;;
197 version)
198 if [ -n "$version" ]; then
199 local v=$(echo "$version" | cut -d'+' -f1)
200 tags="$tags $v"
201 fi
202 ;;
203 latest)
204 tags="$tags latest"
205 ;;
206 arch)
207 if [ -n "$arch" ]; then
208 local arch_tags=""
209 for t in $tags; do
210 [ "$t" != "latest" ] && arch_tags="$arch_tags ${{t}}-${{arch}}"
211 done
212 tags="$tags $arch_tags"
213 fi
214 ;;
215 esac
216 done
217
218 # Ensure at least one tag
219 [ -z "$tags" ] && tags="latest"
220 echo $tags
221}}
222
148cmd_start() {{ 223cmd_start() {{
149 if [ -f "$PID_FILE" ] && kill -0 "$(cat $PID_FILE)" 2>/dev/null; then 224 if [ -f "$PID_FILE" ] && kill -0 "$(cat $PID_FILE)" 2>/dev/null; then
150 echo "Registry already running (PID: $(cat $PID_FILE))" 225 echo "Registry already running (PID: $(cat $PID_FILE))"
@@ -213,14 +288,53 @@ cmd_status() {{
213}} 288}}
214 289
215cmd_push() {{ 290cmd_push() {{
291 shift # Remove 'push' from args
292
293 # Parse options
294 local explicit_tags=""
295 local strategy="${{CONTAINER_REGISTRY_TAG_STRATEGY:-$DEFAULT_TAG_STRATEGY}}"
296 local version="${{IMAGE_VERSION:-}}"
297
298 while [ $# -gt 0 ]; do
299 case "$1" in
300 --tag|-t)
301 explicit_tags="$explicit_tags $2"
302 shift 2
303 ;;
304 --strategy|-s)
305 strategy="$2"
306 shift 2
307 ;;
308 --version|-v)
309 version="$2"
310 shift 2
311 ;;
312 *)
313 shift
314 ;;
315 esac
316 done
317
318 # Export version for generate_tags
319 export IMAGE_VERSION="$version"
320
216 if ! curl -s "http://$REGISTRY_URL/v2/" >/dev/null 2>&1; then 321 if ! curl -s "http://$REGISTRY_URL/v2/" >/dev/null 2>&1; then
217 echo "Registry not responding at http://$REGISTRY_URL" 322 echo "Registry not responding at http://$REGISTRY_URL"
218 echo "Start it first: $0 start" 323 echo "Start it first: $0 start"
219 return 1 324 return 1
220 fi 325 fi
221 326
327 # Determine tags to use
328 local tags
329 if [ -n "$explicit_tags" ]; then
330 tags="$explicit_tags"
331 else
332 tags=$(generate_tags "$strategy")
333 fi
334
222 echo "Pushing OCI images from $DEPLOY_DIR_IMAGE" 335 echo "Pushing OCI images from $DEPLOY_DIR_IMAGE"
223 echo "To registry: $REGISTRY_URL/$REGISTRY_NAMESPACE/" 336 echo "To registry: $REGISTRY_URL/$REGISTRY_NAMESPACE/"
337 echo "Tags: $tags"
224 echo "" 338 echo ""
225 339
226 for oci_dir in "$DEPLOY_DIR_IMAGE"/*-oci; do 340 for oci_dir in "$DEPLOY_DIR_IMAGE"/*-oci; do
@@ -234,9 +348,12 @@ cmd_push() {{
234 name=$(echo "$name" | sed 's/\\.rootfs-[0-9]*//') 348 name=$(echo "$name" | sed 's/\\.rootfs-[0-9]*//')
235 349
236 echo "Pushing: $name" 350 echo "Pushing: $name"
237 "$SKOPEO_BIN" copy --dest-tls-verify=false \\ 351 for tag in $tags; do
238 "oci:$oci_dir" \\ 352 echo " -> $REGISTRY_URL/$REGISTRY_NAMESPACE/$name:$tag"
239 "docker://$REGISTRY_URL/$REGISTRY_NAMESPACE/$name:latest" 353 "$SKOPEO_BIN" copy --dest-tls-verify=false \\
354 "oci:$oci_dir" \\
355 "docker://$REGISTRY_URL/$REGISTRY_NAMESPACE/$name:$tag"
356 done
240 done 357 done
241 358
242 echo "" 359 echo ""
@@ -365,39 +482,64 @@ cmd_import() {{
365}} 482}}
366 483
367cmd_help() {{ 484cmd_help() {{
368 echo "Usage: $0 <command>" 485 echo "Usage: $0 <command> [options]"
369 echo "" 486 echo ""
370 echo "Commands:" 487 echo "Commands:"
371 echo " start Start the container registry server" 488 echo " start Start the container registry server"
372 echo " stop Stop the container registry server" 489 echo " stop Stop the container registry server"
373 echo " status Check if registry is running" 490 echo " status Check if registry is running"
374 echo " push Push all OCI images to registry" 491 echo " push [options] Push all OCI images to registry"
375 echo " import <image> [name] Import 3rd party image to registry" 492 echo " import <image> [name] Import 3rd party image to registry"
376 echo " list List all images with tags" 493 echo " list List all images with tags"
377 echo " tags <image> List tags for an image" 494 echo " tags <image> List tags for an image"
378 echo " catalog List image names (raw API)" 495 echo " catalog List image names (raw API)"
379 echo " help Show this help" 496 echo " help Show this help"
380 echo "" 497 echo ""
498 echo "Push options:"
499 echo " --tag, -t <tag> Explicit tag (can be repeated for multiple tags)"
500 echo " --strategy, -s <str> Tag strategy (default: $DEFAULT_TAG_STRATEGY)"
501 echo " --version, -v <ver> Version for semver strategy (e.g., 1.2.3)"
502 echo ""
503 echo "Tag strategies (can combine: 'sha branch latest'):"
504 echo " timestamp YYYYMMDD-HHMMSS format"
505 echo " sha, git Short git commit hash"
506 echo " branch Git branch name (sanitized)"
507 echo " semver Nested SemVer (1.2.3 -> 1.2.3, 1.2, 1)"
508 echo " version Single version tag from --version"
509 echo " latest The 'latest' tag"
510 echo " arch Append architecture suffix to other tags"
511 echo ""
381 echo "Examples:" 512 echo "Examples:"
382 echo " $0 start" 513 echo " $0 start"
383 echo " $0 push" 514 echo " $0 push # Uses default strategy"
515 echo " $0 push --tag v1.0.0 # Explicit tag"
516 echo " $0 push --tag latest --tag v1.0.0 # Multiple tags"
517 echo " $0 push --strategy 'sha branch latest' # Strategy-based"
518 echo " $0 push --strategy semver --version 1.2.3 # SemVer tags"
384 echo " $0 import docker.io/library/alpine:latest" 519 echo " $0 import docker.io/library/alpine:latest"
385 echo " $0 import docker.io/library/busybox:latest my-busybox" 520 echo " $0 import docker.io/library/busybox:latest my-busybox"
386 echo " $0 list" 521 echo " $0 list"
387 echo " $0 tags container-base" 522 echo " $0 tags container-base"
388 echo "" 523 echo ""
389 echo "Configuration:" 524 echo "Environment variables:"
390 echo " Registry URL: $REGISTRY_URL" 525 echo " CONTAINER_REGISTRY_TAG_STRATEGY Override default tag strategy"
391 echo " Namespace: $REGISTRY_NAMESPACE" 526 echo " IMAGE_VERSION Version for semver/version strategies"
392 echo " Storage: $REGISTRY_STORAGE" 527 echo " TARGET_ARCH Architecture for arch strategy"
393 echo " Deploy images: $DEPLOY_DIR_IMAGE" 528 echo ""
529 echo "Configuration (baked from bitbake):"
530 echo " Registry URL: $REGISTRY_URL"
531 echo " Namespace: $REGISTRY_NAMESPACE"
532 echo " Tag strategy: $DEFAULT_TAG_STRATEGY"
533 echo " Target arch: $DEFAULT_TARGET_ARCH"
534 echo " Storage: $REGISTRY_STORAGE"
535 echo " Deploy images: $DEPLOY_DIR_IMAGE"
394}} 536}}
395 537
396case "${{1:-help}}" in 538case "${{1:-help}}" in
397 start) cmd_start ;; 539 start) cmd_start ;;
398 stop) cmd_stop ;; 540 stop) cmd_stop ;;
399 status) cmd_status ;; 541 status) cmd_status ;;
400 push) cmd_push ;; 542 push) cmd_push "$@" ;;
401 import) cmd_import "$@" ;; 543 import) cmd_import "$@" ;;
402 list) cmd_list ;; 544 list) cmd_list ;;
403 tags) cmd_tags "$@" ;; 545 tags) cmd_tags "$@" ;;