跳到主要内容

Docker 私有仓库 Registry

私有镜像仓库是企业级容器化部署的重要组成部分。本章将介绍如何搭建和管理 Docker 私有仓库。

什么是镜像仓库?

镜像仓库(Registry)是存储和分发 Docker 镜像的服务。Docker Hub 是最大的公共仓库,但在企业环境中,通常需要搭建私有仓库。

私有仓库的优势

优势说明
访问控制管理谁可以推送和拉取镜像
网络效率本地网络传输更快
安全合规敏感镜像不暴露在公网
成本控制避免公共仓库的带宽费用
镜像管理自定义标签和版本策略

仓库架构

┌─────────────────────────────────────────────────────────┐
│ Docker Registry │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ API │ │ Auth │ │ Storage │ │
│ │ 接口 │ │ 认证 │ │ 存储 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ 存储后端 │
│ ┌───────────┐┌───────────┐┌───────────┐ │
│ │文件系统 ││ S3 ││ Azure │ │
│ │ ││ ││ Blob │ │
│ └───────────┘└───────────┘└───────────┘ │
└─────────────────────────────────────────────────────────┘

Docker Registry 是一个开源项目,现已成为 CNCF(云原生计算基金会)的一部分,名为 Distribution。它提供了镜像存储、分发和访问控制的核心功能。

快速部署私有仓库

使用 Docker 部署

最简单的方式是使用官方 Registry 镜像:

# 启动仓库容器
docker run -d \
--name registry \
-p 5000:5000 \
-v /data/registry:/var/lib/registry \
--restart=always \
registry:2

# 查看运行状态
docker ps | grep registry

Registry 默认将数据存储在 /var/lib/registry 目录下。通过挂载本地目录,可以实现数据的持久化存储。

验证仓库

# 查看仓库状态
curl http://localhost:5000/v2/_catalog

# 输出
{"repositories":[]}

这个 API 端点返回仓库中所有镜像仓库的列表。空列表表示仓库刚创建,还没有镜像。

推送镜像到私有仓库

# 标记镜像
docker tag nginx:latest localhost:5000/nginx:latest

# 推送镜像
docker push localhost:5000/nginx:latest

# 查看仓库内容
curl http://localhost:5000/v2/_catalog
# {"repositories":["nginx"]}

# 查看镜像标签
curl http://localhost:5000/v2/nginx/tags/list
# {"name":"nginx","tags":["latest"]}

镜像标签格式为:<仓库地址>/<镜像名>:<标签>。推送时,Docker 会将镜像分层上传到仓库。

从私有仓库拉取

# 删除本地镜像
docker rmi localhost:5000/nginx:latest

# 从私有仓库拉取
docker pull localhost:5000/nginx:latest

使用 Docker Compose 部署

基础配置

# compose.yaml
services:
registry:
image: registry:2
ports:
- "5000:5000"
environment:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry
volumes:
- ./data:/var/lib/registry
restart: always

带认证的配置

services:
registry:
image: registry:2
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
volumes:
- ./data:/var/lib/registry
- ./auth:/auth
restart: always

创建认证文件

# 创建目录
mkdir -p auth

# 创建用户密码文件
docker run --rm --entrypoint htpasswd httpd:2 -Bbn admin password > auth/htpasswd

# 查看文件
cat auth/htpasswd
# admin:$2y$05$...

htpasswd 是 Apache HTTP Server 提供的密码文件管理工具。-B 参数使用 bcrypt 加密,-b 从命令行读取密码。

登录和推送

# 登录私有仓库
docker login localhost:5000
# Username: admin
# Password: password

# 推送镜像
docker push localhost:5000/nginx:latest

# 登出
docker logout localhost:5000

配置 HTTPS

生产环境必须使用 HTTPS 加密传输,防止镜像数据在传输过程中被窃取或篡改。

使用自签名证书

# 创建证书目录
mkdir -p certs

# 生成自签名证书
openssl req -newkey rsa:4096 -nodes -sha256 \
-keyout certs/domain.key \
-x509 -days 365 \
-out certs/domain.crt \
-subj "/CN=myregistry.local"

# 证书信息
# CN: 仓库域名
# days: 有效期

Docker Compose 配置

services:
registry:
image: registry:2
ports:
- "443:443"
environment:
REGISTRY_HTTP_ADDR: 0.0.0.0:443
REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt
REGISTRY_HTTP_TLS_KEY: /certs/domain.key
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry
volumes:
- ./data:/var/lib/registry
- ./certs:/certs
restart: always

客户端配置

信任自签名证书

