Docker 私有仓库搭建与使用

Docker 私有仓库搭建与使用笔记

环境:registry:2 官方镜像,以 10.145.145.1:5000 为例。 所有命令在服务端 (装 Docker 的 Linux 主机)或客户端(任意需要推/拉镜像的机器)执行,已标注。


目录

  1. 什么是私有仓库
  2. 搭建仓库(服务端)
  3. 开启认证(服务端)
  4. [客户端配置 insecure-registries](#客户端配置 insecure-registries "#4-%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%85%8D%E7%BD%AE-insecure-registries")
  5. 登录仓库(客户端)
  6. 镜像命名规则
  7. 打标签
  8. 推送镜像
  9. 拉取镜像
  10. 查询/验证仓库内容
  11. 常见报错排查
  12. [进阶:去掉 IP 和端口](#进阶:去掉 IP 和端口 "#12-%E8%BF%9B%E9%98%B6%E5%8E%BB%E6%8E%89-ip-%E5%92%8C%E7%AB%AF%E5%8F%A3")
  13. 一键发布脚本
  14. [附:registry-mirrors 不是别名机制](#附:registry-mirrors 不是别名机制 "#14-%E9%99%84registry-mirrors-%E4%B8%8D%E6%98%AF%E5%88%AB%E5%90%8D%E6%9C%BA%E5%88%B6")

1. 什么是私有仓库

Docker Hub 是公共仓库,企业内部的镜像(业务代码、不公开的基础镜像)需要存放在自己的仓库里。官方提供 registry:2 镜像,一个容器就能搭起符合 Docker Registry API v2 协议的仓库服务。

  • 公共仓库:docker.io(写镜像名时可以省略)
  • 私有仓库:自建,必须写完整地址,如 10.145.145.1:5000

生产级替代品:Harbor (带 Web UI、权限管理、镜像扫描)、Nexus、Artifactory。个人/小团队用 registry:2 足够。


2. 搭建仓库(服务端)

最简版(仅本地测试,数据不持久化)

bash 复制代码
docker run -d -p 5000:5000 --restart=always --name registry registry:2

推荐版(数据持久化,重启不丢镜像)

bash 复制代码
mkdir -p /data/registry

docker run -d -p 5000:5000 --restart=always --name registry \
  -v /data/registry/data:/var/lib/registry \
  registry:2

/var/lib/registry 是镜像层和 manifest 的实际存储位置,必须挂 volume。

验证服务已启动:

bash 复制代码
curl http://localhost:5000/v2/
# 返回 {} 即正常

3. 开启认证(服务端)

裸仓库默认无认证,任何能连到 5000 端口的人都能推拉。用 htpasswd 加 Basic 认证:

3.1 生成密码文件

bash 复制代码
mkdir -p /data/registry/auth

docker run --rm --entrypoint htpasswd httpd:2 \
  -Bbn admin YourPassword123 > /data/registry/auth/htpasswd

参数说明:-B 用 bcrypt 加密(registry 只认 bcrypt)、-b 密码放命令行、-n 输出到 stdout。

追加用户时用 -Bbn 新用户 密码 >> htpasswd,注意别用 > 覆盖掉老用户。

3.2 带认证启动仓库

bash 复制代码
docker run -d -p 5000:5000 --restart=always --name registry \
  -v /data/registry/auth:/auth \
  -v /data/registry/data:/var/lib/registry \
  -e REGISTRY_AUTH=htpasswd \
  -e REGISTRY_AUTH_HTPASSWD_REALM="Registry" \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
  registry:2

验证认证已生效:

bash 复制代码
curl -I http://10.145.145.1:5000/v2/
# 期望返回 401 Unauthorized,响应头带 Www-Authenticate: Basic realm="Registry"

4. 客户端配置 insecure-registries

为什么需要:Docker 默认只信任 HTTPS 仓库。自建仓库没配 TLS 证书时走的是 HTTP,必须告诉 daemon"这个地址允许明文",否则推拉时报 TLS 错误。

Docker Desktop(Windows / Mac)

Settings → Docker Engine → 右侧 JSON 中加上 → Apply & Restart:

json 复制代码
{
  "insecure-registries": ["10.145.145.1:5000"]
}

Linux

编辑 /etc/docker/daemon.json

json 复制代码
{
  "insecure-registries": ["10.145.145.1:5000"]
}

重启服务:

bash 复制代码
sudo systemctl restart docker

注意:insecure-registries 只解决"能不能连上 HTTP",不含任何别名/缩写功能,镜像名里的地址一个字都省不了。


5. 登录仓库(客户端)

bash 复制代码
docker login 10.145.145.1:5000
# 依次输入用户名、密码
# 出现 "Login Succeeded" 即成功

其他方式:

bash 复制代码
# 非交互(密码会留在 shell 历史,不推荐)
docker login 10.145.145.1:5000 -u admin -p YourPassword123

# 非交互但安全(脚本里用这种)
echo "YourPassword123" | docker login 10.145.145.1:5000 -u admin --password-stdin

# 登出
docker logout 10.145.145.1:5000

凭据存哪了 :登录后凭据存入本机凭据管理器(~/.docker/config.json"credsStore": "desktop" 表示交给系统凭据管理器保管,config.json 本身不存明文密码)。之后该机器上所有 docker push / pull 自动携带凭据,无需重复登录。


6. 镜像命名规则

完整格式:

css 复制代码
[仓库地址:端口/][命名空间/]镜像名:标签
写法 实际指向
nginx docker.io/library/nginx:latest
alice/myapp docker.io/alice/myapp:latest
10.145.145.1:5000/app-demo:1.0 私有仓库,原样

地址判断规则 :Docker 看第一段 / 前面的内容------

  • .、含 :、或是 localhost → 当作仓库地址
  • 否则 → 当作 docker.io 上的命名空间

端口的来历 :公共仓库监听默认 443,可省略;registry:2 默认监听 5000,必须写。地址是镜像名的一部分(跟着 manifest 分发),daemon.json 里没有任何"别名"配置能把它变短,见[第 14 节](#第 14 节 "#14-%E9%99%84registry-mirrors-%E4%B8%8D%E6%98%AF%E5%88%AB%E5%90%8D%E6%9C%BA%E5%88%B6")。


7. 打标签

本地镜像必须带上仓库地址才能推送,两种做法:

bash 复制代码
# 方式一:对已有镜像补标签
docker tag app-demo:1.0 10.145.145.1:5000/app-demo:1.0

# 方式二(推荐):build 时直接打全名,省一步
docker build -t 10.145.145.1:5000/app-demo:1.0 .

同一个镜像可以有多个标签,docker tag 只是加引用,不复制数据。


8. 推送镜像

bash 复制代码
docker push 10.145.145.1:5000/app-demo:1.0

成功标志:最后一行返回 digest,例如:

arduino 复制代码
1.0: digest: sha256:9427afca4f8e... size: 856

记下这个 digest,它是镜像内容的唯一指纹,可用于核对推送/拉取是否一致。


9. 拉取镜像

任何一台配好了 insecure-registries(第 4 节)并登录(第 5 节)的机器:

bash 复制代码
docker pull 10.145.145.1:5000/app-demo:1.0

拉完核对 digest 与推送时是否一致:

bash 复制代码
docker images --digests | grep app-demo

10. 查询/验证仓库内容

用 curl 调 Registry API v2(开认证的仓库要带 -u 用户:密码):

bash 复制代码
# 列出所有镜像
curl -u admin:YourPassword123 http://10.145.145.1:5000/v2/_catalog

# 列出某镜像的所有标签
curl -u admin:YourPassword123 http://10.145.145.1:5000/v2/app-demo/tags/list

返回示例:

json 复制代码
{"name":"app-demo","tags":["1.0"]}

⚠️ docker manifest inspect 对"HTTP + Basic 认证"的仓库有兼容问题,可能误报 no such manifest。验证镜像是否存在,以 docker pull 为准。


11. 常见报错排查

报错 原因 解决
authorization failed: no basic auth credentials 未登录或登录过期 docker login 仓库地址
http: server gave HTTP response to HTTPS client 客户端没配 insecure-registries 按第 4 节配置后重启 Docker
x509: certificate signed by unknown authority 仓库走了 HTTPS 但自签证书未被信任 信任证书(见下)或改走 HTTP + insecure-registries
connection refused 仓库容器没起 / 端口没映射 / 防火墙 docker ps 查容器,curl http://IP:5000/v2/ 测连通
push 成功但 manifest inspect 报 no such manifest 命令兼容性问题(误报) docker pull 验证

自签 HTTPS 证书的信任方法(Linux 客户端,每个客户端都要做):

bash 复制代码
# 把仓库的 CA 证书放到下面目录(目录名 = 仓库地址:端口)
sudo mkdir -p /etc/docker/certs.d/10.145.145.1:5000
sudo cp ca.crt /etc/docker/certs.d/10.145.145.1:5000/ca.crt
# 无需重启 docker

12. 进阶:去掉 IP 和端口

镜像名里的地址会被写进部署文件(K8s yaml、compose 等),裸 IP:端口又长又不稳定。正规做法:

12.1 hosts 加短域名(改客户端)

hosts 文件(Windows:C:\Windows\System32\drivers\etc\hosts)加:

lua 复制代码
10.145.145.1 reg.local

之后镜像名写 reg.local:5000/app-demo:1.0

⚠️ 域名必须含点 :Docker 靠"第一段含 .:"识别仓库地址, 写 reg/app-demo 会被当成 docker.ioreg 用户的仓库。

12.2 仓库挪到 443 端口(改服务端,去掉端口)

bash 复制代码
docker run -d -p 443:5000 --restart=always --name registry ... registry:2

配合 hosts,镜像名最短变成:

bash 复制代码
reg.local/app-demo:1.0

insecure-registries 里相应写 reg.local


13. 一键发布脚本

把仓库地址收进脚本,日常命令不再出现 IP。项目根目录放 release.sh

bash 复制代码
#!/bin/bash
# 用法: ./release.sh [版本号],不传默认 1.0
REGISTRY=10.145.145.1:5000
APP=app-demo
VERSION=${1:-1.0}

docker build -t $REGISTRY/$APP:$VERSION . && \
docker push $REGISTRY/$APP:$VERSION
bash 复制代码
chmod +x release.sh
./release.sh          # 构建并推送 1.0
./release.sh 1.1      # 构建并推送 1.1

Windows 下等价物(PowerShell release.ps1):

powershell 复制代码
param([string]$Version = "1.0")
$Registry = "10.145.145.1:5000"; $App = "app-demo"
docker build -t "$Registry/$App`:$Version" . ; if ($?) { docker push "$Registry/$App`:$Version" }

14. 附:registry-mirrors 不是别名机制

一个常见误区:以为在 daemon.json 的 registry-mirrors 里配私有仓库地址,拉镜像就能省掉 IP。

不行registry-mirrorsdocker.io 的前置缓存(pull-through cache),机制是:

bash 复制代码
docker pull nginx          ← 只有"短名"(默认解析到 docker.io)才触发 mirror
      │
      ▼
① 先查 mirror(路径会被规范化成 /v2/library/nginx/...),404 则
② 兜底查 docker.io

它不能当私有仓库别名用的原因:

  1. 只对短名生效 ------docker pull 10.145.145.1:5000/xxx 全名直奔地址,不看 mirror 配置;
  2. pull-only ------docker push 永远不经过 mirror,推镜像照样要写全地址;
  3. 路径不匹配 ------短名会被规范化成 library/<名字> 去查询,私有仓库里不存在这个路径;
  4. 误伤正常拉取 ------每条 docker pull nginx 都要先去私有仓库吃一个 404 再兜底,多一跳延迟。

它的正确用途:给 Docker Hub 套加速缓存(国内镜像加速站就是这个原理)。

省 IP 只有两条例子正路:hosts 短域名 + 443 端口 (第 12 节),或地址收进脚本(第 13 节)。


附:命令速查

bash 复制代码
# ── 服务端 ──────────────────────────────────────
docker run -d -p 5000:5000 --restart=always --name registry \
  -v /data/registry/auth:/auth -v /data/registry/data:/var/lib/registry \
  -e REGISTRY_AUTH=htpasswd \
  -e REGISTRY_AUTH_HTPASSWD_REALM="Registry" \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
  registry:2                                   # 带认证启动

docker run --rm --entrypoint htpasswd httpd:2 -Bbn user pass > htpasswd   # 生成密码

# ── 客户端 ──────────────────────────────────────
docker login 10.145.145.1:5000                 # 登录
docker logout 10.145.145.1:5000                # 登出
docker tag 本地名:tag 10.145.145.1:5000/名:tag  # 打标签
docker push 10.145.145.1:5000/名:tag           # 推送
docker pull 10.145.145.1:5000/名:tag           # 拉取
curl -u user:pass http://10.145.145.1:5000/v2/_catalog                    # 列镜像
curl -u user:pass http://10.145.145.1:5000/v2/名/tags/list                # 列标签
相关推荐
姚不倒2 小时前
etcd 学习系列(一):从业务需求出发,理解 etcd 是什么
运维·数据库·etcd
迪康Defender3 小时前
政企内网终端安全建设:资产‑管控‑防护‑审计闭环能力拆解
运维·网络·安全·web安全·终端安全管理
Neighbor_OldY3 小时前
【实战复盘】文件上传漏洞检测与应急处置:校验绕过、图片马与WebShell的排查修复指南
运维·前端·web安全
米糕闯编程3 小时前
鱼香ros2(一)在ubuntu中安装ros2
linux·运维·ubuntu·机器学习
数字孪生视频孪生3 小时前
三维实时重构异构底座 核工危化无感定位跨境轨迹一屏统揽
大数据·运维·人工智能·重构·架构
Huangjin007_3 小时前
【Linux 系统篇(十八)】进程(六) :环境变量
linux·运维·服务器
cnnews3 小时前
Ubuntu 编译 postmarketOS
linux·运维·arm开发·ubuntu·github·音视频
w01_02_033 小时前
linux, 桌面, 自启动。
linux·运维·服务器
云飞云共享云桌面4 小时前
SolidWorks+AutoCAD,多并发。可以多人共享一台设计服务器吗
运维·服务器·3d·自动化·制造