Publish & Promote
Purpose: For platform engineers, shows the image promotion pipeline from dev → staging → production.
Task Summary
This guide walks through publishing a newly built image to Harbor and promoting it across environment-scoped projects until it reaches production.
Prerequisites
- Harbor account with push access to the target project
dockerCLI orskopeoinstalledcosigninstalled for signature verification- Harbor projects created:
platform-dev,platform-staging,platform-production
Steps
1. Push the Image to the Dev Project
After a successful CI build, push the image to the dev project:
# Tag for Harbor dev project
docker tag myservice:1.4.2-a1b2c3d \
harbor.opencenter.example.com/platform-dev/myservice:1.4.2-a1b2c3d
# Push
docker push harbor.opencenter.example.com/platform-dev/myservice:1.4.2-a1b2c3d
Harbor's Trivy scanner runs automatically on push. Check the scan result in the Harbor UI under Projects > platform-dev > myservice > 1.4.2-a1b2c3d > Vulnerabilities.
2. Sign the Image
Sign the image after it passes the vulnerability scan:
cosign sign --key cosign.key \
harbor.opencenter.example.com/platform-dev/myservice:1.4.2-a1b2c3d
3. Promote to Staging
Promotion copies the image (including its signature and SBOM) between Harbor projects. Use the Harbor replication API or skopeo:
# Using skopeo (copies manifest, signature, and SBOM)
skopeo copy \
--src-creds admin:${HARBOR_PASSWORD} \
--dest-creds admin:${HARBOR_PASSWORD} \
docker://harbor.opencenter.example.com/platform-dev/myservice:1.4.2-a1b2c3d \
docker://harbor.opencenter.example.com/platform-staging/myservice:1.4.2-a1b2c3d
Harbor re-scans the image on arrival in the staging project. If the staging project has a stricter vulnerability threshold (e.g., block HIGH), the image may be quarantined.
4. Validate in Staging
Deploy the staging-tagged image to the staging cluster. FluxCD ImagePolicy can automate this:
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: myservice
namespace: flux-system
spec:
imageRepositoryRef:
name: myservice-staging
policy:
semver:
range: ">=1.4.0 <2.0.0"
Run integration tests against the staging deployment before promoting further.
5. Promote to Production
After staging validation, copy to the production project:
skopeo copy \
--src-creds admin:${HARBOR_PASSWORD} \
--dest-creds admin:${HARBOR_PASSWORD} \
docker://harbor.opencenter.example.com/platform-staging/myservice:1.4.2-a1b2c3d \
docker://harbor.opencenter.example.com/platform-production/myservice:1.4.2-a1b2c3d
Update the cluster overlay to reference the production image:
# applications/overlays/k8s-production/services/myservice/kustomization.yaml
images:
- name: myservice
newName: harbor.opencenter.example.com/platform-production/myservice
newTag: "1.4.2-a1b2c3d"
Verification
Confirm the image exists in each project with the correct digest:
# Check digest matches across all three projects
skopeo inspect docker://harbor.opencenter.example.com/platform-dev/myservice:1.4.2-a1b2c3d | jq .Digest
skopeo inspect docker://harbor.opencenter.example.com/platform-staging/myservice:1.4.2-a1b2c3d | jq .Digest
skopeo inspect docker://harbor.opencenter.example.com/platform-production/myservice:1.4.2-a1b2c3d | jq .Digest
All three digests must be identical — promotion is a copy, not a rebuild.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Push rejected with 403 | Missing project permissions | Grant push role in Harbor project settings |
| Image quarantined after promotion | Destination project has stricter CVE policy | Fix vulnerabilities or adjust threshold |
| Signature missing after copy | skopeo version < 1.14 doesn't copy cosign artifacts | Upgrade skopeo or copy signature separately with cosign copy |
Further Reading
- Image Lifecycle Overview — Full pipeline context
- Security & SBOM — Scanning thresholds and signing
- Air-Gap Mirroring — Packaging production images for offline sites