跳到主要内容

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. 配置镜像垃圾回收定时任务

参考资源​