Files
stack/docs/harbor-tag-retention-policy.md
Jason Woltje 4e96a32714
All checks were successful
ci/woodpecker/push/infra Pipeline was successful
ci/woodpecker/push/orchestrator Pipeline was successful
ci/woodpecker/push/coordinator Pipeline was successful
ci/woodpecker/push/web Pipeline was successful
ci/woodpecker/push/api Pipeline was successful
chore: switch from develop/dev to main/latest image tags
Remove develop branch references from CI, compose, env, and docs
now that all development uses trunk-based workflow on main.

- CI: remove develop branch filters and dev tag logic
- Compose: default IMAGE_TAG from dev to latest
- Env: update IMAGE_TAG default and comments
- Docs: update branching strategy, PR targets, and image tag docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:01:05 -06:00

4.4 KiB

Harbor Tag Retention Policy

This document describes the recommended tag retention policy for the Mosaic Stack container images in Harbor.

Tagging Strategy

Images are tagged based on branch and event type:

Trigger Tags Applied Example
Push to main {sha}, latest 658ec077, latest
Git tag (release) {sha}, {tag} 658ec077, v1.0.0

Tag Meanings

Tag Purpose Stability
latest Current build from main Latest
v* (e.g., v1.0.0) Versioned release Immutable
{sha} (e.g., 658ec077) Specific commit for traceability Immutable

Retention Policy Configuration

Configure in Harbor UI: Projects → mosaic → Policy → Tag Retention

Create the following retention rules in order:

Rule 1: Keep Release Tags Forever

Repositories: **
Tag filter: v*
Retain: all

Keeps all versioned releases (v1.0.0, v2.0.0, etc.)

Rule 2: Keep Latest and Dev Tags

Repositories: **
Tag filter: {latest,dev}
Retain: all

Keeps the latest and dev tags (always exactly one of each)

Rule 3: Keep Recent SHA Tags

Repositories: **
Tag filter: *
Retain: most recent 10 tags

Keeps the 10 most recent commit SHA tags for rollback capability

Expected Result

After retention runs:

  • All v* tags preserved
  • latest and dev tags preserved
  • Last 10 SHA tags preserved
  • Older SHA tags deleted

Garbage Collection

Tag retention only removes tag references. Actual blob storage is reclaimed via garbage collection.

Schedule GC

Harbor UI: Administration → Garbage Collection

Recommended schedule: Weekly (Sunday 2:00 AM)

Options:

  • ☑ Delete untagged artifacts (removes images with no tags)
  • Workers: 1 (adjust based on registry size)

Manual GC

Run on-demand after large cleanup operations:

  1. Go to Administration → Garbage Collection
  2. Click "GC Now"
  3. Monitor job status

Cleanup Commands

Delete Specific Tag (API)

# Delete a specific tag
curl -sk -X DELETE -u "$HARBOR_AUTH" \
  "https://reg.mosaicstack.dev/api/v2.0/projects/mosaic/repositories/api/artifacts/{tag}"

# Example: delete old test tag
curl -sk -X DELETE -u "robot\$woodpecker-ci:$TOKEN" \
  "https://reg.mosaicstack.dev/api/v2.0/projects/mosaic/repositories/api/artifacts/test"

List All Tags

# List tags for a repository
curl -sk -u "$HARBOR_AUTH" \
  "https://reg.mosaicstack.dev/v2/mosaic/api/tags/list" | jq '.tags'

Bulk Delete Old SHA Tags (Script)

#!/bin/bash
# Delete SHA tags older than the 10 most recent
HARBOR_AUTH="robot\$woodpecker-ci:$TOKEN"
REPO="mosaic/api"

# Get all SHA tags (8 char hex), sorted by push time
TAGS=$(curl -sk -u "$HARBOR_AUTH" \
  "https://reg.mosaicstack.dev/api/v2.0/projects/mosaic/repositories/${REPO#mosaic/}/artifacts?with_tag=true" | \
  jq -r 'sort_by(.push_time) | .[:-10] | .[].tags[]?.name | select(test("^[a-f0-9]{8}$"))')

for tag in $TAGS; do
  echo "Deleting $REPO:$tag"
  curl -sk -X DELETE -u "$HARBOR_AUTH" \
    "https://reg.mosaicstack.dev/api/v2.0/projects/mosaic/repositories/${REPO#mosaic/}/artifacts/$tag"
done

Monitoring

Check Repository Size

curl -sk -u "$HARBOR_AUTH" \
  "https://reg.mosaicstack.dev/api/v2.0/projects/mosaic" | \
  jq '{name, repo_count, chart_count}'

Check Artifact Count Per Repository

for repo in api web postgres; do
  count=$(curl -sk -u "$HARBOR_AUTH" \
    "https://reg.mosaicstack.dev/api/v2.0/projects/mosaic/repositories/$repo/artifacts" | jq 'length')
  echo "$repo: $count artifacts"
done

Best Practices

  1. Never delete latest or dev manually - CI will recreate them on next push
  2. Don't delete release tags (v*) - These should be preserved for rollbacks
  3. Run GC after bulk deletions - Reclaim storage space
  4. Monitor storage usage - Set up alerts if approaching quota
  5. Test retention policy - Use "Dry Run" option before enabling