Harbor Registry: The Production-Grade Docker Registry You Should Be Using
Harbor on Kubernetes via Helm, HA with Patroni/CloudNativePG, Redis Sentinel/Cluster, Trivy integration with --with-trivy, Cosign/Notation content trust, OCI artifact management (Helm charts, OPA bundles, SBOMs), garbage collection, replication, and vulnerability scanning at registry level..
20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.
- ✓Kubernetes basics (Helm, kubectl)
- ✓Docker registry concepts (push, pull, tags)
- ✓PostgreSQL and Redis familiarity
- ✓Basic understanding of container image signing and vulnerability scanning
Deploy Harbor on Kubernetes with: helm repo add harbor https://helm.goharbor.io && helm install harbor harbor/harbor --set expose.type=loadBalancer --set persistence.enabled=true --set trivy.enabled=true. Access the UI at the LoadBalancer IP, login with admin/Harbor12345, create a project, and push images: docker login . Harbor automatically scans pushed images with Trivy. Enable content trust with Cosign: cosign sign --key cosign.key . Configure replication to mirror images to a secondary Harbor or cloud registry. Set up garbage collection to reclaim storage from deleted images.
Think of Harbor as a secure, automated warehouse for your Docker images and software packages. A basic Docker registry is like a simple storage unit — you put boxes (images) in and take them out, but there's no security check, no inventory tracking, and no quality control. Harbor is a full warehouse with security guards (vulnerability scanning), librarians (content trust and signing), inventory managers (replication and garbage collection), and access control (RBAC). It checks every box for pests (vulnerabilities), stamps it with an authenticity seal (Cosign signature), keeps copies in multiple locations (replication), and periodically cleans out expired boxes (GC).
| Chrome | Firefox | Safari | Edge |
|---|---|---|---|
| ✓ | ✓ | ✓ | ✓ |
You're running 50 microservices on Kubernetes, each deployed multiple times a day. Your images live in Docker Hub or a basic registry. Security asks: 'Are all our images scanned for vulnerabilities?' Compliance asks: 'Can we prove who built each image and when?' Your team asks: 'Why is the registry so slow during deployments?' The answer to all three is Harbor — an enterprise-grade registry that's been the CNCF standard since 2020 and serves as the backbone for production container workflows at thousands of organizations.
Harbor is not just a place to store images. It's an image security platform. It integrates Trivy for automatic vulnerability scanning on push, supports Cosign and Notation for image signing and attestation, manages OCI artifacts beyond containers (Helm charts, OPA policies, SBOMs, signatures), replicates images across clouds and regions for DR, enforces retention policies with tag immutability and garbage collection, and provides a full audit trail of every push, pull, and delete.
By 2026, Harbor has become the default self-hosted registry for production Kubernetes. This guide covers deployment on Kubernetes with Helm, high-availability database configuration (Patroni, CloudNativePG, Redis Sentinel/Cluster), integration with Trivy for scanning, Cosign/Notation for content trust, OCI artifact management, replication strategies, garbage collection, and the production incident patterns that burn teams new to Harbor.
This guide is for platform engineers, DevOps teams, and SREs who need to deploy and operate Harbor in production. By the end, you'll have a production-grade Harbor deployment with HA database, automated scanning, content trust enforcement, and zero-downtime upgrades.
Deploying Harbor on Kubernetes with Helm: HA Configuration
Harbor's Helm chart is the recommended deployment method. It deploys 6+ components: core (API + UI), jobservice (GC, replication, scanning), registry (blob storage, based on Docker Distribution), trivy (vulnerability scanner), portal (web UI), and optional components like Notary, Clair, and ChartMuseum. For HA, you need high-availability for PostgreSQL and Redis — Harbor's stateful dependencies.
The Helm chart supports --set database.type=external to use an external PostgreSQL. For HA, use Patroni (PostgreSQL HA manager), CloudNativePG (Kubernetes-native operator), or a managed cloud database (RDS, Cloud SQL). CloudNativePG is the recommended choice for Kubernetes-native deployments: it manages failover, backups, and replica configuration automatically.
Redis: Harbor uses Redis for session storage (core), job queue (jobservice), and registry cache. For HA, use Redis Sentinel (for smaller deployments) or Redis Cluster (for larger ones). The Helm chart supports --set redis.type=external. Deploy Redis via the bitnami/redis Helm chart with sentinel mode: helm install redis bitnami/redis --set sentinel.enabled=true --set architecture=replication.
Storage: Harbor supports filesystem (PVC), S3, GCS, Azure Blob, and Swift backends. For production, use S3-compatible storage (MinIO, AWS S3, GCS). This decouples blob storage from Kubernetes nodes, enables multi-region replication, and provides durability. The Helm chart configures persistence.imageChartStorage.type: s3.
Ingress: Use a proper ingress controller (nginx-ingress, Traefik, or cloud LB). Harbor needs the ingress to support HTTP/2 for the registry API (it uses the Docker Registry protocol over HTTP/2). Configure TLS termination at the ingress. Set expose.type: ingress and expose.tls.secretName.
Minimal HA configuration: 3x core pods, 3x registry pods, 2x jobservice pods, external PostgreSQL (CloudNativePG cluster with 3 replicas), external Redis (sentinel with 1 primary + 2 replicas), S3 blob storage.
redis.external.sentinelAddrs must include all three sentinel addresses, not just the primary. Harbor uses sentinel to discover the current Redis primary during failover. Without all sentinel addresses, a failover breaks Harbor's connection. Format: redis-node-0.redis-headless:26379,redis-node-1.redis-headless:26379,redis-node-2.redis-headless:26379.redis.external.sentinelMasterName: mymaster. Recovery required restarting all Harbor pods to force Redis reconnection.Trivy Integration: Automatic Vulnerability Scanning at the Registry Level
Harbor integrates Trivy as its default vulnerability scanner. When configured with --set trivy.enabled=true, Harbor deploys a Trivy scanner pod that automatically scans every image pushed to the registry. Scan results appear in the Harbor UI and are exposed via API. Harbor can enforce policies based on scan results: block pull of images with critical vulnerabilities, block push of images that fail scan, or quarantine images to a separate project.
Trivy in Harbor runs as a separate deployment. It downloads the vulnerability database on startup and updates it periodically. For air-gapped environments, pre-download the Trivy DB and mount it as a volume. The scanner pod needs internet access to update the CVE database, or use a local mirror.
Configuration: trivy.severity sets the severity threshold for blocking (default: CRITICAL). trivy.ignoreUnfixed (default: true) only fails scans on vulnerabilities with a known fix. trivy.gitHubToken sets a GitHub token for API rate limiting when downloading the DB.
Scan-on-push is the default. Schedule scans for existing images with the Harbor jobservice. For large registries, prioritize scanning production-tagged images first. Harbor's scanner supports parallel scanning across multiple scanner pods for throughput.
Policy enforcement: In project configuration, enable 'Prevent vulnerable images from being pulled' and set severity to Critical. Images with any critical CVE will return 403 on pull. This prevents vulnerable images from reaching Kubernetes even if CI/CD scanning missed them.
Cosign and Notation Content Trust: Signing Images in Harbor
Harbor supports image signing and verification through two mechanisms: Cosign (Sigstore) and Notation (Notary v2). Both integrate with Harbor's content trust features to ensure that only signed images can be pulled from specific projects.
Cosign integration: Harbor stores Cosign signatures as OCI artifacts alongside the image. When you cosign sign <harbor-url>/project/image:tag, the signature is stored in Harbor as a separate OCI artifact referenced from the image manifest. Harbor does not verify signatures during push/pull by default — verification happens at the admission controller level (Kyverno) or via cosign verify. However, Harbor can enforce 'immutable tags' to prevent signature overwrite.
Notation (Notary v2) integration: Harbor has built-in support for Notation since version 2.8.0. Signature verification is enforced at the registry level: a project can be configured to require valid Notation signatures before allowing pull. This is the most mature content trust enforcement in Harbor. Set --set notary.enabled=true in the Helm chart to deploy the Notary signer.
Robot accounts: Harbor supports robot accounts for CI/CD automation. Create a robot account with push permissions, and use its credentials in CI pipelines. Robot accounts can be scoped to specific projects and expiration dates.
Best practice: use Cosign for keyless signing (via OIDC) in CI/CD pipelines, and use Notation for enterprise PKI-based signing (if you have an existing certificate authority). Harbor supports both simultaneously.
harbor robot create --name ci-bot --project production --permission push --expiration 30d.cosign verify --key cosign.pub image:tag@sha256:... and confirm the signature was created by the CI pipeline's OIDC identity.OCI Artifact Management: Beyond Container Images
Harbor supports OCI artifacts — any OCI-compliant content stored and managed like container images. This includes Helm charts, OPA policies, CNAB bundles, WASM modules, SBOMs, vulnerability reports, and custom artifacts. Harbor provides a unified UI and API for all artifact types.
Helm charts: Store and manage Helm charts directly in Harbor. Harbor's ChartMuseum component (deprecated in favor of OCI-native Helm charts) now supports pushing charts as OCI artifacts: helm push chart.tar.gz oci://harbor.example.com/project. Charts are versioned, searchable, and scanable for vulnerabilities in their dependencies.
OPA bundles: OPA/Gatekeeper policies can be stored as OCI artifacts in Harbor. This enables versioned, signed policy distribution. opa build -t oci . -o policy.tar.gz && oras push harbor.example.com/policies/kubernetes:1.0 policy.tar.gz.
SBOMs: Harbor can store CycloneDX and SPDX SBOMs as OCI artifacts. Attach SBOMs to image artifacts for supply chain transparency. Tools like Syft can generate and push SBOMs directly to Harbor: syft myapp:latest -o cyclonedx-json | oras push harbor.example.com/library/myapp:sbom-latest -.
Cosign signatures and attestations: Harbor stores Cosign signatures (.sig) and attestations (.att) as OCI artifacts referenced by the image manifest. cosign sign pushes to <image>.sig as a referrer. Harbor handles the referrers API automatically (OCI 1.1 spec).
OCI artifact management is configured per-project. Each artifact type can have its own retention policy, access control, and immutability settings.
GET /v2/<project>/<repo>/manifests/<digest>/referrers. This is how Harbor associates signatures, SBOMs, and vulnerability reports with their parent images.Garbage Collection, Replication, and Retention Policies
Harbor's garbage collection (GC) reclaims storage from blobs that are no longer referenced by any image tag. GC is critical for production registries that see frequent image pushes and deletions. Without GC, deleted images leave orphaned blobs that consume storage indefinitely.
GC configuration: Harbor's jobservice runs GC as a cron job. Default: daily at midnight. Configure via jobservice.gcCron in Helm values. Always run GC with --dry-run first to see what would be deleted. Review the GC report in Harbor UI. Enable --delete-untagged only after validating the dry-run.
Key GC risk: GC can delete blobs that are still referenced by an image tag if the reference count is temporarily inconsistent (e.g., during replication). Solution: schedule GC and replication at different times. Use S3 versioning or blob soft-delete to recover from accidental deletion.
Replication: Harbor replicates images between registries. Use cases: DR (replicate to a secondary Harbor in another region), migration (from Docker Hub to Harbor), multi-cloud (replicate to AWS ECR or GCR for cloud-native deployments), and edge distribution (replicate to edge registries).
Replication modes: push-based (Harbor pushes to remote) and pull-based (remote pulls from Harbor). Filter by repository name, tag pattern, or resource type. Replication respects Harbor's scan and content trust policies — only scan-passing images are replicated.
Retention policies: Harbor can automatically delete images based on rules: number of days since push, number of most recent tags to retain, or tag patterns to exclude. Combine with immutability to protect critical tags (latest, production) from deletion.
The Garbage Collection That Ate Our Production Images
--delete-untagged without --dry-run. Over 200 blobs shared by active images were deleted, including blobs referenced by the latest tags of critical production services.harbor gc --dry-run via the jobservice. 3) Changed GC schedule to run during lowest-traffic window (4 AM Sunday) with no replication jobs scheduled concurrently. 4) Enabled blob reference logging to audit future GC runs. 5) Implemented a pre-GC check: verify blob references against active image tags before deletion.- Never run Harbor garbage collection without
--dry-runfirst. GC with--delete-untaggedcan delete blobs shared by active tags if reference counts are temporarily incorrect during replication. - Schedule GC and replication jobs at different times. Concurrent GC and replication caused the reference count inconsistency that triggered this incident.
- Always test GC in a staging environment that mirrors production data size. A 10-image test doesn't reveal reference counting race conditions.
curl -u admin:harbor -X GET https://harbor/api/v2.0/projects/<project>/sum_quota. 2. Increase quota via Harbor UI: Projects → <project> → Configuration → Storage Quota. 3. Check if the registry backend (S3, GCS) has its own quota limits. 4. Run Harbor GC to reclaim space from deleted images.pg_stat_activity for long-running queries. 2. Ensure PostgreSQL has adequate shared_buffers (25% of RAM). 3. Check Redis connectivity: Harbor uses Redis for session caching and job queue. 4. Scale Harbor's core pods: kubectl scale deployment harbor-core --replicas=3. 5. Consider adding a CDN in front of Harbor for blob distribution.kubectl exec <harbor-core> -- curl -k https://remote-registry/v2/. 2. Check TLS certificates on both ends. For self-signed certs, add to Harbor's trust store. 3. Verify credentials: the replication rule uses a robot account or admin credentials. 4. Check the replication log in Harbor UI for specific error messages. 5. Ensure the remote registry supports the OCI distribution spec v1.0+.| File | Command / Code | Purpose |
|---|---|---|
| harbor-ha-deploy.sh | helm repo add harbor https://helm.goharbor.io | Deploying Harbor on Kubernetes with Helm |
| harbor-scan-policy.yaml | apiVersion: goharbor.io/v1alpha1 | Trivy Integration |
| harbor-signing.sh | docker pull alpine:latest | Cosign and Notation Content Trust |
| oci-artifacts.sh | helm package my-chart/ | OCI Artifact Management |
| harbor-gc-replication.sh | curl -u admin:harbor -X POST \ | Garbage Collection, Replication, and Retention Policies |
Key takeaways
Common mistakes to avoid
4 patternsUsing default admin password (Harbor12345) in production
Running GC without dry-run and deleting active blobs
Using file system storage (PVC) instead of S3 for production
Not configuring immutable tags for production images
Interview Questions on This Topic
How does Harbor handle concurrent garbage collection and image pushes? What consistency model does it use?
Frequently Asked Questions
20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.
That's Docker. Mark it forged?
5 min read · try the examples if you haven't