# Linux
sudo mkdir -p /etc/docker/certs.d/myregistry.local
sudo cp certs/domain.crt /etc/docker/certs.d/myregistry.local/ca.crt

# 重启 Docker
sudo systemctl restart docker

# macOS (Docker Desktop)
# 将证书添加到系统钥匙串
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain \
certs/domain.crt

# Windows
# 将证书添加到 "受信任的根证书颁发机构"
certutil -addstore "Root" domain.crt

使用域名访问

# 添加 hosts 记录
echo "127.0.0.1 myregistry.local" | sudo tee -a /etc/hosts

# 登录
docker login myregistry.local

# 推送镜像
docker tag nginx:latest myregistry.local/nginx:latest
docker push myregistry.local/nginx:latest

使用 Let's Encrypt 证书

如果你的仓库有公网域名,可以使用免费的 Let's Encrypt 证书:

services:
registry:
image: registry:2
ports:
- "443:443"
environment:
REGISTRY_HTTP_ADDR: 0.0.0.0:443
REGISTRY_HTTP_TLS_CERTIFICATE: /etc/letsencrypt/live/registry.example.com/fullchain.pem
REGISTRY_HTTP_TLS_KEY: /etc/letsencrypt/live/registry.example.com/privkey.pem
volumes:
- ./data:/var/lib/registry
- /etc/letsencrypt:/etc/letsencrypt:ro
restart: always

Registry 配置详解

配置文件方式

创建 config.yml 文件:

version: 0.1
log:
level: info
formatter: text
fields:
service: registry

storage:
filesystem:
rootdirectory: /var/lib/registry
maxthreads: 100
delete:
enabled: true
cache:
blobdescriptor: inmemory

http:
addr: 0.0.0.0:5000
headers:
X-Content-Type-Options: [nosniff]
Access-Control-Allow-Origin: ['*']
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
Access-Control-Allow-Headers: ['Authorization', 'Accept']

auth:
htpasswd:
realm: Registry Realm
path: /auth/htpasswd

health:
storagedriver:
enabled: true
interval: 10s
threshold: 3

使用配置文件

services:
registry:
image: registry:2
ports:
- "5000:5000"
volumes:
- ./data:/var/lib/registry
- ./auth:/auth
- ./config.yml:/etc/docker/registry/config.yml
restart: always

配置文件提供了比环境变量更灵活的配置方式,支持更复杂的配置场景。

存储配置

本地文件系统

storage:
filesystem:
rootdirectory: /var/lib/registry

AWS S3

storage:
s3:
accesskey: AWS_ACCESS_KEY
secretkey: AWS_SECRET_KEY
region: us-west-1
bucket: my-registry-bucket
encrypt: true
secure: true

Azure Blob Storage

storage:
azure:
accountname: myaccount
accountkey: mykey
container: mycontainer

Google Cloud Storage

storage:
gcs:
bucket: my-bucket
keyfile: /path/to/keyfile.json

使用云存储后端可以实现高可用和灾备,适合生产环境。

清理策略

配置镜像删除

storage:
delete:
enabled: true

删除镜像

# 获取镜像 digest
curl -u admin:password \
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
https://myregistry.local/v2/nginx/manifests/latest

# 删除镜像(需要 digest)
curl -u admin:password -X DELETE \
https://myregistry.local/v2/nginx/manifests/sha256:xxx

# 运行垃圾回收
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml

删除镜像分两步:首先删除 manifest,然后运行垃圾回收释放存储空间。

高级认证配置

使用 Docker Registry Token Auth

更安全的认证方式是通过独立的认证服务器(Token Auth Server)。Docker Registry 支持基于 JWT(JSON Web Token)的认证机制。

工作流程

  1. 客户端尝试访问 Registry
  2. Registry 返回 401 错误,并提供认证服务器地址
  3. 客户端向认证服务器请求 Token
  4. 认证服务器验证用户身份,签发 Token
  5. 客户端携带 Token 访问 Registry
# 认证服务器配置示例
auth:
token:
realm: https://auth.example.com/auth
service: registry.example.com
issuer: Auth Server
rootcertbundle: /certs/auth.crt

Token Auth 是 Docker 官方推荐的认证方式,支持更复杂的权限控制,如:

  • 基于命名空间的访问控制
  • 基于仓库的细粒度权限
  • 用户组和角色管理
  • 审计日志

使用 Docker Auth Server

可以使用现成的认证服务器:

Docker Registry Token Server

services:
auth:
image: cesanta/docker-auth
ports:
- "5001:5001"
volumes:
- ./auth_config.yml:/config/auth_config.yml
command: /config/auth_config.yml

