OSSのコンテナレジストリ比較:Harbor vs Zot vs Distribution でDockerHub代替をセルフホストする
オープンソースラボ編集部 ・ 2026年6月13日
OSSのコンテナレジストリ比較:Harbor vs Zot vs Distribution でDockerHub代替をセルフホストする
DockerHub(月$5/ユーザー〜・Pull Rate Limit あり)・AWS ECR($0.10/GB/月)・GitHub Container Registry(GitHub Actions連動)に対して、Harbor(最も機能が豊富なOSSコンテナレジストリ・セキュリティスキャン搭載)・Zot(最軽量・OCI専用)・Distribution(DockerのOSSレジストリ・公式実装)はOSSのコンテナイメージレジストリです。
セルフホストコンテナレジストリを選ぶ理由
- DockerHubのRate Limit回避: 匿名ユーザーは6時間で100 Pull制限。大規模CIで頻繁にブロックされる
- コスト: ECRはデータ転送費用が高い($0.09/GB〜)。同一VPC内のセルフホストならほぼ無料
- セキュリティ: 社内専用レジストリでイメージを外部に公開しない
- スキャン: HarborはTrivyでイメージの脆弱性を自動スキャン
主要ツールの概要
Harbor
2016年にVMwareが開発したGo製のOSSコンテナレジストリです。CNCF Graduatedプロジェクト・GitHubスター24k+。OCI準拠・Docker/Helm Chart対応・Trivyによる脆弱性スキャン・LDAP/OIDC認証・レプリケーション・ガベージコレクションを備えた本番グレードのレジストリです。KubernetesクラスタのCNI(Harbor→k8s)構成で広く使われています。
# Harbor を Docker Compose でセルフホスト(本番構成)
curl -L https://github.com/goharbor/harbor/releases/download/v2.11.0/harbor-online-installer-v2.11.0.tgz | tar xz
cd harbor
# 設定ファイルを生成
cp harbor.yml.tmpl harbor.yml
# harbor.yml を編集(最低限の設定)
cat > harbor.yml << 'EOF'
hostname: registry.yourcompany.com
https:
port: 443
certificate: /etc/letsencrypt/live/registry.yourcompany.com/fullchain.pem
private_key: /etc/letsencrypt/live/registry.yourcompany.com/privkey.pem
harbor_admin_password: your-secure-admin-password
database:
password: your-db-password
max_idle_conns: 50
max_open_conns: 100
data_volume: /data/harbor
trivy:
ignore_unfixed: false
skip_update: false
offline_scan: false
security_check: vuln
insecure: false
jobservice:
max_job_workers: 10
log:
level: warning
local:
rotate_count: 50
rotate_size: 200m
location: /var/log/harbor
EOF
# インストール・起動(--with-trivy でスキャン機能を有効化)
./install.sh --with-trivy
# HarborにDockerイメージをプッシュ・プル
# Docker loginでHarborに認証
docker login registry.yourcompany.com -u admin -p your-secure-admin-password
# イメージをビルドしてHarborにプッシュ
docker build -t myapp:v1.2.3 .
docker tag myapp:v1.2.3 registry.yourcompany.com/myproject/myapp:v1.2.3
docker push registry.yourcompany.com/myproject/myapp:v1.2.3
# Kubernetes からHarborのイメージをプル
kubectl create secret docker-registry harbor-secret --docker-server=registry.yourcompany.com --docker-username=robot-account --docker-password=robot-token --namespace=production
# Deploymentでシークレットを使用
kubectl patch serviceaccount default -n production -p '{"imagePullSecrets": [{"name": "harbor-secret"}]}'
# .github/workflows/build-push.yml
# GitHub Actions でHarborにイメージをビルド・プッシュ
name: Build and Push to Harbor
on:
push:
branches: [main]
tags: ['v*']
env:
REGISTRY: registry.yourcompany.com
IMAGE_NAME: myproject/myapp
jobs:
build-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.HARBOR_USER }}
password: ${{ secrets.HARBOR_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=sha,prefix=sha-
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
- name: Trivy Security Scan
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
format: sarif
output: trivy-results.sarif
severity: CRITICAL,HIGH
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-results.sarif
# Harbor REST APIでイメージ管理を自動化
import httpx
from base64 import b64encode
HARBOR_URL = "https://registry.yourcompany.com"
AUTH = b64encode(b"admin:your-secure-admin-password").decode()
headers = {
"Authorization": f"Basic {AUTH}",
"Content-Type": "application/json",
}
# プロジェクト一覧を取得
def list_projects():
resp = httpx.get(f"{HARBOR_URL}/api/v2.0/projects", headers=headers)
return resp.json()
# リポジトリのタグ一覧を取得
def list_tags(project: str, repo: str):
resp = httpx.get(
f"{HARBOR_URL}/api/v2.0/projects/{project}/repositories/{repo}/artifacts",
headers=headers,
params={"page": 1, "page_size": 50, "with_scan_overview": True},
)
return resp.json()
# 古いイメージタグを削除(30日以上前のshaタグを削除)
def cleanup_old_tags(project: str, repo: str, keep_days: int = 30):
from datetime import datetime, timezone, timedelta
cutoff = datetime.now(timezone.utc) - timedelta(days=keep_days)
artifacts = list_tags(project, repo)
deleted = 0
for artifact in artifacts:
push_time = datetime.fromisoformat(
artifact["push_time"].replace("Z", "+00:00")
)
# sha- で始まるビルドキャッシュタグのみ削除(latest等は除外)
is_sha_tag = any(
t["name"].startswith("sha-") for t in artifact.get("tags", [])
)
if push_time < cutoff and is_sha_tag:
digest = artifact["digest"]
httpx.delete(
f"{HARBOR_URL}/api/v2.0/projects/{project}/repositories/{repo}/artifacts/{digest}",
headers=headers,
)
deleted += 1
print(f"Deleted {deleted} old artifacts")
return deleted
Distribution(旧 Docker Registry 2.0)
Dockerが2013年に公開したGo製のOSSコンテナレジストリです。GitHubスター9k+。OCIとDockerイメージフォーマットに対応したシンプルなレジストリで、UIはなくAPIとDockerコマンドで操作します。Harborの内部レジストリとしても使われています。
# docker-compose.yml - Distribution(最軽量構成)
version: '3.8'
services:
registry:
image: registry:2
restart: unless-stopped
ports:
- "5000:5000"
environment:
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry
REGISTRY_HTTP_TLS_CERTIFICATE: /certs/fullchain.pem
REGISTRY_HTTP_TLS_KEY: /certs/privkey.pem
volumes:
- registry_data:/var/lib/registry
- ./auth:/auth
- ./certs:/certs
volumes:
registry_data:
# htpasswdファイルを作成(Basic認証)
mkdir auth
docker run --rm --entrypoint htpasswd httpd:2 -Bbn myuser mypassword > auth/htpasswd
# 使用例
docker login localhost:5000 -u myuser -p mypassword
docker pull nginx:alpine
docker tag nginx:alpine localhost:5000/nginx:alpine
docker push localhost:5000/nginx:alpine
機能比較表
| 比較項目 | Harbor | Zot | Distribution |
|---|---|---|---|
| WebUI | ✅ | ❌ | ❌ |
| 脆弱性スキャン | ✅(Trivy) | ✅(Trivy連携) | ❌ |
| Helm Chart対応 | ✅ | ✅ | ❌ |
| LDAP/OIDC | ✅ | ✅ | ❌(別途) |
| マルチレプリカ | ✅ | ✅ | △ |
| メモリ使用量 | 1GB〜 | 64MB〜 | 32MB〜 |
| GitHub Stars | 24k+ | 0.7k+ | 9k+ |
HarborのTrivyスキャン結果をDevOpsカテゴリ/categories/devopsのSigNoz・Grafanaダッシュボードで可視化してセキュリティダッシュボードを構築します。KubernetesクラスタのコンテナをHarborから取得するにはDevOpsカテゴリ/categories/devopsのHelm・k9sと組み合わせてデプロイを管理します。
FAQ
Q. DockerHubのRate Limitを回避するためにHarborをミラーとして使うには?
A. Harborのプロキシキャッシュ機能を使います。①Harbor WebUI → Administration → Registries → New Endpoint → DockerHubを追加②Projects → New Project → プロキシキャッシュを有効化・DockerHubエンドポイントを選択③Kubernetes等のimagePullPolicyでHarborのミラーURLを使う(registry.yourcompany.com/dockerhub-proxy/library/nginx:latest)。初回はDockerHubから取得してHarborにキャッシュされ、以降はHarborから高速に返します。DockerHubのRate Limitが発生しなくなり、内部ネットワークの帯域も節約できます。
Q. HarborのTrivyスキャンで脆弱性が見つかったときに自動でPushを拒否するには?
A. Harbor Webhook + CI/CDで実装します。①Harborのプロジェクト → Webhooks → SCanning Completedイベントでエンドポイントに通知②カスタムAPIがスキャン結果を確認してCRITICAL/HIGH脆弱性があればCI/CDのデプロイを停止③または Harbor のタグ不変性 + Cosign でサイン済みイメージのみデプロイを許可。GitHub Actionsではtrivy-actionでスキャンして--exit-code 1を設定するとCRITICAL検出時にステップを失敗させられます。
Q. AWS ECRとHarborセルフホストのコスト比較は?
A. 月100GB転送・500GBストレージの場合: AWS ECR: ストレージ$50 + データ転送(ECR→EC2同リージョンは無料・別リージョンは$0.09/GB)で合計約$50〜。Harbor(EC2 t3.small): インスタンス$15.18/月 + EBSストレージ500GB $50 + 運用コスト(バックアップ・モニタリング)で合計約$70〜。ECRはシンプルさとAWSサービス統合の価値があるが、Harborはスキャン・LDAP・WebUIが無料で付いてくる点でエンタープライズ価値が高い。マルチクラウド・オンプレ・Kubernetes環境が複数あるならHarborのコスパが良くなります。
Q. HarborのOIDC設定でOktaと連携するには?
A. Harbor WebUI → Administration → Configuration → Authentication → OIDC を選択。設定値: OIDC Endpoint = OktaのIssuer URL(https://yourorg.okta.com/oauth2/default)、OIDC Client ID/Secret = OktaアプリのClient ID/Secret、OIDC Scope = openid profile email groups、OIDC Admin Group = harbor-admins(OktaグループをHarborAdminにマッピング)。Harborへのログインで「Login via OIDC Provider」ボタンが表示されOktaSSO認証が使えます。
まとめ
| ユースケース | 推奨ツール |
|---|---|
| 本番グレード・脆弱性スキャン・LDAP/OIDC統合 | Harbor |
| OCI専用・超軽量・CI向けミラー | Zot |
| シンプルなセルフホスト・最低限の機能 | Distribution |