内网 Docker 私有镜像仓库搭建实战:Registry、Nginx 与 HTTPS 配置全套示例
Docker 私有化部署方案|附配置文件
在企业内部系统建设、研发测试环境搭建、离线交付、私有云部署等场景中,Docker 已经成为非常常见的基础设施组件。相比传统的应用部署方式,Docker 能够将应用、依赖、运行环境统一封装,提升交付一致性,降低环境差异带来的问题。
不过,在实际生产环境中,很多企业并不会直接依赖公网镜像仓库或云厂商镜像服务,而是会选择搭建一套Docker 私有化部署方案。这样既可以保证镜像资产的安全性,也能提升镜像拉取速度,并满足内网、离线、合规审计等要求。
本文将围绕 Docker 私有化部署进行完整说明,包括方案架构、部署步骤、Registry 私有镜像仓库搭建、Docker Compose 配置、Nginx 反向代理、HTTPS 配置、认证配置、镜像推送与拉取、常见问题及生产建议等内容,并附带可直接参考的配置文件。
一、为什么需要 Docker 私有化部署?
在很多公司或项目中,使用 Docker 时最常见的方式是直接从 Docker Hub、阿里云镜像仓库、腾讯云镜像仓库等公网服务拉取镜像。例如:
docker pull nginx:latest
docker pull mysql:8.0
docker pull redis:7
这种方式在互联网环境中比较方便,但在企业级场景下存在一些问题。
1. 网络环境受限
很多政企、金融、能源、医疗、工业等行业项目部署在内网环境中,服务器无法直接访问公网。如果依赖公网镜像仓库,就会导致镜像无法拉取,部署流程无法持续。
2. 镜像安全不可控
公网镜像来源复杂,即使是官方镜像,也可能存在版本变化、漏洞未修复、供应链风险等问题。企业通常希望对镜像进行统一扫描、统一维护、统一发布。
3. 镜像拉取速度不稳定
公网镜像仓库受网络带宽、跨境链路、限流策略等因素影响,拉取速度可能很慢,尤其是 CI/CD 批量构建时会明显影响效率。
4. 版本管理要求
企业内部通常会维护自己的基础镜像,例如:
company/openjdk:17company/nginx:1.24company/node:20company/python:3.11project/backend:v1.0.0
这些镜像需要放在内部仓库中进行统一管理。
5. 满足合规与审计
在生产环境中,镜像发布、下载、更新都需要具备可追溯性。私有镜像仓库能够结合权限控制、日志审计、漏洞扫描等能力,满足企业管理要求。
二、整体部署架构
本文采用比较通用、轻量、可维护的方案:
客户端 / CI/CD / 业务服务器
|
| docker login / pull / push
|
Nginx HTTPS 反向代理
|
| proxy_pass
|
Docker Registry 私有镜像仓库
|
|
本地磁盘 / NAS / 对象存储
核心组件如下:
| 组件 | 说明 |
|---|---|
| Docker Engine | 容器运行时 |
| Docker Compose | 编排 Registry 和 Nginx |
| Registry | Docker 官方私有镜像仓库服务 |
| Nginx | 提供 HTTPS 反向代理、统一入口 |
| htpasswd | 用于配置基础认证 |
| SSL 证书 | 用于 HTTPS 加密访问 |
| 存储目录 | 保存镜像层数据和元信息 |
本文示例中,我们假设私有仓库域名为:
registry.example.com
服务器内网 IP 为:
192.168.10.20
Registry 对外访问地址为:
https://registry.example.com
如果没有正式域名,也可以使用内网 DNS 或 hosts 方式解析。
三、服务器环境准备
1. 推荐服务器配置
如果只是中小型团队使用,推荐配置如下:
| 项目 | 推荐配置 |
|---|---|
| CPU | 2 核及以上 |
| 内存 | 4GB 及以上 |
| 磁盘 | 200GB 起步,建议使用独立数据盘 |
| 系统 | Ubuntu 22.04 / Debian 12 / CentOS 7+ / Rocky Linux |
| 网络 | 内网千兆网络优先 |
如果企业镜像较多,建议磁盘空间至少 500GB 起步,并规划定期清理策略。
2. 安装 Docker
以 Ubuntu 为例:
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
添加 Docker 官方 GPG Key:
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
添加 Docker 软件源:
echo \
"deb [arch=$(dpkg --print-architecture) \
signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
安装 Docker:
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
启动并设置开机自启:
sudo systemctl enable docker
sudo systemctl start docker
检查版本:
docker version
docker compose version
四、目录规划
建议将私有仓库相关文件统一放在 /data/docker-registry 目录下:
sudo mkdir -p /data/docker-registry/{registry,nginx,auth,certs,logs}
目录说明:
/data/docker-registry
├── auth # htpasswd 认证文件
├── certs # SSL 证书文件
├── logs # Nginx 日志
├── nginx # Nginx 配置文件
└── registry # Registry 镜像数据存储目录
设置权限:
sudo chown -R root:root /data/docker-registry
如果生产环境中使用独立数据盘,可以将数据盘挂载到 /data,避免系统盘被镜像数据占满。
五、创建认证文件
Docker Registry 默认可以匿名访问,但生产环境不建议这么做。我们可以使用 htpasswd 配置用户名和密码。
1. 安装 htpasswd 工具
Ubuntu / Debian:
sudo apt install -y apache2-utils
CentOS / Rocky Linux:
sudo yum install -y httpd-tools
2. 创建用户
假设创建一个用户:
用户名:admin
密码:Admin@123456
执行:
sudo htpasswd -Bbn admin 'Admin@123456' \
| sudo tee /data/docker-registry/auth/htpasswd
参数说明:
| 参数 | 说明 |
|---|---|
-B |
使用 bcrypt 加密 |
-b |
从命令行输入密码 |
-n |
输出到标准输出,不直接写文件 |
如果需要添加更多用户:
sudo htpasswd -B /data/docker-registry/auth/htpasswd devuser
然后根据提示输入密码。
六、准备 SSL 证书
生产环境建议使用正式 CA 签发的证书。如果是内网环境,可以使用企业内部 CA 或自签名证书。
本文示例证书文件如下:
/data/docker-registry/certs/registry.example.com.crt
/data/docker-registry/certs/registry.example.com.key
如果使用自签名证书,可以执行:
sudo openssl req -newkey rsa:4096 -nodes -sha256 \
-keyout /data/docker-registry/certs/registry.example.com.key \
-x509 -days 3650 \
-out /data/docker-registry/certs/registry.example.com.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=Example/OU=IT/CN=registry.example.com"
注意:如果使用自签名证书,客户端机器需要信任该证书,否则执行 docker login 或 docker pull 时会报证书错误。
七、Registry 配置文件
创建 Registry 配置文件:
sudo mkdir -p /data/docker-registry/config
sudo vim /data/docker-registry/config/config.yml
内容如下:
version: 0.1
log:
fields:
service: registry
storage:
filesystem:
rootdirectory: /var/lib/registry
delete:
enabled: true
cache:
blobdescriptor: inmemory
http:
addr: :5000
headers:
X-Content-Type-Options:
- nosniff
auth:
htpasswd:
realm: basic-realm
path: /auth/htpasswd
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
配置说明:
| 配置项 | 说明 |
|---|---|
storage.filesystem.rootdirectory |
Registry 容器内镜像数据目录 |
delete.enabled |
开启镜像删除能力 |
http.addr |
Registry 监听端口 |
auth.htpasswd.path |
认证文件路径 |
health.storagedriver |
存储健康检查 |
八、Nginx 配置文件
Nginx 负责对外提供 HTTPS 服务,并将请求转发给 Registry。
创建配置文件:
sudo vim /data/docker-registry/nginx/registry.conf
内容如下:
upstream docker_registry {
server registry:5000;
}
server {
listen 80;
server_name registry.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name registry.example.com;
ssl_certificate /etc/nginx/certs/registry.example.com.crt;
ssl_certificate_key /etc/nginx/certs/registry.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
client_max_body_size 0;
chunked_transfer_encoding on;
access_log /var/log/nginx/registry_access.log;
error_log /var/log/nginx/registry_error.log;
location /v2/ {
proxy_pass http://docker_registry;
proxy_set_header Host $http_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 $scheme;
proxy_read_timeout 900;
proxy_connect_timeout 900;
proxy_send_timeout 900;
proxy_buffering off;
proxy_request_buffering off;
}
}
这里有几个关键配置需要注意:
-
client_max_body_size 0
表示不限制上传大小,否则推送大镜像时可能失败。 -
proxy_request_buffering off
避免 Nginx 先缓存整个上传请求,适合大镜像上传。 -
/v2/
Docker Registry API 的核心路径,Docker 客户端访问仓库时会请求该路径。
九、Docker Compose 配置文件
创建 docker-compose.yml:
sudo vim /data/docker-registry/docker-compose.yml
完整内容如下:
services:
registry:
image: registry:2
container_name: docker-registry
restart: always
volumes:
- ./registry:/var/lib/registry
- ./auth:/auth
- ./config/config.yml:/etc/docker/registry/config.yml:ro
environment:
REGISTRY_HTTP_ADDR: 0.0.0.0:5000
networks:
- registry-net
nginx:
image: nginx:1.25
container_name: docker-registry-nginx
restart: always
depends_on:
- registry
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/registry.conf:/etc/nginx/conf.d/default.conf:ro
- ./certs:/etc/nginx/certs:ro
- ./logs:/var/log/nginx
networks:
- registry-net
networks:
registry-net:
driver: bridge
该配置中包含两个服务:
| 服务 | 说明 |
|---|---|
registry |
Docker 官方镜像仓库 |
nginx |
HTTPS 反向代理 |
启动服务:
cd /data/docker-registry
sudo docker compose up -d
查看容器状态:
sudo docker compose ps
查看日志:
sudo docker compose logs -f
十、配置域名解析
如果内网有 DNS,可以将域名解析到服务器 IP:
registry.example.com -> 192.168.10.20
如果没有 DNS,可以在每台客户端机器的 hosts 文件中添加:
Linux:
sudo vim /etc/hosts
增加:
192.168.10.20 registry.example.com
Windows:
C:\Windows\System32\drivers\etc\hosts
增加:
192.168.10.20 registry.example.com
十一、客户端信任自签名证书
如果使用的是正式 CA 证书,一般无需额外配置。
如果使用自签名证书,需要在每台 Docker 客户端上配置信任证书。
1. 创建证书目录
sudo mkdir -p /etc/docker/certs.d/registry.example.com
2. 拷贝证书
将服务端的证书复制到客户端:
sudo cp registry.example.com.crt \
/etc/docker/certs.d/registry.example.com/ca.crt
注意文件名必须是:
ca.crt
3. 重启 Docker
sudo systemctl restart docker
如果仓库使用的是非标准端口,例如 registry.example.com:5000,目录应为:
/etc/docker/certs.d/registry.example.com:5000/ca.crt
十二、登录私有镜像仓库
在客户端执行:
docker login registry.example.com
输入用户名和密码:
Username: admin
Password: Admin@123456
登录成功后会看到类似输出:
Login Succeeded
Docker 会将登录凭据保存到:
~/.docker/config.json
十三、推送镜像到私有仓库
以 Nginx 镜像为例:
docker pull nginx:1.25
重新打标签:
docker tag nginx:1.25 registry.example.com/library/nginx:1.25
推送镜像:
docker push registry.example.com/library/nginx:1.25
成功后,私有仓库中就会保存该镜像。
以后其他服务器可以直接拉取:
docker pull registry.example.com/library/nginx:1.25
十四、业务镜像发布示例
假设有一个 Spring Boot 项目,Dockerfile 如下:
FROM registry.example.com/library/eclipse-temurin:17-jre
WORKDIR /app
COPY target/app.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
构建镜像:
docker build -t registry.example.com/project/backend:v1.0.0 .
推送镜像:
docker push registry.example.com/project/backend:v1.0.0
业务服务器部署:
docker pull registry.example.com/project/backend:v1.0.0
docker run -d \
--name backend \
-p 8080:8080 \
--restart=always \
registry.example.com/project/backend:v1.0.0
十五、查看仓库镜像列表
Docker Registry 原生 API 能力比较基础,可以通过接口查看镜像列表。
查看所有仓库:
curl -u admin:Admin@123456 \
https://registry.example.com/v2/_catalog
返回示例:
{
"repositories": [
"library/nginx",
"project/backend"
]
}
查看某个镜像的标签:
curl -u admin:Admin@123456 \
https://registry.example.com/v2/library/nginx/tags/list
返回示例:
{
"name": "library/nginx",
"tags": [
"1.25"
]
}
如果使用自签名证书且未被 curl 信任,可以临时使用 -k 参数:
curl -k -u admin:Admin@123456 \
https://registry.example.com/v2/_catalog
十六、删除镜像与垃圾回收
Registry 删除镜像不是简单地删除 tag,需要先获取 manifest digest,再调用删除接口。
1. 获取镜像 Digest
curl -I \
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
-u admin:Admin@123456 \
https://registry.example.com/v2/library/nginx/manifests/1.25
响应头中会包含:
Docker-Content-Digest: sha256:xxxxxxxxxxxxxxxx
2. 删除 Manifest
curl -X DELETE \
-u admin:Admin@123456 \
https://registry.example.com/v2/library/nginx/manifests/sha256:xxxxxxxxxxxxxxxx
3. 执行垃圾回收
进入 Registry 容器执行:
docker exec -it docker-registry sh
执行垃圾回收:
registry garbage-collect /etc/docker/registry/config.yml
为了避免在垃圾回收过程中仍有镜像上传或拉取,建议先停止 Registry 服务:
cd /data/docker-registry
docker compose stop registry
然后临时执行:
docker run --rm \
-v /data/docker-registry/registry:/var/lib/registry \
-v /data/docker-registry/config/config.yml:/etc/docker/registry/config.yml:ro \
registry:2 \
registry garbage-collect /etc/docker/registry/config.yml
最后启动服务:
docker compose start registry
十七、生产环境增强建议
上面的方案适合中小规模私有镜像仓库。如果用于生产环境,建议进一步增强。
1. 使用 Harbor 替代原生 Registry
Docker Registry 功能较简单,适合轻量使用。如果企业需要更完整的镜像管理平台,建议使用 Harbor。
Harbor 支持:
- Web 管理界面
- 项目与用户权限管理
- 镜像漏洞扫描
- 镜像复制
- 镜像签名
- 机器人账号
- 审计日志
- 镜像保留策略
- LDAP / OIDC 集成
如果是企业生产级环境,Harbor 通常是更推荐的选择。
2. 配置磁盘监控
镜像仓库非常容易占用大量磁盘空间,需要配置监控和告警。
可以关注:
df -h
du -sh /data/docker-registry/registry
建议结合 Prometheus、Grafana、Node Exporter 配置磁盘容量告警。
3. 定期清理无用镜像
CI/CD 高频构建时会产生大量版本镜像,例如:
backend:feature-xxx
backend:test-20240101
backend:commit-abcdef
这些镜像如果不清理,会快速占满磁盘。
建议制定镜像保留策略:
- 生产版本永久保留;
- 测试版本保留最近 30 天;
- 临时分支镜像保留最近 7 天;
- 每周执行一次垃圾回收。
4. 配置访问控制
虽然 htpasswd 可以满足基础认证,但权限粒度较粗。如果需要项目级权限,例如:
- A 项目成员只能访问 A 项目镜像;
- B 项目成员只能访问 B 项目镜像;
- CI 账号只能 push,生产服务器只能 pull;
则建议使用 Harbor 或其他更完整的镜像仓库产品。
5. 配置备份策略
镜像仓库数据目录非常重要,建议定期备份:
/data/docker-registry/registry
/data/docker-registry/auth
/data/docker-registry/config
/data/docker-registry/certs
/data/docker-registry/nginx
可使用 rsync、对象存储、NAS 快照等方式进行备份。
示例备份脚本:
#!/bin/bash
BACKUP_DIR="/backup/docker-registry"
DATE=$(date +%F-%H%M%S)
mkdir -p ${BACKUP_DIR}
tar -czf ${BACKUP_DIR}/docker-registry-${DATE}.tar.gz \
/data/docker-registry/auth \
/data/docker-registry/config \
/data/docker-registry/certs \
/data/docker-registry/nginx
echo "backup finished: ${BACKUP_DIR}/docker-registry-${DATE}.tar.gz"
对于镜像数据目录,如果数据量很大,不建议频繁 tar 打包,可以使用增量同步:
rsync -av --delete /data/docker-registry/registry/ /backup/docker-registry-data/
6. 配置日志轮转
Nginx 日志如果长期不清理,也会占用磁盘空间。可以配置 logrotate:
sudo vim /etc/logrotate.d/docker-registry-nginx
内容如下:
/data/docker-registry/logs/*.log {
daily
rotate 14
compress
missingok
notifempty
copytruncate
}
十八、常见问题排查
1. docker login 报 x509 证书错误
错误示例:
x509: certificate signed by unknown authority
原因通常是客户端不信任自签名证书。
解决方式:
sudo mkdir -p /etc/docker/certs.d/registry.example.com
sudo cp registry.example.com.crt /etc/docker/certs.d/registry.example.com/ca.crt
sudo systemctl restart docker
2. 推送镜像时报 413 Request Entity Too Large
说明 Nginx 限制了上传大小。
确认 Nginx 配置中存在:
client_max_body_size 0;
修改后重启:
cd /data/docker-registry
docker compose restart nginx
3. 推送大镜像超时
可适当增大 Nginx 超时时间:
proxy_read_timeout 900;
proxy_connect_timeout 900;
proxy_send_timeout 900;
4. no basic auth credentials
说明没有登录,或登录地址与推送地址不一致。
执行:
docker login registry.example.com
注意以下地址必须一致:
docker login registry.example.com
docker push registry.example.com/project/backend:v1.0.0
如果一个使用 IP,一个使用域名,Docker 会认为是两个不同仓库。
5. http: server gave HTTP response to HTTPS client
说明 Docker 客户端按 HTTPS 访问,但服务端只提供 HTTP,或者反向代理配置异常。
推荐解决方式是启用 HTTPS。如果只是测试环境使用 HTTP,需要在客户端配置 insecure registry。
编辑:
sudo vim /etc/docker/daemon.json
增加:
{
"insecure-registries": ["registry.example.com"]
}
重启 Docker:
sudo systemctl restart docker
生产环境不建议使用该方式。
十九、完整文件结构汇总
最终目录结构如下:
/data/docker-registry
├── auth
│ └── htpasswd
├── certs
│ ├── registry.example.com.crt
│ └── registry.example.com.key
├── config
│ └── config.yml
├── docker-compose.yml
├── logs
├── nginx
│ └── registry.conf
└── registry
核心文件包括:
1. docker-compose.yml
services:
registry:
image: registry:2
container_name: docker-registry
restart: always
volumes:
- ./registry:/var/lib/registry
- ./auth:/auth
- ./config/config.yml:/etc/docker/registry/config.yml:ro
environment:
REGISTRY_HTTP_ADDR: 0.0.0.0:5000
networks:
- registry-net
nginx:
image: nginx:1.25
container_name: docker-registry-nginx
restart: always
depends_on:
- registry
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/registry.conf:/etc/nginx/conf.d/default.conf:ro
- ./certs:/etc/nginx/certs:ro
- ./logs:/var/log/nginx
networks:
- registry-net
networks:
registry-net:
driver: bridge
2. config.yml
version: 0.1
log:
fields:
service: registry
storage:
filesystem:
rootdirectory: /var/lib/registry
delete:
enabled: true
cache:
blobdescriptor: inmemory
http:
addr: :5000
headers:
X-Content-Type-Options:
- nosniff
auth:
htpasswd:
realm: basic-realm
path: /auth/htpasswd
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
3. registry.conf
upstream docker_registry {
server registry:5000;
}
server {
listen 80;
server_name registry.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name registry.example.com;
ssl_certificate /etc/nginx/certs/registry.example.com.crt;
ssl_certificate_key /etc/nginx/certs/registry.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
client_max_body_size 0;
chunked_transfer_encoding on;
access_log /var/log/nginx/registry_access.log;
error_log /var/log/nginx/registry_error.log;
location /v2/ {
proxy_pass http://docker_registry;
proxy_set_header Host $http_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 $scheme;
proxy_read_timeout 900;
proxy_connect_timeout 900;
proxy_send_timeout 900;
proxy_buffering off;
proxy_request_buffering off;
}
}
二十、总结
本文介绍了一套基于 Docker Registry、Nginx、HTTPS 和 htpasswd 的 Docker 私有化部署方案。该方案具有部署简单、依赖少、可维护性高的特点,适合中小团队、测试环境、离线交付环境以及轻量级生产场景使用。
通过本文配置,可以实现:
- 内网私有镜像仓库;
- HTTPS 安全访问;
- 用户名密码认证;
- 镜像推送与拉取;
- 镜像删除与垃圾回收;
- 日志管理与备份扩展;
- 与业务 Dockerfile、CI/CD 流程集成。
如果只是需要一个轻量、稳定、易部署的私有仓库,Docker Registry 已经足够使用;如果企业对权限、审计、漏洞扫描、可视化管理要求更高,则建议进一步采用 Harbor 作为企业级镜像仓库平台。
无论选择哪种方式,Docker 私有化部署的核心目标都是一致的:让镜像交付更安全、更稳定、更可控,让应用部署更加标准化和自动化。