registry:
image: registry:2
ports:
- "5000:5000"
environment:
REGISTRY_AUTH: token
REGISTRY_AUTH_TOKEN_REALM: http://auth:5001/auth
REGISTRY_AUTH_TOKEN_SERVICE: registry
REGISTRY_AUTH_TOKEN_ISSUER: auth
depends_on:
- auth

使用 OAuth

auth:
token:
realm: https://auth.example.com/oauth/token
service: registry.example.com
issuer: Auth Server
autoredirect: true

仓库管理工具

Registry Web UI

使用 Docker Registry UI

services:
registry:
image: registry:2
ports:
- "5000:5000"
volumes:
- ./data:/var/lib/registry

ui:
image: joxit/docker-registry-ui:static
ports:
- "8080:80"
environment:
- REGISTRY_TITLE=My Private Registry
- REGISTRY_URL=http://registry:5000
- DELETE_IMAGES=true
depends_on:
- registry

访问 http://localhost:8080 即可管理镜像。

Web UI 提供了可视化的镜像管理界面,可以浏览、删除镜像,查看镜像详情。

Portus

Portus 是一个功能完整的私有仓库管理平台:

services:
portus:
image: opensuse/portus:latest
ports:
- "3000:3000"
environment:
- PORTUS_MACHINE_FQDN_VALUE=portus.example.com
- PORTUS_SECRET_KEY_BASE=secret
- PORTUS_PASSWORD=secret
depends_on:
- db

db:
image: library/mariadb:10.0.23
environment:
MYSQL_ROOT_PASSWORD: portus

registry:
image: library/registry:2
ports:
- "5000:5000"
environment:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry
REGISTRY_AUTH_TOKEN_REALM: http://portus.example.com:3000/v2/token
REGISTRY_AUTH_TOKEN_SERVICE: registry.example.com
REGISTRY_AUTH_TOKEN_ISSUER: portus.example.com
volumes:
- ./data:/var/lib/registry

Harbor

Harbor 是企业级的镜像仓库解决方案:

# 下载 Harbor
wget https://github.com/goharbor/harbor/releases/download/v2.8.0/harbor-offline-installer-v2.8.0.tgz

# 解压
tar xzf harbor-offline-installer-v2.8.0.tgz

# 配置
cd harbor
cp harbor.yml.tmpl harbor.yml
# 编辑 harbor.yml 配置域名、密码等

# 安装
./install.sh

Harbor 功能特性

  • 基于角色的访问控制
  • 漏洞扫描(Trivy)
  • 镜像签名(Notary)
  • 垃圾回收
  • 复制策略
  • 审计日志
  • 图形化管理界面

Harbor 是 CNCF 毕业项目,被广泛应用于企业生产环境。

Registry API

Registry 提供了符合 OCI(Open Container Initiative)规范的 HTTP API,可以用于自动化管理。

常用 API 端点

端点方法说明
/v2/GET检查 API 版本
/v2/_catalogGET列出所有仓库
/v2/<name>/tags/listGET列出镜像标签
/v2/<name>/manifests/<ref>GET获取镜像清单
/v2/<name>/manifests/<ref>DELETE删除镜像
/v2/<name>/blobs/<digest>GET获取镜像层

API 示例

# 检查 API
curl -u admin:password https://myregistry.local/v2/

# 列出所有仓库
curl -u admin:password https://myregistry.local/v2/_catalog

# 分页列出仓库
curl -u admin:password "https://myregistry.local/v2/_catalog?n=10&last=nginx"

# 列出镜像标签
curl -u admin:password https://myregistry.local/v2/nginx/tags/list

# 获取镜像清单
curl -u admin:password \
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
https://myregistry.local/v2/nginx/manifests/latest

# 获取镜像 digest
DIGEST=$(curl -u admin:password \
-I -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
https://myregistry.local/v2/nginx/manifests/latest 2>/dev/null \
| grep Docker-Content-Digest | awk '{print $2}' | tr -d '\r')

# 删除镜像
curl -u admin:password -X DELETE \
https://myregistry.local/v2/nginx/manifests/$DIGEST

镜像复制与同步

Registry 同步

# 从 Docker Hub 拉取并推送到私有仓库
docker pull nginx:latest
docker tag nginx:latest myregistry.local/library/nginx:latest
docker push myregistry.local/library/nginx:latest

使用 skopeo 同步

Skopeo 是一个强大的镜像操作工具:

# 安装
brew install skopeo # macOS

# 复制镜像
skopeo copy docker://nginx:latest docker://myregistry.local/nginx:latest

