Docker: 私有镜像仓库
最后更新:2026-08-26
不想把公司代码推送到公开的 Docker Hub?5 分钟搭建一个私有镜像仓库。
1. 你将学到
- Registry 镜像的部署
- 镜像推送与拉取操作
- 仓库认证配置
- 镜像清理与垃圾回收
- 仓库与 CI/CD 集成思路
2. 一个团队负责人的真实故事
(1) 痛点:代码不能推到公开仓库
Alice 不想把公司代码推送到公开的 Docker Hub——镜像里可能包含配置文件、环境变量默认值等敏感信息。但团队需要一个镜像仓库来共享构建产物,手动 docker save/load 传输太低效,5 个开发者每次传递镜像要 30 分钟。
(2) 私有 Registry 的解法
用 3 行配置就搭建了带认证的私有仓库。
BASH
# Start a private registry with authentication
docker run -d -p 5000:5000 \
-v registry-data:/var/lib/registry \
--restart=always \
--name registry registry:2
(3) 收益:5 分钟共享镜像
团队 5 分钟内就开始使用私有仓库。docker push 一次,所有人 docker pull 即可。镜像传递从 30 分钟降到 30 秒。
3. 镜像仓库方案对比
(1) 三种方案对比
| 维度 | Docker Hub(公开) | 私有 Registry | Harbor |
|---|---|---|---|
| 费用 | 免费有限额,付费 $5/月 | 完全免费 | 免费开源 |
| 认证 | Docker 账号 | htpasswd/TLS | LDAP/OIDC/DB |
| Web UI | ✅ | ❌ | ✅ |
| 镜像扫描 | ✅(付费) | ❌ | ✅(Trivy 集成) |
| 部署难度 | 零(已上线) | 低(1 条命令) | 中(Docker Compose) |
| 适用规模 | 个人/小团队 | 中小团队 | 企业级 |
(2) 镜像命名规范
TEXT
📖 仅展示
# Official images on Docker Hub
docker.io/library/nginx:1.25
# User images on Docker Hub
docker.io/myorg/myapp:v2.0
# Private registry images
localhost:5000/myapp:v2.0
registry.example.com/team/app:v1.0
4. 部署私有 Registry
▶ 示例:启动 Registry 容器(难度⭐)
BASH
# Start a basic private registry
docker run -d \
-p 5000:5000 \
--name registry \
--restart=always \
-v registry-data:/var/lib/registry \
registry:2
# Verify it's running
curl http://localhost:5000/v2/_catalog
💻 输出:
TEXT
📖 仅展示
{"repositories":[]}
(1) 数据持久化
| 方式 | 命令 | 说明 |
|---|---|---|
| Named Volume | -v registry-data:/var/lib/registry |
Docker 管理的持久化存储 |
| Bind Mount | -v /data/registry:/var/lib/registry |
指定主机目录 |
| 默认(无 -v) | 无持久化 | 容器删除后镜像数据丢失 |
⚠️ 注意: 生产环境必须使用 Volume 或 Bind Mount 持久化数据。否则 Registry 容器删除后,所有推送的镜像都会丢失。
5. 推送与拉取镜像
▶ 示例:推送到私有仓库(难度⭐⭐)
BASH
# 1. Tag an image for the private registry
docker tag nginx:1.25-alpine localhost:5000/web/nginx:v1
# 2. Push the image
docker push localhost:5000/web/nginx:v1
# 3. Verify it's in the registry
curl http://localhost:5000/v2/web/nginx/tags/list
💻 输出:
TEXT
📖 仅展示
{"name":"web/nginx","tags":["v1"]}
▶ 示例:从私有仓库拉取镜像(难度⭐⭐)
BASH
# 1. Remove the local copy
docker rmi localhost:5000/web/nginx:v1
# 2. Pull from the private registry
docker pull localhost:5000/web/nginx:v1
# 3. Run the pulled image
docker run --rm localhost:5000/web/nginx:v1 nginx -v
💻 输出:
TEXT
📖 仅展示
nginx version: nginx/1.25.3
6. 仓库认证配置
默认 Registry 无认证,任何人都能 push/pull。生产环境需要配置认证。
▶ 示例:生成 htpasswd 密码文件(难度⭐⭐⭐)
BASH
# Create a directory for auth data
mkdir -p auth
# Generate htpasswd file (requires httpd-tools / apache2-utils)
htpasswd -Bbn admin secret123 > auth/htpasswd
# Start registry with authentication
docker run -d \
-p 5000:5000 \
--name registry-auth \
--restart=always \
-v registry-data:/var/lib/registry \
-v $(pwd)/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
registry:2
(1) 认证后的操作
BASH
# Login to the private registry
docker login localhost:5000
# Username: admin
# Password: secret123
# Push (requires login)
docker push localhost:5000/myapp:v1
# Pull (requires login)
docker pull localhost:5000/myapp:v1
# Logout
docker logout localhost:5000
7. 查看仓库目录
▶ 示例:curl 查看 catalog 和 tags(难度⭐⭐)
BASH
# List all repositories
curl -s http://localhost:5000/v2/_catalog | python3 -m json.tool
# List tags for a specific repository
curl -s http://localhost:5000/v2/web/nginx/tags/list | python3 -m json.tool
# View image manifest (detailed metadata)
curl -s -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
http://localhost:5000/v2/web/nginx/manifests/v1 | python3 -m json.tool
💻 输出:
TEXT
📖 仅展示
# catalog
{
"repositories": [
"web/nginx",
"team/api"
]
}
# tags/list
{
"name": "web/nginx",
"tags": ["v1", "v2"]
}
8. 垃圾回收
Registry 中的镜像被删除后(untag),层数据不会自动清理。需要手动执行垃圾回收。
▶ 示例:垃圾回收(难度⭐⭐⭐)
BASH
# Delete a tag (mark for deletion)
curl -X DELETE -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
http://localhost:5000/v2/web/nginx/manifests/<digest>
# Run garbage collection inside the registry container
docker exec registry bin/registry garbage-collect \
/etc/docker/registry/config.yml
# Or with dry-run first (preview only)
docker exec registry bin/registry garbage-collect --dry-run \
/etc/docker/registry/config.yml
9. HTTP vs HTTPS 仓库
(1) Docker 安全策略
Docker 默认只允许 HTTPS 连接到 Registry(除了 localhost)。远程 Registry 必须配置 HTTPS 或在客户端添加 insecure-registries。
| 场景 | 安全级别 | 配置 |
|---|---|---|
localhost:5000 |
默认允许 HTTP | 无需额外配置 |
| 远程 HTTP 仓库 | 不安全,需显式允许 | insecure-registries |
| 远程 HTTPS 仓库 | ✅ 推荐 | TLS 证书 |
(2) 配置 insecure-registries(仅限测试环境)
JSON
{
"insecure-registries": ["registry.example.com:5000"]
}
🔒 安全: 生产环境必须使用 HTTPS + 受信任的 TLS 证书。insecure-registries 仅用于内部测试,流量可被中间人攻击。
10. 完整示例:部署带认证的私有仓库
BASH
# ============================================
# Complete walkthrough: Private registry with auth
# Covers: deploy, auth, push, pull, catalog, GC
# ============================================
# 1. Create directories for persistent data
mkdir -p auth registry-data
# 2. Generate htpasswd authentication file
htpasswd -Bbn admin secret123 > auth/htpasswd
# 3. Start the registry with authentication and persistence
docker run -d \
-p 5000:5000 \
--name my-registry \
--restart=always \
-v $(pwd)/registry-data:/var/lib/registry \
-v $(pwd)/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
registry:2
# 4. Login to the registry
docker login localhost:5000 -u admin -p secret123
# 5. Tag and push an image
docker tag nginx:1.25-alpine localhost:5000/web/nginx:v1.0
docker push localhost:5000/web/nginx:v1.0
# 6. Verify the push
curl -s -u admin:secret123 http://localhost:5000/v2/_catalog
curl -s -u admin:secret123 http://localhost:5000/v2/web/nginx/tags/list
# 7. Pull from another machine (after login)
docker pull localhost:5000/web/nginx:v1.0
# 8. Clean up
docker logout localhost:5000
💻 输出(节选):
TEXT
📖 仅展示
# curl catalog
{"repositories":["web/nginx"]}
# curl tags
{"name":"web/nginx","tags":["v1.0"]}
❓ 常见问题
Q 私有仓库需要多大的存储空间?
A 取决于镜像数量和大小。单个镜像 50-500 MB,10 个镜像约 1-5 GB。建议初始分配 50 GB,定期清理旧版本。企业级建议用对象存储(S3/OSS)作为 Registry 后端,存储按需扩容。
Q 怎么给仓库配 HTTPS?
A 两种方式:① 用 Nginx/Caddy 做反向代理,配置 TLS 证书(推荐);② 直接在 Registry 中配置 TLS。推荐反向代理方案——Nginx 处理 TLS 终止,Registry 专注存储。Let's Encrypt 提供免费证书。
Q 镜像多了怎么清理?
A 两步:① 通过 API DELETE 删除不需要的 tag/manifest;② 执行
registry garbage-collect 释放未引用的层数据。建议写脚本定期清理超过 N 天的旧版本。Harbor 有内置的清理策略。Q 仓库的镜像能被其他人看到吗?
A 无认证时,任何人都能 pull(匿名访问)。配置 htpasswd 认证后,必须 login 才能 push/pull。生产环境建议:pull 需只读权限,push 需写权限(Registry 2.8+ 支持 RBAC)。
Q Harbor 和 Registry 哪个好用?
A Registry 是极简仓库(适合小团队/CI),Harbor 是企业级仓库(Web UI + 镜像扫描 + RBAC + 审计日志)。团队 <10 人用 Registry,>10 人或有合规需求用 Harbor。Harbor 本身用 Docker Compose 部署,5 分钟可搭建。
📖 小节
registry:2镜像 1 条命令启动私有仓库,必须用 Volume 持久化数据- 镜像命名规则:
registry-host/repo:tag,push 前必须先 tag - htpasswd 认证保护仓库,docker login 后才能 push/pull
curl /v2/_catalog和/v2/repo/tags/list查看仓库内容- 垃圾回收(garbage-collect)释放已删除镜像的层数据
- 生产环境必须 HTTPS,HTTP 仅限 localhost 或测试环境
📝 作业
- 基础题(难度⭐):用
docker run启动一个私有 registry,将 nginx:alpine 推送到localhost:5000/test/nginx:v1,然后从另一台机器(或删除本地镜像后)拉取验证。 - 进阶题(难度⭐⭐):配置 htpasswd 认证,验证未登录时 push 被拒绝,登录后 push 成功。
- 挑战题(难度⭐⭐⭐):用 Nginx 反向代理给 Registry 配置 HTTPS(可用自签名证书),通过
https://registry.local/v2/_catalog访问仓库。