Files
stack/docs/harbor-tag-retention-policy.md
Jason Woltje 67da5370e2
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
feat(ci): Add branch-aware tagging and retention policy docs
Tagging Strategy:
- main branch: {sha} + 'latest'
- develop branch: {sha} + 'dev'
- git tags: {sha} + version (e.g., v1.0.0)

Also added docs/harbor-tag-retention-policy.md with:
- Recommended retention rules for Harbor
- Garbage collection schedule
- Cleanup commands and scripts
- Monitoring commands

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 18:10:16 -06:00

4.6 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
Push to develop {sha}, dev a1b2c3d4, dev
Git tag (release) {sha}, {tag} 658ec077, v1.0.0

Tag Meanings

Tag Purpose Stability
latest Current production-ready build from main Stable
dev Current development build from develop Unstable
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