# 列出镜像标签
skopeo list-tags docker://myregistry.local/nginx

# 检查镜像
skopeo inspect docker://myregistry.local/nginx:latest

# 同步整个仓库
skopeo sync --src docker --dest docker \
docker://docker.io/library \
docker://myregistry.local/library

Skopeo 可以在不同仓库之间复制镜像,无需通过 Docker daemon,更适合自动化场景。

Harbor 复制策略

在 Harbor 中可以配置自动复制规则:

  1. 进入 Harbor Web 界面
  2. 选择 "复制管理" -> "新建规则"
  3. 配置源仓库和目标仓库
  4. 设置触发模式(手动/定时/事件驱动)

备份与恢复

备份仓库数据

# 备份数据目录
tar czf registry-backup-$(date +%Y%m%d).tar.gz /data/registry

# 备份配置和认证文件
tar czf registry-config-backup.tar.gz ./auth ./certs ./config.yml

使用 Docker 备份

# 创建备份容器
docker run --rm \
-v registry-data:/data \
-v $(pwd):/backup \
alpine \
tar czf /backup/registry-backup.tar.gz /data

恢复仓库

# 停止仓库
docker stop registry

# 恢复数据
tar xzf registry-backup.tar.gz -C /

# 启动仓库
docker start registry

生产环境最佳实践

高可用配置

services:
registry-1:
image: registry:2
environment:
REGISTRY_STORAGE: s3
REGISTRY_STORAGE_S3_ACCESSKEY: ${AWS_ACCESS_KEY}
REGISTRY_STORAGE_S3_SECRETKEY: ${AWS_SECRET_KEY}
REGISTRY_STORAGE_S3_REGION: us-east-1
REGISTRY_STORAGE_S3_BUCKET: my-registry
deploy:
replicas: 2

nginx:
image: nginx:alpine
ports:
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- registry-1

使用共享存储(如 S3)配合负载均衡器可以实现 Registry 的高可用部署。

监控配置

services:
registry:
image: registry:2
environment:
REGISTRY_HTTP_DEBUG_ADDR: 0.0.0.0:5001
REGISTRY_HTTP_DEBUG_PROMETHEUS_ENABLED: "true"
REGISTRY_HTTP_DEBUG_PROMETHEUS_PATH: /metrics
ports:
- "5000:5000"
- "5001:5001"

Prometheus 抓取配置

scrape_configs:
- job_name: 'docker-registry'
static_configs:
- targets: ['registry:5001']

日志配置

log:
level: info
formatter: json
fields:
service: registry
environment: production
hooks:
- type: syslog
levels: [error, fatal]
config:
address: syslog.example.com:514
tag: registry

常见问题

1. 推送镜像时权限被拒绝

# 错误:denied: requested access to the resource is denied

# 解决方案:先登录
docker login myregistry.local

2. HTTPS 证书问题

# 错误:x509: certificate signed by unknown authority

# 解决方案:配置信任证书
sudo mkdir -p /etc/docker/certs.d/myregistry.local
sudo cp ca.crt /etc/docker/certs.d/myregistry.local/

# 或临时禁用验证(不推荐)
docker --insecure-registry myregistry.local push myregistry.local/nginx

3. 存储空间不足

# 清理未使用的层
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml

# 配置定时清理
# crontab -e
0 2 * * * docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml

4. 推送大镜像超时

# 增加客户端超时时间
# 在 daemon.json 中配置
{
"max-concurrent-uploads": 1,
"max-upload-attempts": 5
}

小结

私有镜像仓库的关键要点:

  • 部署方式:使用 registry:2 镜像快速部署,或 Docker Compose 配置
  • 认证配置:htpasswd 创建用户认证,保护镜像访问
  • HTTPS 配置:自签名证书或 Let's Encrypt 免费证书
  • 存储后端:本地文件系统、AWS S3、Azure Blob、GCS 等
  • 管理工具:Registry UI(轻量)、Portus(完整)、Harbor(企业级)
  • API 操作/v2/_catalog 列出仓库、/v2/<name>/tags/list 列出标签
  • 镜像同步:skopeo 工具在不同仓库间复制镜像
  • 备份恢复:备份数据目录或使用临时容器导出

练习

  1. 使用 Docker Compose 部署一个带认证的私有仓库
  2. 配置 HTTPS 并测试推送拉取
  3. 使用 Registry API 列出仓库中的镜像
  4. 使用 skopeo 从 Docker Hub 同步镜像到私有仓库
  5. 配置镜像垃圾回收定时任务

参考资源