feat(ci): Add branch-aware tagging and retention policy docs
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
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>
This commit is contained in:
@@ -9,6 +9,10 @@ variables:
|
||||
pnpm install --frozen-lockfile
|
||||
- &use_deps |
|
||||
corepack enable
|
||||
# Kaniko base command setup
|
||||
- &kaniko_setup |
|
||||
mkdir -p /kaniko/.docker
|
||||
echo "{\"auths\":{\"reg.mosaicstack.dev\":{\"username\":\"$HARBOR_USER\",\"password\":\"$HARBOR_PASS\"}}}" > /kaniko/.docker/config.json
|
||||
|
||||
steps:
|
||||
install:
|
||||
@@ -83,6 +87,12 @@ steps:
|
||||
# Docker Build & Push (main/develop only)
|
||||
# ======================
|
||||
# Requires secrets: harbor_username, harbor_password
|
||||
#
|
||||
# Tagging Strategy:
|
||||
# - Always: commit SHA (e.g., 658ec077)
|
||||
# - main branch: 'latest'
|
||||
# - develop branch: 'dev'
|
||||
# - git tags: version tag (e.g., v1.0.0)
|
||||
|
||||
# Build and push API image using Kaniko
|
||||
docker-build-api:
|
||||
@@ -92,13 +102,25 @@ steps:
|
||||
from_secret: harbor_username
|
||||
HARBOR_PASS:
|
||||
from_secret: harbor_password
|
||||
CI_COMMIT_BRANCH: ${CI_COMMIT_BRANCH}
|
||||
CI_COMMIT_TAG: ${CI_COMMIT_TAG}
|
||||
CI_COMMIT_SHA: ${CI_COMMIT_SHA}
|
||||
commands:
|
||||
- mkdir -p /kaniko/.docker
|
||||
- echo "{\"auths\":{\"reg.mosaicstack.dev\":{\"username\":\"$HARBOR_USER\",\"password\":\"$HARBOR_PASS\"}}}" > /kaniko/.docker/config.json
|
||||
- /kaniko/executor --context . --dockerfile apps/api/Dockerfile --destination reg.mosaicstack.dev/mosaic/api:${CI_COMMIT_SHA:0:8} --destination reg.mosaicstack.dev/mosaic/api:latest
|
||||
- *kaniko_setup
|
||||
- |
|
||||
DESTINATIONS="--destination reg.mosaicstack.dev/mosaic/api:${CI_COMMIT_SHA:0:8}"
|
||||
if [ "$CI_COMMIT_BRANCH" = "main" ]; then
|
||||
DESTINATIONS="$DESTINATIONS --destination reg.mosaicstack.dev/mosaic/api:latest"
|
||||
elif [ "$CI_COMMIT_BRANCH" = "develop" ]; then
|
||||
DESTINATIONS="$DESTINATIONS --destination reg.mosaicstack.dev/mosaic/api:dev"
|
||||
fi
|
||||
if [ -n "$CI_COMMIT_TAG" ]; then
|
||||
DESTINATIONS="$DESTINATIONS --destination reg.mosaicstack.dev/mosaic/api:$CI_COMMIT_TAG"
|
||||
fi
|
||||
/kaniko/executor --context . --dockerfile apps/api/Dockerfile $DESTINATIONS
|
||||
when:
|
||||
- branch: [main, develop]
|
||||
event: [push, manual]
|
||||
event: [push, manual, tag]
|
||||
depends_on:
|
||||
- build
|
||||
|
||||
@@ -110,13 +132,25 @@ steps:
|
||||
from_secret: harbor_username
|
||||
HARBOR_PASS:
|
||||
from_secret: harbor_password
|
||||
CI_COMMIT_BRANCH: ${CI_COMMIT_BRANCH}
|
||||
CI_COMMIT_TAG: ${CI_COMMIT_TAG}
|
||||
CI_COMMIT_SHA: ${CI_COMMIT_SHA}
|
||||
commands:
|
||||
- mkdir -p /kaniko/.docker
|
||||
- echo "{\"auths\":{\"reg.mosaicstack.dev\":{\"username\":\"$HARBOR_USER\",\"password\":\"$HARBOR_PASS\"}}}" > /kaniko/.docker/config.json
|
||||
- /kaniko/executor --context . --dockerfile apps/web/Dockerfile --build-arg NEXT_PUBLIC_API_URL=https://api.mosaicstack.dev --destination reg.mosaicstack.dev/mosaic/web:${CI_COMMIT_SHA:0:8} --destination reg.mosaicstack.dev/mosaic/web:latest
|
||||
- *kaniko_setup
|
||||
- |
|
||||
DESTINATIONS="--destination reg.mosaicstack.dev/mosaic/web:${CI_COMMIT_SHA:0:8}"
|
||||
if [ "$CI_COMMIT_BRANCH" = "main" ]; then
|
||||
DESTINATIONS="$DESTINATIONS --destination reg.mosaicstack.dev/mosaic/web:latest"
|
||||
elif [ "$CI_COMMIT_BRANCH" = "develop" ]; then
|
||||
DESTINATIONS="$DESTINATIONS --destination reg.mosaicstack.dev/mosaic/web:dev"
|
||||
fi
|
||||
if [ -n "$CI_COMMIT_TAG" ]; then
|
||||
DESTINATIONS="$DESTINATIONS --destination reg.mosaicstack.dev/mosaic/web:$CI_COMMIT_TAG"
|
||||
fi
|
||||
/kaniko/executor --context . --dockerfile apps/web/Dockerfile --build-arg NEXT_PUBLIC_API_URL=https://api.mosaicstack.dev $DESTINATIONS
|
||||
when:
|
||||
- branch: [main, develop]
|
||||
event: [push, manual]
|
||||
event: [push, manual, tag]
|
||||
depends_on:
|
||||
- build
|
||||
|
||||
@@ -128,12 +162,24 @@ steps:
|
||||
from_secret: harbor_username
|
||||
HARBOR_PASS:
|
||||
from_secret: harbor_password
|
||||
CI_COMMIT_BRANCH: ${CI_COMMIT_BRANCH}
|
||||
CI_COMMIT_TAG: ${CI_COMMIT_TAG}
|
||||
CI_COMMIT_SHA: ${CI_COMMIT_SHA}
|
||||
commands:
|
||||
- mkdir -p /kaniko/.docker
|
||||
- echo "{\"auths\":{\"reg.mosaicstack.dev\":{\"username\":\"$HARBOR_USER\",\"password\":\"$HARBOR_PASS\"}}}" > /kaniko/.docker/config.json
|
||||
- /kaniko/executor --context docker/postgres --dockerfile docker/postgres/Dockerfile --destination reg.mosaicstack.dev/mosaic/postgres:${CI_COMMIT_SHA:0:8} --destination reg.mosaicstack.dev/mosaic/postgres:latest
|
||||
- *kaniko_setup
|
||||
- |
|
||||
DESTINATIONS="--destination reg.mosaicstack.dev/mosaic/postgres:${CI_COMMIT_SHA:0:8}"
|
||||
if [ "$CI_COMMIT_BRANCH" = "main" ]; then
|
||||
DESTINATIONS="$DESTINATIONS --destination reg.mosaicstack.dev/mosaic/postgres:latest"
|
||||
elif [ "$CI_COMMIT_BRANCH" = "develop" ]; then
|
||||
DESTINATIONS="$DESTINATIONS --destination reg.mosaicstack.dev/mosaic/postgres:dev"
|
||||
fi
|
||||
if [ -n "$CI_COMMIT_TAG" ]; then
|
||||
DESTINATIONS="$DESTINATIONS --destination reg.mosaicstack.dev/mosaic/postgres:$CI_COMMIT_TAG"
|
||||
fi
|
||||
/kaniko/executor --context docker/postgres --dockerfile docker/postgres/Dockerfile $DESTINATIONS
|
||||
when:
|
||||
- branch: [main, develop]
|
||||
event: [push, manual]
|
||||
event: [push, manual, tag]
|
||||
depends_on:
|
||||
- build
|
||||
|
||||
167
docs/harbor-tag-retention-policy.md
Normal file
167
docs/harbor-tag-retention-policy.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# 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**
|
||||
|
||||
### Recommended Rules
|
||||
|
||||
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)
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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)
|
||||
|
||||
```bash
|
||||
#!/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
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Woodpecker-Harbor Integration Tips](../docs/work/woodpecker-harbor-integration-tips.md) (in jarvis-brain)
|
||||
- [Harbor Official Docs: Tag Retention](https://goharbor.io/docs/2.0.0/administration/tag-retention/)
|
||||
Reference in New Issue
Block a user