diff options
| author | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-01-12 21:12:03 +0000 |
|---|---|---|
| committer | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-02-09 03:32:52 +0000 |
| commit | 68320b2c0a6751bf54ae9376d6e1e1dab30c0376 (patch) | |
| tree | 88c9e017796b496dc34099a6ee1df5b123b3f229 /recipes-containers/container-registry | |
| parent | 8b19fa53399cdeb18b1cdd41276ecac5a4f659b0 (diff) | |
| download | meta-virtualization-68320b2c0a6751bf54ae9376d6e1e1dab30c0376.tar.gz | |
container-registry: add management commands and documentation
Registry management commands:
- delete <image>:<tag>: Remove tagged images from registry
- gc: Garbage collection with dry-run preview and confirmation
- push <image> --tag: Explicit tags now require image name
(prevents accidentally tagging all images with same version)
Config improvements:
- Copy config to storage directory with baked-in storage path
- Fixes gc which reads config directly (not via env var)
- All registry files now in ${TOPDIR}/container-registry/
Documentation:
- Development Loop workflow (build, push, pull, test)
- Build-time OCI labels (revision, branch, created)
- Complete command reference
Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
Diffstat (limited to 'recipes-containers/container-registry')
3 files changed, 272 insertions, 17 deletions
diff --git a/recipes-containers/container-registry/README.md b/recipes-containers/container-registry/README.md index 82932706..1a0f74eb 100644 --- a/recipes-containers/container-registry/README.md +++ b/recipes-containers/container-registry/README.md | |||
| @@ -34,8 +34,10 @@ 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 [options]` | Push all OCI images from deploy/ to registry | | 37 | | `push [image] [options]` | Push 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 | | `delete <image>:<tag>` | Delete a tagged image from registry | | ||
| 40 | | `gc` | Garbage collect unreferenced blobs | | ||
| 39 | | `list` | List all images with their tags | | 41 | | `list` | List all images with their tags | |
| 40 | | `tags <image>` | List tags for a specific image | | 42 | | `tags <image>` | List tags for a specific image | |
| 41 | | `catalog` | Raw API catalog output | | 43 | | `catalog` | Raw API catalog output | |
| @@ -43,9 +45,9 @@ Script location: `${TOPDIR}/container-registry/container-registry.sh` (outside t | |||
| 43 | ### Push Options | 45 | ### Push Options |
| 44 | 46 | ||
| 45 | ```bash | 47 | ```bash |
| 46 | # Explicit tags | 48 | # Explicit tags (require image name) |
| 47 | container-registry.sh push --tag v1.0.0 | 49 | container-registry.sh push container-base --tag v1.0.0 |
| 48 | container-registry.sh push --tag latest --tag v1.0.0 | 50 | container-registry.sh push container-base --tag latest --tag v1.0.0 |
| 49 | 51 | ||
| 50 | # Strategy-based (see Tag Strategies below) | 52 | # Strategy-based (see Tag Strategies below) |
| 51 | container-registry.sh push --strategy "sha branch latest" | 53 | container-registry.sh push --strategy "sha branch latest" |
| @@ -89,6 +91,64 @@ Result: `my-app:1.2.3`, `my-app:1.2`, `my-app:1`, `my-app:latest` | |||
| 89 | IMAGE_VERSION=1.2.3 container-registry.sh push --strategy "semver sha latest" | 91 | IMAGE_VERSION=1.2.3 container-registry.sh push --strategy "semver sha latest" |
| 90 | ``` | 92 | ``` |
| 91 | 93 | ||
| 94 | ## Development Loop | ||
| 95 | |||
| 96 | The default strategy (`timestamp latest`) supports a simple development workflow: | ||
| 97 | |||
| 98 | ```bash | ||
| 99 | # Build | ||
| 100 | bitbake container-base | ||
| 101 | |||
| 102 | # Push (creates both timestamp tag AND :latest) | ||
| 103 | ./container-registry/container-registry.sh push | ||
| 104 | |||
| 105 | # Pull on target - :latest is implicit, gets your most recent push | ||
| 106 | vdkr pull container-base | ||
| 107 | |||
| 108 | # Test | ||
| 109 | vdkr run container-base /bin/sh | ||
| 110 | |||
| 111 | # Repeat: rebuild, push, pull - no tag hunting needed | ||
| 112 | ``` | ||
| 113 | |||
| 114 | Each push overwrites `:latest` with your newest build. The timestamp tags (`20260112-143022`) remain for rollback/debugging. | ||
| 115 | |||
| 116 | ## Build-Time OCI Labels | ||
| 117 | |||
| 118 | Container images automatically include standard OCI traceability labels: | ||
| 119 | |||
| 120 | ```bash | ||
| 121 | $ skopeo inspect oci:container-base-oci | jq '.Labels' | ||
| 122 | { | ||
| 123 | "org.opencontainers.image.revision": "8a3f2b1", | ||
| 124 | "org.opencontainers.image.ref.name": "master", | ||
| 125 | "org.opencontainers.image.created": "2026-01-12T20:32:24Z" | ||
| 126 | } | ||
| 127 | ``` | ||
| 128 | |||
| 129 | | Label | Source | Description | | ||
| 130 | |-------|--------|-------------| | ||
| 131 | | `org.opencontainers.image.revision` | git SHA from TOPDIR | Code traceability | | ||
| 132 | | `org.opencontainers.image.ref.name` | git branch from TOPDIR | Branch tracking | | ||
| 133 | | `org.opencontainers.image.created` | Build timestamp | When image was built | | ||
| 134 | | `org.opencontainers.image.version` | PV (if set) | Semantic version | | ||
| 135 | |||
| 136 | ### Customizing Labels | ||
| 137 | |||
| 138 | ```bitbake | ||
| 139 | # In local.conf or image recipe | ||
| 140 | |||
| 141 | # Explicit override (e.g., from CI/CD) | ||
| 142 | OCI_IMAGE_REVISION = "${CI_COMMIT_SHA}" | ||
| 143 | OCI_IMAGE_BRANCH = "${CI_BRANCH}" | ||
| 144 | |||
| 145 | # Disable specific label | ||
| 146 | OCI_IMAGE_REVISION = "none" | ||
| 147 | |||
| 148 | # Disable all auto-labels | ||
| 149 | OCI_IMAGE_AUTO_LABELS = "0" | ||
| 150 | ``` | ||
| 151 | |||
| 92 | ## Configuration (local.conf) | 152 | ## Configuration (local.conf) |
| 93 | 153 | ||
| 94 | ```bitbake | 154 | ```bitbake |
diff --git a/recipes-containers/container-registry/container-registry-index.bb b/recipes-containers/container-registry/container-registry-index.bb index f865bfaa..75090faa 100644 --- a/recipes-containers/container-registry/container-registry-index.bb +++ b/recipes-containers/container-registry/container-registry-index.bb | |||
| @@ -93,6 +93,7 @@ CONTAINER_REGISTRY_SCRIPT = "${CONTAINER_REGISTRY_STORAGE}/container-registry.sh | |||
| 93 | python do_generate_registry_script() { | 93 | python do_generate_registry_script() { |
| 94 | import os | 94 | import os |
| 95 | import stat | 95 | import stat |
| 96 | import shutil | ||
| 96 | 97 | ||
| 97 | script_path = d.getVar('CONTAINER_REGISTRY_SCRIPT') | 98 | script_path = d.getVar('CONTAINER_REGISTRY_SCRIPT') |
| 98 | deploy_dir = d.getVar('DEPLOY_DIR') | 99 | deploy_dir = d.getVar('DEPLOY_DIR') |
| @@ -105,9 +106,6 @@ python do_generate_registry_script() { | |||
| 105 | # Find skopeo binary path | 106 | # Find skopeo binary path |
| 106 | skopeo_bin = os.path.join(d.getVar('STAGING_SBINDIR_NATIVE') or '', 'skopeo') | 107 | skopeo_bin = os.path.join(d.getVar('STAGING_SBINDIR_NATIVE') or '', 'skopeo') |
| 107 | 108 | ||
| 108 | # Config file path | ||
| 109 | config_file = os.path.join(d.getVar('THISDIR'), 'files', 'container-registry-dev.yml') | ||
| 110 | |||
| 111 | # Registry settings | 109 | # Registry settings |
| 112 | registry_url = d.getVar('CONTAINER_REGISTRY_URL') | 110 | registry_url = d.getVar('CONTAINER_REGISTRY_URL') |
| 113 | registry_namespace = d.getVar('CONTAINER_REGISTRY_NAMESPACE') | 111 | registry_namespace = d.getVar('CONTAINER_REGISTRY_NAMESPACE') |
| @@ -115,8 +113,23 @@ python do_generate_registry_script() { | |||
| 115 | tag_strategy = d.getVar('CONTAINER_REGISTRY_TAG_STRATEGY') or 'latest' | 113 | tag_strategy = d.getVar('CONTAINER_REGISTRY_TAG_STRATEGY') or 'latest' |
| 116 | target_arch = d.getVar('TARGET_ARCH') or '' | 114 | target_arch = d.getVar('TARGET_ARCH') or '' |
| 117 | 115 | ||
| 116 | # Create storage directory | ||
| 117 | os.makedirs(registry_storage, exist_ok=True) | ||
| 118 | os.makedirs(deploy_dir, exist_ok=True) | 118 | os.makedirs(deploy_dir, exist_ok=True) |
| 119 | 119 | ||
| 120 | # Copy config file to storage directory and update storage path | ||
| 121 | src_config = os.path.join(d.getVar('THISDIR'), 'files', 'container-registry-dev.yml') | ||
| 122 | config_file = os.path.join(registry_storage, 'registry-config.yml') | ||
| 123 | with open(src_config, 'r') as f: | ||
| 124 | config_content = f.read() | ||
| 125 | # Replace the default storage path with actual path | ||
| 126 | config_content = config_content.replace( | ||
| 127 | 'rootdirectory: /tmp/container-registry', | ||
| 128 | f'rootdirectory: {registry_storage}' | ||
| 129 | ) | ||
| 130 | with open(config_file, 'w') as f: | ||
| 131 | f.write(config_content) | ||
| 132 | |||
| 120 | script = f'''#!/bin/bash | 133 | script = f'''#!/bin/bash |
| 121 | # Container Registry Helper Script | 134 | # Container Registry Helper Script |
| 122 | # Generated by: bitbake container-registry-index -c generate_registry_script | 135 | # Generated by: bitbake container-registry-index -c generate_registry_script |
| @@ -233,7 +246,6 @@ cmd_start() {{ | |||
| 233 | fi | 246 | fi |
| 234 | 247 | ||
| 235 | mkdir -p "$REGISTRY_STORAGE" | 248 | mkdir -p "$REGISTRY_STORAGE" |
| 236 | export REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY="$REGISTRY_STORAGE" | ||
| 237 | 249 | ||
| 238 | echo "Starting container registry..." | 250 | echo "Starting container registry..." |
| 239 | echo " URL: http://$REGISTRY_URL" | 251 | echo " URL: http://$REGISTRY_URL" |
| @@ -290,10 +302,11 @@ cmd_status() {{ | |||
| 290 | cmd_push() {{ | 302 | cmd_push() {{ |
| 291 | shift # Remove 'push' from args | 303 | shift # Remove 'push' from args |
| 292 | 304 | ||
| 293 | # Parse options | 305 | # Parse options and positional args |
| 294 | local explicit_tags="" | 306 | local explicit_tags="" |
| 295 | local strategy="${{CONTAINER_REGISTRY_TAG_STRATEGY:-$DEFAULT_TAG_STRATEGY}}" | 307 | local strategy="${{CONTAINER_REGISTRY_TAG_STRATEGY:-$DEFAULT_TAG_STRATEGY}}" |
| 296 | local version="${{IMAGE_VERSION:-}}" | 308 | local version="${{IMAGE_VERSION:-}}" |
| 309 | local image_filter="" | ||
| 297 | 310 | ||
| 298 | while [ $# -gt 0 ]; do | 311 | while [ $# -gt 0 ]; do |
| 299 | case "$1" in | 312 | case "$1" in |
| @@ -309,12 +322,34 @@ cmd_push() {{ | |||
| 309 | version="$2" | 322 | version="$2" |
| 310 | shift 2 | 323 | shift 2 |
| 311 | ;; | 324 | ;; |
| 325 | -*) | ||
| 326 | echo "Unknown option: $1" | ||
| 327 | return 1 | ||
| 328 | ;; | ||
| 312 | *) | 329 | *) |
| 330 | # Positional arg = image name filter | ||
| 331 | if [ -z "$image_filter" ]; then | ||
| 332 | image_filter="$1" | ||
| 333 | fi | ||
| 313 | shift | 334 | shift |
| 314 | ;; | 335 | ;; |
| 315 | esac | 336 | esac |
| 316 | done | 337 | done |
| 317 | 338 | ||
| 339 | # Explicit tags require an image name | ||
| 340 | if [ -n "$explicit_tags" ] && [ -z "$image_filter" ]; then | ||
| 341 | echo "Error: --tag requires an image name" | ||
| 342 | echo "Usage: $0 push <image> --tag <tag>" | ||
| 343 | echo "" | ||
| 344 | echo "Examples:" | ||
| 345 | echo " $0 push container-base --tag v1.0.0" | ||
| 346 | echo " $0 push container-base --tag latest --tag v1.0.0" | ||
| 347 | echo "" | ||
| 348 | echo "To push all images, use a strategy instead:" | ||
| 349 | echo " $0 push --strategy 'timestamp latest'" | ||
| 350 | return 1 | ||
| 351 | fi | ||
| 352 | |||
| 318 | # Export version for generate_tags | 353 | # Export version for generate_tags |
| 319 | export IMAGE_VERSION="$version" | 354 | export IMAGE_VERSION="$version" |
| 320 | 355 | ||
| @@ -332,11 +367,16 @@ cmd_push() {{ | |||
| 332 | tags=$(generate_tags "$strategy") | 367 | tags=$(generate_tags "$strategy") |
| 333 | fi | 368 | fi |
| 334 | 369 | ||
| 335 | echo "Pushing OCI images from $DEPLOY_DIR_IMAGE" | 370 | if [ -n "$image_filter" ]; then |
| 371 | echo "Pushing image: $image_filter" | ||
| 372 | else | ||
| 373 | echo "Pushing all OCI images from $DEPLOY_DIR_IMAGE" | ||
| 374 | fi | ||
| 336 | echo "To registry: $REGISTRY_URL/$REGISTRY_NAMESPACE/" | 375 | echo "To registry: $REGISTRY_URL/$REGISTRY_NAMESPACE/" |
| 337 | echo "Tags: $tags" | 376 | echo "Tags: $tags" |
| 338 | echo "" | 377 | echo "" |
| 339 | 378 | ||
| 379 | local found=0 | ||
| 340 | for oci_dir in "$DEPLOY_DIR_IMAGE"/*-oci; do | 380 | for oci_dir in "$DEPLOY_DIR_IMAGE"/*-oci; do |
| 341 | [ -d "$oci_dir" ] || continue | 381 | [ -d "$oci_dir" ] || continue |
| 342 | [ -f "$oci_dir/index.json" ] || continue | 382 | [ -f "$oci_dir/index.json" ] || continue |
| @@ -347,6 +387,20 @@ cmd_push() {{ | |||
| 347 | # Remove rootfs timestamp | 387 | # Remove rootfs timestamp |
| 348 | name=$(echo "$name" | sed 's/\\.rootfs-[0-9]*//') | 388 | name=$(echo "$name" | sed 's/\\.rootfs-[0-9]*//') |
| 349 | 389 | ||
| 390 | # Filter by image name if specified | ||
| 391 | if [ -n "$image_filter" ]; then | ||
| 392 | # Match exact name or name.rootfs variant | ||
| 393 | case "$name" in | ||
| 394 | "$image_filter"|"$image_filter.rootfs") | ||
| 395 | : # match | ||
| 396 | ;; | ||
| 397 | *) | ||
| 398 | continue | ||
| 399 | ;; | ||
| 400 | esac | ||
| 401 | fi | ||
| 402 | |||
| 403 | found=1 | ||
| 350 | echo "Pushing: $name" | 404 | echo "Pushing: $name" |
| 351 | for tag in $tags; do | 405 | for tag in $tags; do |
| 352 | echo " -> $REGISTRY_URL/$REGISTRY_NAMESPACE/$name:$tag" | 406 | echo " -> $REGISTRY_URL/$REGISTRY_NAMESPACE/$name:$tag" |
| @@ -356,6 +410,19 @@ cmd_push() {{ | |||
| 356 | done | 410 | done |
| 357 | done | 411 | done |
| 358 | 412 | ||
| 413 | if [ -n "$image_filter" ] && [ "$found" = "0" ]; then | ||
| 414 | echo "Error: Image '$image_filter' not found in $DEPLOY_DIR_IMAGE" | ||
| 415 | echo "" | ||
| 416 | echo "Available images:" | ||
| 417 | for oci_dir in "$DEPLOY_DIR_IMAGE"/*-oci; do | ||
| 418 | [ -d "$oci_dir" ] || continue | ||
| 419 | [ -f "$oci_dir/index.json" ] || continue | ||
| 420 | n=$(basename "$oci_dir" | sed 's/-latest-oci$//' | sed 's/-oci$//' | sed 's/-qemux86-64//' | sed 's/-qemuarm64//' | sed 's/\\.rootfs-[0-9]*//') | ||
| 421 | echo " $n" | ||
| 422 | done | ||
| 423 | return 1 | ||
| 424 | fi | ||
| 425 | |||
| 359 | echo "" | 426 | echo "" |
| 360 | echo "Done. Catalog:" | 427 | echo "Done. Catalog:" |
| 361 | cmd_catalog | 428 | cmd_catalog |
| @@ -481,6 +548,124 @@ cmd_import() {{ | |||
| 481 | echo " # then: vdkr pull $dest_name" | 548 | echo " # then: vdkr pull $dest_name" |
| 482 | }} | 549 | }} |
| 483 | 550 | ||
| 551 | cmd_delete() {{ | ||
| 552 | local image="${{2:-}}" | ||
| 553 | |||
| 554 | if [ -z "$image" ]; then | ||
| 555 | echo "Usage: $0 delete <image>[:<tag>]" | ||
| 556 | echo "" | ||
| 557 | echo "Examples:" | ||
| 558 | echo " $0 delete container-base:v1.0.0 # Delete specific tag" | ||
| 559 | echo " $0 delete container-base:20260112-143022" | ||
| 560 | echo " $0 delete yocto/alpine:latest # With namespace" | ||
| 561 | echo "" | ||
| 562 | echo "Note: Deleting a tag removes the manifest reference." | ||
| 563 | echo "Run garbage collection to reclaim disk space." | ||
| 564 | return 1 | ||
| 565 | fi | ||
| 566 | |||
| 567 | if ! curl -s "http://$REGISTRY_URL/v2/" >/dev/null 2>&1; then | ||
| 568 | echo "Registry not responding at http://$REGISTRY_URL" | ||
| 569 | return 1 | ||
| 570 | fi | ||
| 571 | |||
| 572 | # Parse image:tag | ||
| 573 | local name tag | ||
| 574 | if echo "$image" | grep -q ':'; then | ||
| 575 | name=$(echo "$image" | rev | cut -d':' -f2- | rev) | ||
| 576 | tag=$(echo "$image" | rev | cut -d':' -f1 | rev) | ||
| 577 | else | ||
| 578 | echo "Error: Tag required. Use format: <image>:<tag>" | ||
| 579 | echo "Example: $0 delete container-base:v1.0.0" | ||
| 580 | return 1 | ||
| 581 | fi | ||
| 582 | |||
| 583 | # Add namespace if not already qualified | ||
| 584 | if ! echo "$name" | grep -q '/'; then | ||
| 585 | name="$REGISTRY_NAMESPACE/$name" | ||
| 586 | fi | ||
| 587 | |||
| 588 | echo "Deleting: $name:$tag" | ||
| 589 | |||
| 590 | # Get the digest for the tag (try OCI format first, then Docker V2) | ||
| 591 | local digest="" | ||
| 592 | for accept in "application/vnd.oci.image.manifest.v1+json" \ | ||
| 593 | "application/vnd.docker.distribution.manifest.v2+json"; do | ||
| 594 | digest=$(curl -s -I -H "Accept: $accept" \ | ||
| 595 | "http://$REGISTRY_URL/v2/$name/manifests/$tag" 2>/dev/null \ | ||
| 596 | | grep -i "docker-content-digest" | awk '{{print $2}}' | tr -d '\r\n') | ||
| 597 | [ -n "$digest" ] && break | ||
| 598 | done | ||
| 599 | |||
| 600 | if [ -z "$digest" ]; then | ||
| 601 | echo "Error: Tag not found: $name:$tag" | ||
| 602 | return 1 | ||
| 603 | fi | ||
| 604 | |||
| 605 | echo " Digest: $digest" | ||
| 606 | |||
| 607 | # Delete by digest | ||
| 608 | local status=$(curl -s -o /dev/null -w "%{{http_code}}" -X DELETE \ | ||
| 609 | "http://$REGISTRY_URL/v2/$name/manifests/$digest") | ||
| 610 | |||
| 611 | if [ "$status" = "202" ]; then | ||
| 612 | echo " Deleted successfully" | ||
| 613 | echo "" | ||
| 614 | echo "Note: Run garbage collection to reclaim disk space:" | ||
| 615 | echo " $0 gc" | ||
| 616 | elif [ "$status" = "405" ]; then | ||
| 617 | echo "Error: Deletion not enabled in registry config" | ||
| 618 | echo "Add 'storage.delete.enabled: true' to registry config and restart" | ||
| 619 | return 1 | ||
| 620 | else | ||
| 621 | echo "Error: Delete failed (HTTP $status)" | ||
| 622 | return 1 | ||
| 623 | fi | ||
| 624 | }} | ||
| 625 | |||
| 626 | cmd_gc() {{ | ||
| 627 | echo "Running garbage collection..." | ||
| 628 | echo "" | ||
| 629 | |||
| 630 | if [ ! -x "$REGISTRY_BIN" ]; then | ||
| 631 | echo "Error: Registry binary not found at $REGISTRY_BIN" | ||
| 632 | echo "Build it with: bitbake docker-distribution-native" | ||
| 633 | return 1 | ||
| 634 | fi | ||
| 635 | |||
| 636 | # Check if registry is running | ||
| 637 | local was_running=0 | ||
| 638 | if [ -f "$PID_FILE" ] && kill -0 "$(cat $PID_FILE)" 2>/dev/null; then | ||
| 639 | was_running=1 | ||
| 640 | echo "Stopping registry for garbage collection..." | ||
| 641 | cmd_stop | ||
| 642 | sleep 1 | ||
| 643 | fi | ||
| 644 | |||
| 645 | echo "Collecting garbage from: $REGISTRY_STORAGE" | ||
| 646 | echo "" | ||
| 647 | |||
| 648 | # Run garbage collection (dry-run first to show what would be deleted) | ||
| 649 | "$REGISTRY_BIN" garbage-collect --dry-run "$REGISTRY_CONFIG" 2>&1 || true | ||
| 650 | echo "" | ||
| 651 | |||
| 652 | read -p "Proceed with garbage collection? [y/N] " confirm | ||
| 653 | if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then | ||
| 654 | "$REGISTRY_BIN" garbage-collect "$REGISTRY_CONFIG" | ||
| 655 | echo "" | ||
| 656 | echo "Garbage collection complete." | ||
| 657 | else | ||
| 658 | echo "Cancelled." | ||
| 659 | fi | ||
| 660 | |||
| 661 | # Restart if it was running | ||
| 662 | if [ "$was_running" = "1" ]; then | ||
| 663 | echo "" | ||
| 664 | echo "Restarting registry..." | ||
| 665 | cmd_start | ||
| 666 | fi | ||
| 667 | }} | ||
| 668 | |||
| 484 | cmd_help() {{ | 669 | cmd_help() {{ |
| 485 | echo "Usage: $0 <command> [options]" | 670 | echo "Usage: $0 <command> [options]" |
| 486 | echo "" | 671 | echo "" |
| @@ -488,15 +673,18 @@ cmd_help() {{ | |||
| 488 | echo " start Start the container registry server" | 673 | echo " start Start the container registry server" |
| 489 | echo " stop Stop the container registry server" | 674 | echo " stop Stop the container registry server" |
| 490 | echo " status Check if registry is running" | 675 | echo " status Check if registry is running" |
| 491 | echo " push [options] Push all OCI images to registry" | 676 | echo " push [image] [opts] Push OCI images to registry" |
| 492 | echo " import <image> [name] Import 3rd party image to registry" | 677 | echo " import <image> [name] Import 3rd party image to registry" |
| 678 | echo " delete <image>:<tag> Delete a tagged image from registry" | ||
| 679 | echo " gc Garbage collect unreferenced blobs" | ||
| 493 | echo " list List all images with tags" | 680 | echo " list List all images with tags" |
| 494 | echo " tags <image> List tags for an image" | 681 | echo " tags <image> List tags for an image" |
| 495 | echo " catalog List image names (raw API)" | 682 | echo " catalog List image names (raw API)" |
| 496 | echo " help Show this help" | 683 | echo " help Show this help" |
| 497 | echo "" | 684 | echo "" |
| 498 | echo "Push options:" | 685 | echo "Push options:" |
| 499 | echo " --tag, -t <tag> Explicit tag (can be repeated for multiple tags)" | 686 | echo " <image> Image name (required when using --tag)" |
| 687 | echo " --tag, -t <tag> Explicit tag (can be repeated, requires image name)" | ||
| 500 | echo " --strategy, -s <str> Tag strategy (default: $DEFAULT_TAG_STRATEGY)" | 688 | echo " --strategy, -s <str> Tag strategy (default: $DEFAULT_TAG_STRATEGY)" |
| 501 | echo " --version, -v <ver> Version for semver strategy (e.g., 1.2.3)" | 689 | echo " --version, -v <ver> Version for semver strategy (e.g., 1.2.3)" |
| 502 | echo "" | 690 | echo "" |
| @@ -511,13 +699,15 @@ cmd_help() {{ | |||
| 511 | echo "" | 699 | echo "" |
| 512 | echo "Examples:" | 700 | echo "Examples:" |
| 513 | echo " $0 start" | 701 | echo " $0 start" |
| 514 | echo " $0 push # Uses default strategy" | 702 | echo " $0 push # Push all, default strategy" |
| 515 | echo " $0 push --tag v1.0.0 # Explicit tag" | 703 | echo " $0 push container-base # Push one, default strategy" |
| 516 | echo " $0 push --tag latest --tag v1.0.0 # Multiple tags" | 704 | echo " $0 push container-base --tag v1.0.0 # Explicit tag (one image)" |
| 517 | echo " $0 push --strategy 'sha branch latest' # Strategy-based" | 705 | echo " $0 push container-base -t latest -t v1.0.0 # Multiple explicit tags" |
| 518 | echo " $0 push --strategy semver --version 1.2.3 # SemVer tags" | 706 | echo " $0 push --strategy 'sha branch latest' # All images, strategy" |
| 707 | echo " $0 push --strategy semver --version 1.2.3 # All images, SemVer" | ||
| 519 | echo " $0 import docker.io/library/alpine:latest" | 708 | echo " $0 import docker.io/library/alpine:latest" |
| 520 | echo " $0 import docker.io/library/busybox:latest my-busybox" | 709 | echo " $0 import docker.io/library/busybox:latest my-busybox" |
| 710 | echo " $0 delete container-base:20260112-143022" | ||
| 521 | echo " $0 list" | 711 | echo " $0 list" |
| 522 | echo " $0 tags container-base" | 712 | echo " $0 tags container-base" |
| 523 | echo "" | 713 | echo "" |
| @@ -541,6 +731,8 @@ case "${{1:-help}}" in | |||
| 541 | status) cmd_status ;; | 731 | status) cmd_status ;; |
| 542 | push) cmd_push "$@" ;; | 732 | push) cmd_push "$@" ;; |
| 543 | import) cmd_import "$@" ;; | 733 | import) cmd_import "$@" ;; |
| 734 | delete) cmd_delete "$@" ;; | ||
| 735 | gc) cmd_gc ;; | ||
| 544 | list) cmd_list ;; | 736 | list) cmd_list ;; |
| 545 | tags) cmd_tags "$@" ;; | 737 | tags) cmd_tags "$@" ;; |
| 546 | catalog) cmd_catalog ;; | 738 | catalog) cmd_catalog ;; |
diff --git a/recipes-containers/container-registry/files/container-registry-dev.yml b/recipes-containers/container-registry/files/container-registry-dev.yml index ed0a7c88..80e5296c 100644 --- a/recipes-containers/container-registry/files/container-registry-dev.yml +++ b/recipes-containers/container-registry/files/container-registry-dev.yml | |||
| @@ -33,6 +33,9 @@ storage: | |||
| 33 | filesystem: | 33 | filesystem: |
| 34 | # Storage directory - override with REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY env var | 34 | # Storage directory - override with REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY env var |
| 35 | rootdirectory: /tmp/container-registry | 35 | rootdirectory: /tmp/container-registry |
| 36 | # Enable deletion of images/tags | ||
| 37 | delete: | ||
| 38 | enabled: true | ||
| 36 | # Don't redirect to external storage | 39 | # Don't redirect to external storage |
| 37 | redirect: | 40 | redirect: |
| 38 | disable: true | 41 | disable: true |
