Docker 私有镜像仓库 Registry 部署
概述
在容器化技术普及的今天,Docker镜像已成为应用分发和部署的核心载体。然而,依赖公共仓库(如Docker Hub)存在安全隐患、网络依赖、速率限制等问题。私有Docker镜像仓库不仅能提升安全性,还能优化CI/CD流程、控制镜像版本、降低网络依赖,尤其适合企业级开发、离线环境或需要严格权限管理的场景。
Registry 是 Docker 的镜像存储服务,DockerHub 上的 registry 镜像见 Registry 官方镜像,更多详细信息请转至 GitHub 查看最新源码。
本文档介绍如何通过 Docker Compose 搭建一个简单的 registry 环境。使用 DockerHub 官方镜像,registry 镜像版本为 registry:3。这里主要介绍 registry 环境的搭建及使用,更详细的企业级 registry 服务器的搭建可参阅开源的 Harbor。
方案选型:Docker Registry vs Harbor
在搭建私有仓库前,需明确技术选型。当前主流方案有两种:
- Docker 官方 Registry:轻量级、开源免费,适合小型团队或快速验证场景。
- Harbor:企业级镜像仓库,基于Registry扩展,提供权限管理、镜像扫描、UI界面等高级功能。
对比结论:
- 若追求快速搭建且功能需求简单,选择Docker Registry;
- 若需企业级管理功能(如RBAC权限、漏洞扫描),选择Harbor。
本文以Docker Registry为例,因其部署更简单,适合“快速搭建”的核心目标。
环境准备
本次部署环境为内网树莓派,系统架构为 ubuntu/aarch64。
基础环境如下:
| 项目 | 配置 |
|---|---|
| 主机名 | Amadeus |
| 内网地址 | 192.168.0.10 |
| Registry 域名 | registry.amadeus.lan |
| CPU | 4 核 |
| 内存 | 8GB |
| Docker | 26.1.5 |
| Docker Compose | 2.26.1 |
| OpenSSL | 3.5.6 |
| Registry 端口 | 基础直连端口 5000;域名访问使用 HTTPS 默认端口 443 |
| 访问方式 | HTTPS |
目录规划如下:
| 用途 | 路径 |
|---|---|
| Compose 工程目录 | /home/lyra/workspace/registry |
| 证书目录 | /home/lyra/workspace/registry/certs |
| 认证目录 | /home/lyra/workspace/registry/auth |
| 镜像数据目录 | /srv/registry/data |
初始化目录:
mkdir -p /home/lyra/workspace/registry/{certs,auth} sudo mkdir -p /srv/registry/data
进入 Compose 工程目录:
cd /home/lyra/workspace/registry
确认 Docker、Docker Compose 和 OpenSSL 可用:
docker --version docker compose version openssl version
HTTPS 证书采用内网私有 CA 签发,证书需要包含 Registry 的访问域名和内网 IP:
registry.amadeus.lan 192.168.0.10
基础直连访问地址:
https://registry.amadeus.lan:5000
如果需要通过 https://registry.amadeus.lan 直接访问,按“配置域名访问”章节修改端口映射和代理配置。
搭建 Registry
构建配置文件
目录结构:
/home/lyra/workspace/registry ├── docker-compose.yml ├── config │ └── config.yml ├── certs │ ├── ca.crt │ ├── registry.crt │ └── registry.key └── auth └── htpasswd /srv/registry └── data
创建配置目录:
mkdir -p /home/lyra/workspace/registry/{config,certs,auth} sudo mkdir -p /srv/registry/data sudo chown -R 1000:1000 /srv/registry/data
config/config.yml 是 Registry 服务配置文件,控制存储路径、HTTP 监听、HTTPS 证书和认证方式。下面是基础直连模式的配置;如果需要通过域名直接访问,后续需要按“配置域名访问”章节调整 http.host 和 TLS 入口。
version: 0.1 log: fields: service: registry storage: filesystem: rootdirectory: /var/lib/registry delete: enabled: true http: addr: :5000 host: https://registry.amadeus.lan:5000 tls: certificate: /certs/registry.crt key: /certs/registry.key headers: X-Content-Type-Options: [nosniff] auth: htpasswd: realm: basic-realm path: /auth/htpasswd
docker-compose.yml 用于定义 Registry 容器、端口映射和数据挂载。下面的配置会把宿主机 5000 端口映射到 Registry 容器,适合先完成基础服务验证;如果要改为域名无端口访问,后续需要按“配置域名访问”章节调整 ports。
services: registry: image: registry:3 container_name: registry restart: unless-stopped user: "1000:1000" ports: - "5000:5000" volumes: - /srv/registry/data:/var/lib/registry - ./config/config.yml:/etc/distribution/config.yml:ro - ./certs:/certs:ro - ./auth:/auth:ro command: - serve - /etc/distribution/config.yml
auth/htpasswd 用于保存 Registry 用户认证信息,文件在后续步骤中生成。
生成 HTTPS 证书
进入 Compose 工程目录:
cd /home/lyra/workspace/registry
生成内网私有 CA:
openssl genrsa -out certs/ca.key 4096 openssl req -x509 -new -nodes \ -key certs/ca.key \ -sha256 \ -days 3650 \ -out certs/ca.crt \ -subj "/CN=Amadeus Registry CA"
生成 Registry 服务端私钥:
openssl genrsa -out certs/registry.key 4096
生成证书签名请求配置文件:
cat > certs/registry.cnf <<'EOF' [req] default_bits = 4096 prompt = no default_md = sha256 distinguished_name = dn req_extensions = req_ext [dn] CN = registry.amadeus.lan [req_ext] subjectAltName = @alt_names [alt_names] DNS.1 = registry.amadeus.lan IP.1 = 192.168.0.10 EOF
生成 Registry 证书签名请求:
openssl req -new \ -key certs/registry.key \ -out certs/registry.csr \ -config certs/registry.cnf
生成证书扩展配置文件:
cat > certs/registry.ext <<'EOF' authorityKeyIdentifier = keyid,issuer basicConstraints = CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1 = registry.amadeus.lan IP.1 = 192.168.0.10 EOF
使用内网私有 CA 签发 Registry 服务端证书:
openssl x509 -req \ -in certs/registry.csr \ -CA certs/ca.crt \ -CAkey certs/ca.key \ -CAcreateserial \ -out certs/registry.crt \ -days 3650 \ -sha256 \ -extfile certs/registry.ext
查看证书信息:
openssl x509 -in certs/registry.crt -noout -subject -issuer -dates openssl x509 -in certs/registry.crt -noout -text | grep -A 2 "Subject Alternative Name"
调整证书文件权限:
chmod 600 certs/ca.key certs/registry.key chmod 644 certs/ca.crt certs/registry.crt
生成认证文件
使用 httpd:2 镜像生成 htpasswd 文件:
docker run --rm \ --entrypoint htpasswd \ httpd:2 \ -Bbn registry '<registry-password>' > auth/htpasswd
调整认证文件权限:
chmod 600 auth/htpasswd
其中 registry 为登录用户名,<registry-password> 替换为实际密码。
启动 Registry 服务
在 docker-compose.yml 文件目录下启动 Registry 服务:
cd /home/lyra/workspace/registry docker compose up -d
查看容器状态:
docker compose ps
查看服务日志:
docker compose logs -f registry
常用管理命令:
docker compose stop docker compose restart docker compose down
配置域名访问
通过域名直接访问 Registry 时,客户端使用默认 HTTPS 端口 443,登录地址不再携带端口:
docker login registry.amadeus.lan
方案一:直接映射 443 端口
该方案由 Registry 容器直接处理 HTTPS,将宿主机 443 端口映射到容器内 5000 端口。
需要修改 docker-compose.yml。核心变化是把宿主机 443 映射到容器 5000,其余数据目录、配置文件和认证文件仍沿用基础配置。
services: registry: image: registry:3 container_name: registry restart: unless-stopped user: "1000:1000" ports: - "443:5000" volumes: - /srv/registry/data:/var/lib/registry - ./config/config.yml:/etc/distribution/config.yml:ro - ./certs:/certs:ro - ./auth:/auth:ro command: - serve - /etc/distribution/config.yml
需要修改 config/config.yml。核心变化是把 http.host 改为不带端口的 HTTPS 域名,Registry 仍然由容器自身加载证书并处理 TLS。
version: 0.1 log: fields: service: registry storage: filesystem: rootdirectory: /var/lib/registry delete: enabled: true http: addr: :5000 host: https://registry.amadeus.lan tls: certificate: /certs/registry.crt key: /certs/registry.key headers: X-Content-Type-Options: [nosniff] auth: htpasswd: realm: basic-realm path: /auth/htpasswd
客户端证书信任目录需要改为:
/etc/docker/certs.d/registry.amadeus.lan/ca.crt
应用配置:
cd /home/lyra/workspace/registry docker compose up -d
方案二:Nginx 反向代理
该方案由 Nginx 监听宿主机 443 端口并处理 HTTPS,Registry 容器只监听本机 127.0.0.1:5000。
需要修改 docker-compose.yml。核心变化是只把 Registry 暴露到宿主机回环地址,避免局域网客户端绕过 Nginx 直接访问 5000 端口。
services: registry: image: registry:3 container_name: registry restart: unless-stopped user: "1000:1000" ports: - "127.0.0.1:5000:5000" volumes: - /srv/registry/data:/var/lib/registry - ./config/config.yml:/etc/distribution/config.yml:ro - ./auth:/auth:ro command: - serve - /etc/distribution/config.yml
需要修改 config/config.yml。核心变化是移除 Registry 自身的 TLS 配置,由 Nginx 统一处理 HTTPS;Registry 只保留 HTTP 服务、存储和认证配置。
version: 0.1 log: fields: service: registry storage: filesystem: rootdirectory: /var/lib/registry delete: enabled: true http: addr: :5000 host: https://registry.amadeus.lan headers: X-Content-Type-Options: [nosniff] auth: htpasswd: realm: basic-realm path: /auth/htpasswd
应用 Registry 配置:
cd /home/lyra/workspace/registry docker compose up -d
创建 Nginx 证书目录:
sudo mkdir -p /etc/nginx/certs/registry sudo cp /home/lyra/workspace/registry/certs/registry.crt /etc/nginx/certs/registry/registry.crt sudo cp /home/lyra/workspace/registry/certs/registry.key /etc/nginx/certs/registry/registry.key sudo chmod 600 /etc/nginx/certs/registry/registry.key sudo chmod 644 /etc/nginx/certs/registry/registry.crt
新增 Nginx 配置文件 /etc/nginx/conf.d/registry.conf。该配置负责监听 443,加载 Registry 证书,并把 /v2/ 请求转发给本机 Registry 服务。
server { listen 443 ssl; server_name registry.amadeus.lan; ssl_certificate /etc/nginx/certs/registry/registry.crt; ssl_certificate_key /etc/nginx/certs/registry/registry.key; client_max_body_size 0; chunked_transfer_encoding on; location /v2/ { proxy_pass http://127.0.0.1:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-Host $host; proxy_read_timeout 900; add_header Docker-Distribution-Api-Version registry/2.0 always; } }
检查 Nginx 配置并重载:
sudo nginx -t sudo systemctl reload nginx
确认端口监听状态:
sudo ss -ltnp | grep 443 sudo ss -ltnp | grep 5000
客户端证书信任目录需要改为:
/etc/docker/certs.d/registry.amadeus.lan/ca.crt
基础操作
配置客户端域名解析
客户端需要将 Registry 域名解析到树莓派内网地址:
192.168.0.10 registry.amadeus.lan
如果使用本机 hosts 文件解析,Linux 客户端写入 /etc/hosts:
echo "192.168.0.10 registry.amadeus.lan" | sudo tee -a /etc/hosts
Windows 客户端写入:
C:\Windows\System32\drivers\etc\hosts
配置客户端信任证书
在需要访问私有仓库的 Docker 客户端上创建证书信任目录(以本机为例):
sudo mkdir -p /etc/docker/certs.d/registry.amadeus.lan
复制 CA 证书:
sudo cp /home/lyra/workspace/registry/certs/ca.crt /etc/docker/certs.d/registry.amadeus.lan/ca.crt
重启 Docker:
sudo systemctl restart docker
账号管理
Registry 使用 auth/htpasswd 保存账号密码。账号变更前先进入 Compose 工程目录:
cd /home/lyra/workspace/registry
修改账号前备份认证文件:
cp auth/htpasswd "auth/htpasswd.bak.$(date +%Y%m%d%H%M%S)"
查看已有账号:
cut -d: -f1 auth/htpasswd
创建新账号:
docker run --rm \ --entrypoint htpasswd \ httpd:2 \ -Bbn <user-name> '<user-password>' >> auth/htpasswd
修改账号密码:
grep -v '^<user-name>:' auth/htpasswd > /tmp/htpasswd.new docker run --rm \ --entrypoint htpasswd \ httpd:2 \ -Bbn <user-name> '<new-password>' >> /tmp/htpasswd.new mv /tmp/htpasswd.new auth/htpasswd chmod 600 auth/htpasswd
删除账号:
grep -v '^<user-name>:' auth/htpasswd > /tmp/htpasswd.new mv /tmp/htpasswd.new auth/htpasswd chmod 600 auth/htpasswd
账号变更后重启 Registry:
docker compose restart registry
使用新账号登录:
docker login registry.amadeus.lan
镜像操作
登录私有仓库:
docker login registry.amadeus.lan
拉取测试镜像:
docker pull hello-world:latest
给测试镜像打标签:
docker tag hello-world:latest registry.amadeus.lan/hello-world:latest
推送测试镜像:
docker push registry.amadeus.lan/hello-world:latest
删除本地测试镜像:
docker rmi registry.amadeus.lan/hello-world:latest
从私有仓库重新拉取:
docker pull registry.amadeus.lan/hello-world:latest
通过 HTTPS 接口查看仓库目录:
curl --cacert certs/ca.crt -u <user-name>:<user-password> https://registry.amadeus.lan/v2/_catalog
查看指定镜像的标签:
curl --cacert certs/ca.crt \ -u <user-name>:<user-password> \ https://registry.amadeus.lan/v2/hello-world/tags/list
删除本地镜像:
docker rmi hello-world:latest docker rmi registry.amadeus.lan/hello-world:latest
删除仓库中的镜像
删除仓库中的镜像需要先获取 manifest digest:
IMAGE_NAME=hello-world IMAGE_TAG=latest DIGEST=$(curl -sI \ --cacert certs/ca.crt \ -u <user-name>:<user-password> \ -H 'Accept: application/vnd.docker.distribution.manifest.v2+json, application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json' \ "https://registry.amadeus.lan/v2/${IMAGE_NAME}/manifests/${IMAGE_TAG}" \ | awk -F': ' 'tolower($1) == "docker-content-digest" {print $2}' \ | tr -d '\r') echo "${DIGEST}"
根据 manifest digest 删除仓库中的镜像:
curl -X DELETE \ --cacert certs/ca.crt \ -u <user-name>:<user-password> \ "https://registry.amadeus.lan/v2/${IMAGE_NAME}/manifests/${DIGEST}"
再次查看标签:
curl --cacert certs/ca.crt \ -u <user-name>:<user-password> \ "https://registry.amadeus.lan/v2/${IMAGE_NAME}/tags/list"
删除 manifest 后,Registry 不会立即释放磁盘空间。需要停止服务后执行垃圾回收:
cd /home/lyra/workspace/registry docker compose stop registry docker run --rm \ --user "1000:1000" \ -v /srv/registry/data:/var/lib/registry \ -v /home/lyra/workspace/registry/config/config.yml:/etc/distribution/config.yml:ro \ -v /home/lyra/workspace/registry/certs:/certs:ro \ -v /home/lyra/workspace/registry/auth:/auth:ro \ registry:3 \ garbage-collect /etc/distribution/config.yml docker compose up -d
查看镜像数据目录占用空间:
sudo du -sh /srv/registry/data