πŸ“šBook Signing at KubeCon EU 2026Meet us at Booking.com HQ (Mon 18:30-21:00) & vCluster booth #521 (Tue 24 Mar, 12:30-1:30pm) β€” free book giveaway!RSVP Booking.com Event
Security intermediate ⏱ 12 minutes K8s 1.28+

Harbor: Private Container Registry on K8s

Deploy Harbor container registry in Kubernetes for private image hosting. Vulnerability scanning, image replication, RBAC, Helm chart repository.

By Luca Berton β€’ β€’ πŸ“– 5 min read

πŸ’‘ Quick Answer: Harbor is the CNCF container registry with vulnerability scanning, RBAC, and replication. Install: helm install harbor harbor/harbor -n harbor --create-namespace --set expose.type=ingress --set expose.ingress.hosts.core=registry.example.com --set externalURL=https://registry.example.com. Push images: docker tag myapp registry.example.com/myproject/myapp:v1 && docker push. Harbor auto-scans for CVEs on push.

The Problem

Public registries have limitations:

  • Rate limits (Docker Hub: 100 pulls/6h for anonymous)
  • No control over vulnerability scanning policies
  • Sensitive images shouldn’t leave your network
  • No fine-grained RBAC for teams
  • No replication between regions/clusters

The Solution

Install Harbor

helm repo add harbor https://helm.goharbor.io
helm install harbor harbor/harbor \
  -n harbor --create-namespace \
  --set expose.type=ingress \
  --set expose.ingress.hosts.core=registry.example.com \
  --set expose.ingress.className=nginx \
  --set externalURL=https://registry.example.com \
  --set persistence.persistentVolumeClaim.registry.size=100Gi \
  --set persistence.persistentVolumeClaim.database.size=5Gi \
  --set harborAdminPassword=StrongPassword123

# Access UI: https://registry.example.com
# Login: admin / StrongPassword123

# Verify pods
kubectl get pods -n harbor
# harbor-core-xxx           Running
# harbor-database-xxx       Running
# harbor-jobservice-xxx     Running
# harbor-portal-xxx         Running
# harbor-redis-xxx          Running
# harbor-registry-xxx       Running
# harbor-trivy-xxx          Running  ← vulnerability scanner

Push and Pull Images

# Login to Harbor
docker login registry.example.com -u admin

# Create a project in Harbor UI first (e.g., "myproject")

# Tag and push
docker tag myapp:latest registry.example.com/myproject/myapp:v1
docker push registry.example.com/myproject/myapp:v1

# Pull
docker pull registry.example.com/myproject/myapp:v1

# Use in Kubernetes
kubectl create secret docker-registry harbor-creds \
  --docker-server=registry.example.com \
  --docker-username=admin \
  --docker-password=StrongPassword123

# Reference in pod
# imagePullSecrets:
# - name: harbor-creds

Vulnerability Scanning

# Auto-scan on push (enable in project settings)
# Harbor UI β†’ Projects β†’ myproject β†’ Configuration
# βœ… Automatically scan images on push
# βœ… Prevent vulnerable images from running (severity: Critical)

# Manual scan via API
curl -X POST "https://registry.example.com/api/v2.0/projects/myproject/repositories/myapp/artifacts/v1/scan" \
  -H "Authorization: Basic $(echo -n admin:password | base64)"

# View scan results
curl "https://registry.example.com/api/v2.0/projects/myproject/repositories/myapp/artifacts/v1/additions/vulnerabilities" \
  -H "Authorization: Basic $(echo -n admin:password | base64)"

Image Replication

# Harbor UI β†’ Registries β†’ New Endpoint
# Name: docker-hub
# Provider: Docker Hub
# Endpoint URL: https://hub.docker.com

# Replication Rule (pull from Docker Hub):
# Name: cache-nginx
# Source: docker-hub / library/nginx
# Destination: myproject
# Trigger: Scheduled (daily)

# Replication Rule (push to DR site):
# Name: replicate-to-dr
# Source: myproject/*
# Destination: dr-harbor
# Trigger: Event-based (on push)

RBAC and Projects

# Project roles:
# - Project Admin: full control
# - Maintainer: push/pull, scan, manage tags
# - Developer: push/pull
# - Guest: pull only

# Create robot account for CI/CD
# Harbor UI β†’ Projects β†’ myproject β†’ Robot Accounts β†’ New
# Name: ci-pipeline
# Permissions: Push/Pull repository
# Expiration: 365 days
# β†’ Returns token for docker login

docker login registry.example.com \
  -u 'robot$myproject+ci-pipeline' \
  -p '<robot-token>'

Helm Chart Repository

# Harbor serves as Helm chart repository too

# Push Helm chart
helm package mychart/
helm push mychart-1.0.0.tgz oci://registry.example.com/myproject

# Add as Helm repo
helm repo add myproject https://registry.example.com/chartrepo/myproject \
  --username admin --password StrongPassword123
helm search repo myproject/
helm install myrelease myproject/mychart

Garbage Collection

# Schedule GC in Harbor UI β†’ Administration β†’ Garbage Collection
# Or trigger via API
curl -X POST "https://registry.example.com/api/v2.0/system/gc/schedule" \
  -H "Content-Type: application/json" \
  -H "Authorization: Basic $(echo -n admin:password | base64)" \
  -d '{"schedule":{"type":"Daily","cron":"0 0 2 * * *"}}'

# Tag retention policy
# Harbor UI β†’ Projects β†’ myproject β†’ Tag Retention
# Keep: most recent 10 tags per repository
# OR: tags pushed within last 30 days

Common Issues

ImagePullBackOff with Harbor

Self-signed cert not trusted. Add CA to containerd/docker config, or use insecure-registries for testing.

Scan results empty

Trivy database not downloaded yet. Check: kubectl logs harbor-trivy-xxx -n harbor. First scan takes time.

Storage full

Run garbage collection. Old layers from deleted tags aren’t removed until GC runs.

Best Practices

  • Auto-scan on push with severity gate β€” block Critical/High CVEs from deploying
  • Robot accounts for CI/CD β€” never use admin credentials in pipelines
  • Replication for HA β€” replicate to a second Harbor for disaster recovery
  • Tag retention policies β€” auto-cleanup old tags to save storage
  • Proxy cache β€” cache Docker Hub pulls to avoid rate limits

Key Takeaways

  • Harbor is the CNCF private registry with built-in vulnerability scanning (Trivy)
  • RBAC at project level β€” Admin, Maintainer, Developer, Guest roles
  • Image replication for DR and multi-region deployments
  • Serves as Helm chart OCI repository too
  • Vulnerability gates prevent deploying images with critical CVEs
#harbor #registry #security #container-images #vulnerability-scanning
Luca Berton
Written by Luca Berton

Principal Solutions Architect specializing in Kubernetes, AI/GPU infrastructure, and cloud-native platforms. Author of Kubernetes Recipes and creator of CopyPasteLearn courses.

Kubernetes Recipes book cover

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.

Luca Berton Ansible Pilot Ansible by Example Open Empower K8s Recipes Terraform Pilot CopyPasteLearn ProteinLens