1.1 什么是 Docker 仓库
Docker 仓库(Docker Registry) 是用于存储和分发 Docker 镜像的集中式存储库。 它就像是一个大型的镜像仓库,开发者可以将自己创建的 Docker 镜像推送到仓库中,也可以从仓库中拉取所需的镜像。
Docker 仓库可以分为公共仓库 和私有仓库:
- 公共仓库,如 Docker Hub,任何人都可以访问和使用其中的镜像。许多常用的软件和应用都在 Docker Hub 上提供镜像,方便用户直接获取和使用。例如,想要部署一个 Nginx 服务器,就可以从 Docker Hub 上拉取 Nginx 的镜像。
- 私有仓库则是由组织或个人自己搭建和管理的,用于存储内部使用、不希望公开的镜像。比如,一家企业为其特定业务应用创建了定制化镜像,并存储在自有私有仓库,保障数据安全、控制访问权限。
通过 Docker 仓库,开发者能够方便地共享和复用镜像,加速应用的开发和部署过程。
1.2 Docker Hub
Docker Hub 是 Docker 官方提供的公共镜像仓库服务,也是 Docker 生态中最知名、使用最广泛的镜像仓库,拥有大量官方和社区贡献的镜像。
核心特点
- 丰富的镜像资源:涵盖操作系统、编程语言运行时、数据库、Web 服务器等各类镜像,如 Ubuntu、MySQL、Redis、Nginx 等。
- 官方支持:Docker 官方维护核心镜像,质量与安全性更有保障。
- 社区贡献:开发者可以自由上传、分享自制镜像,促进技术共享。
- 版本管理:同一个镜像提供多标签版本,可按需拉取指定版本。
- 搜索便捷:支持关键词检索镜像。
1.2.1 Docker Hub 的使用方法
# 登陆官方仓库
[root@docker ~]# docker login
Log in with your Docker ID or email address to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com/ to create one.
You can log in with your password or a Personal Access Token (PAT). Using a limited-scope PAT grants better security and is required for organizations using SSO. Learn more at https://docs.docker.com/go/access-tokens/
Username: timinglee
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-stores
Login Succeeded
#登陆信息保存位置
[root@docker ~]# cd .docker/
[root@docker .docker]# ls
config.json
[root@docker .docker]# cat config.json
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "dGltaW5nbGVlOjY3NTE1MTVtaW5nemxu"
}
}
}
# 给镜像打标签,标签格式:用户名/镜像名:版本
[root@docker ~]# docker tag gcr.io/distroless/base-debian11:latest timinglee/base-debian11:latest
# 推送镜像到Docker Hub
[root@docker ~]# docker push timinglee/base-debian11:latest
The push refers to repository [docker.io/timinglee/base-debian11]
6835249f577a: Pushed
24aacbf97031: Pushed
8451c71f8c1e: Pushed
2388d21e8e2b: Pushed
c048279a7d9f: Pushed
1a73b54f556b: Pushed
2a92d6ac9e4f: Pushed
bbb6cacb8c82: Pushed
ac805962e479: Pushed
af5aa97ebe6c: Pushed
4d049f83d9cf: Pushed
9ed498e122b2: Pushed
577c8ee06f39: Pushed
5342a2647e87: Pushed
latest: digest: sha256:f8179c20f1f2b1168665003412197549bd4faab5ccc1b140c666f9b8aa958042 size: 3234
!TIP 在国内因为网络等原因,Docker Hub 连接困难,可以配置国内镜像加速解决下载慢、拉取失败问题
[root@harbor docker]# vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://docker.m.daocloud.io"],
}
# 重启docker生效
[root@harbor docker]# systemctl restart docker
1.3 Docker 仓库的工作原理
仓库包含三个角色:
- index(索引服务):维护用户账户、镜像校验信息、公共命名空间,负责身份鉴权、发放 token。
- registry(仓库存储服务):真正存放镜像,本身不带用户数据库,依靠 index 下发的 token 完成认证。
- Registry Client:Docker 客户端,发起拉取、推送请求,携带 token 完成交互授权。
1.3.1 pull 镜像拉取原理
- docker 客户端向 index 发送镜像拉取请求,完成认证;
- index 返回认证 token + 镜像所在 registry 地址;
- 客户端携带 token,连接 registry;
- registry 拿着 token 去 index 校验合法性;
- index 确认 token 有效;
- registry 向客户端传输镜像分层数据。
1.3.2 push 镜像推送原理
- client 向 index 发起上传请求,完成用户认证;
- index 下发合法 token;
- client 携带 token 连接 Registry;
- Registry 向 index 校验 token;
- index 验证 token 合法;
- Registry 接收客户端上传的镜像层。
1.4 搭建 Docker 的私有仓库
1.4.1 为什么搭建私有仓库
Docker Hub 虽然方便,但存在限制:
- 需要公网环境,国内访问速度慢;
- 公开镜像任何人都能访问;
- 企业内部业务镜像出于安全合规,禁止上传外网。
Docker 官方开源了registry镜像,可以快速自建私有镜像仓库。 官方文档地址: Deprecated and retired Docker products and features | Docker Docs
1.4.2 搭建简单的 Registry 仓库(HTTP 无加密版)
1、拉取 registry 镜像
# 拉取镜像
[root@docker ~]# docker pull registry
Using default tag: latest
latest: Pulling from library/registry
930bdd4d222e: Pull complete
a15309931e05: Pull complete
6263fb9c821f: Pull complete
86c1d3af3872: Pull complete
a37b1bf6a96f: Pull complete
Digest: sha256:12120425f07de11a1b899e418d4b0ea174c8d4d572d45bdb640f93bc7ca06a3d
Status: Downloaded newer image for registry:latest
docker.io/library/registry:latest
# 查看本地镜像
[root@docker-node2 ~]# docker images
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
registry:latest 6c5666b861f3 77.3MB 18.8MB
2、启动 registry 容器
[root@docker-node2 ~]# docker run -d -p 5000:5000 --restart=always --name registry registry:latest
# --restart=always 容器退出自动重启,开机自启
[root@docker-node2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4e6d5cb56170 registry:latest "/entrypoint.sh /etc..." 4 seconds ago Up 3 seconds 0.0.0.0:5000->5000/tcp, [::]:5000->5000/tcp registry
3、镜像打标签
# 给要上传的镜像打标签,格式:仓库地址:端口/镜像名:版本
[root@docker-node2 ~]# docker tag busybox:latest 172.25.254.20:5000/busybox:latest
打标签的核心原因:Docker 通过标签识别推送目标仓库
nginx:latest:不带仓库地址,默认推送到 Docker Hub 官方仓库,普通用户无权限172.25.254.20:5000/nginx:latest:明确指向自建私有仓库
4、配置非加密信任(insecure-registries) Docker 默认强制使用 HTTPS,直接推送 HTTP 仓库会报错:
[root@docker-node2 ~]# docker push 172.25.254.20:5000/busybox:latest
The push refers to repository [172.25.254.20:5000/busybox]
61dfb50712f5: Unavailable
failed to do request: Head "https://172.25.254.20:5000/v2/busybox/blobs/sha256:61dfb50712f5ff92c880813210257a42169ff0937896ae95dab763582cc380e2": http: server gave HTTP response to HTTPS client
编辑 daemon.json,信任这个 HTTP 仓库:
[root@docker-node2 ~]# vim /etc/docker/daemon.json
{
"insecure-registries" : ["http://172.25.254.20:5000"]
}
# 重启docker
[root@docker-node2 ~]# systemctl restart docker
# 再次上传镜像
[root@docker-node2 ~]# docker push 172.25.254.20:5000/busybox:latest
The push refers to repository [172.25.254.20:5000/busybox]
61dfb50712f5: Pushed
latest: digest: sha256:70ce0a747f09cd7c09c2d6eaeab69d60adb0398f569296e8c0e844599388ebd6 size: 610
5、客户端拉取镜像 所有访问这个 HTTP 私有仓库的 docker 节点,都需要配置 insecure-registries
# 分发配置文件到其他docker节点
[root@docker-node2 ~]# scp -p /etc/docker/daemon.json root@172.25.254.10:/etc/docker/
# 客户端重启docker
[root@docker-node1 ~]# systemctl restart docker
# 拉取私有仓库镜像
[root@docker-node1 ~]# docker pull 172.25.254.20:5000/busybox:latest
latest: Pulling from busybox
61dfb50712f5: Pull complete
Digest: sha256:70ce0a747f09cd7c09c2d6eaeab69d60adb0398f569296e8c0e844599388ebd6
Status: Downloaded newer image for 172.25.254.20:5000/busybox:latest
[root@docker-node1 ~]# docker images
IMAGE ID DISK USAGE CONTENT SIZE
172.25.254.20:5000/busybox:latest af3f0f48a24e 4.43MB 0B
1.4.3 为 Registry 配置 HTTPS 加密传输
生产环境推荐 HTTPS,避免镜像明文传输
1.先删除 insecure 配置,清理旧 registry 容器
# 客户端和仓库节点都删除daemon.json里的不安全仓库配置
[root@docker-node1 ~]# rm -f /etc/docker/daemon.json
[root@docker-node1 ~]# systemctl restart docker
2.生成自签名 SSL 证书
# 创建证书目录
[root@docker-node2 ~]# mkdir -p /etc/docker/certs
# openssl生成证书和私钥
[root@docker-node2 ~]# openssl req -newkey rsa:4096 \
> -nodes -sha256 -keyout /etc/docker/certs/doubledragon.org.key \
> -addext "subjectAltName = DNS:reg.doubledragon.org" \
> -x509 -days 365 -out /etc/docker/certs/doubledragon.org.crt
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:shannxi
Locality Name (eg, city) [Default City]:xian
Organization Name (eg, company) [Default Company Ltd]:docker
Organizational Unit Name (eg, section) []:dragon
Common Name (eg, your name or your server's hostname) []:reg.doubledragon.org
Email Address []:admin@123
# 查看证书文件
[root@docker-node2 ~]# ls /etc/docker/certs/
doubledragon.org.crt doubledragon.org.key
3.启动带 SSL 的 registry 容器
[root@docker-node2 ~]# docker run -d -p 443:443 --restart=always --name registry \
> -v /opt/registry:/var/lib/registry \ # 持久化镜像数据
> -v /etc/docker/certs:/certs \ # 挂载证书目录
> -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \ # 监听443端口
> -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/doubledragon.org.crt \
> -e REGISTRY_HTTP_TLS_KEY=/certs/doubledragon.org.key registry
4.配置域名本地解析(所有节点)
[root@docker-node2 ~]# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.254.20 docker-node2
172.25.254.20 reg.doubledragon.org
5.Docker 信任自签名证书 Docker 识别证书目录规则:/etc/docker/certs.d/域名/下放 crt 证书
# 创建证书信任目录
[root@docker-node2 ~]# mkdir -p /etc/docker/certs.d/reg.doubledragon.org
# 复制证书
[root@docker-node2 ~]# cp -p /etc/docker/certs/doubledragon.org.crt /etc/docker/certs.d/reg.doubledragon.org/
# 重启docker
[root@docker-node2 ~]# systemctl restart docker
6.HTTPS 推拉镜像测试
# 打标签,使用域名
[root@docker-node2 ~]# docker tag busybox:latest reg.doubledragon.org/busybox:latest
# 推送镜像
[root@docker-node2 ~]# docker push reg.doubledragon.org/busybox:latest
The push refers to repository [reg.doubledragon.org/busybox]
61dfb50712f5: Pushed
latest: digest: sha256:70ce0a747f09cd7c09c2d6eaeab69d60adb0398f569296e8c0e844599388ebd6 size: 610
# 客户端同步证书、拉取镜像
[root@docker-node1 ~]# mkdir -p /etc/docker/certs.d/reg.doubledragon.org
[root@docker-node2 ~]# scp /etc/docker/certs.d/reg.doubledragon.org/doubledragon.org.crt 172.25.254.10:/etc/docker/certs.d/reg.doubledragon.org/
[root@docker-node1 ~]# systemctl restart docker
[root@docker-node1 ~]# docker pull reg.doubledragon.org/busybox:latest
latest: Pulling from busybox
Digest: sha256:70ce0a747f09cd7c09c2d6eaeab69d60adb0398f569296e8c0e844599388ebd6
Status: Downloaded newer image for reg.doubledragon.org/busybox:latest
1.4.4 为仓库添加账号密码登录认证
开启 htpasswd 基础认证,访问仓库必须先 docker login
# 安装htpasswd工具(httpd-tools)
[root@docker-node2 ~]# dnf install httpd-tools -y
# 创建密码存放目录
[root@docker-node2 ~]# mkdir /etc/docker/auth
# 创建用户dragon,-B 使用bcrypt强加密
[root@docker-node2 ~]# htpasswd -Bc /etc/docker/auth/htpasswd dragon
New password:
Re-type new password:
Adding password for user dragon
重启 registry 容器,开启认证参数:
[root@docker-node2 ~]# docker run -d -p 443:443 --restart=always --name registry \
> -v /opt/registry:/var/lib/registry \
> -v /etc/docker/certs:/certs \
> -v /etc/docker/auth:/auth \
> -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
> -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/doubledragon.org.crt \
> -e REGISTRY_HTTP_TLS_KEY=/certs/doubledragon.org.key \
> -e "REGISTRY_AUTH=htpasswd" \
> -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
> -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
> registry
测试:
# curl携带账号密码查询仓库镜像列表
[root@docker-node2 ~]# curl -k https://reg.doubledragon.org/v2/_catalog -u dragon:123
{"repositories":["busybox"]}
# docker登录私有仓库
[root@docker-node2 ~]# docker login reg.doubledragon.org
Username (dragon): dragon
Password:
WARNING! Your credentials are stored unencrypted in '/root/.docker/config.json'.
Configure a credential helper to remove this warning.
Login Succeeded
开启认证之后:推拉镜像都必须先登录,未登录直接 401 报错
# 未登录拉取报错示例
[root@docker-node1 ~]# docker pull reg.doubledragon.org/busybox:latest
Error response from daemon: unauthorized: authentication required
# 登录后正常拉取
[root@docker-node1 ~]# docker login reg.doubledragon.org
[root@docker-node1 ~]# docker pull reg.doubledragon.org/busybox:latest
latest: Pulling from busybox
61dfb50712f5: Already exists
Digest: sha256:70ce0a747f09cd7c09c2d6eaeab69d60adb0398f569296e8c0e844599388ebd6
Status: Downloaded newer image for reg.doubledragon.org/busybox:latest
1.5 构建企业级私有仓库
软件包下载地址: https://github.com/goharbor/harbor/releases
Harbor 是由 VMware 公司开源的企业级 Docker Registry 项目。 它提供了以下主要功能和特点:
- 基于角色的访问控制(RBAC):可以为不同的用户和用户组分配不同的权限,增强了安全性和管理的灵活性。
- 镜像复制:支持在不同的 Harbor 实例之间复制镜像,方便在多个数据中心或环境中分发镜像。
- 图形化用户界面(UI):提供了直观的 Web 界面,便于管理镜像仓库、项目、用户等。
- 审计日志:记录了对镜像仓库的各种操作,有助于追踪和审查活动。
- 垃圾回收:可以清理不再使用的镜像,节省存储空间。
前面我们搭建的原生 registry 只适合测试环境,没有 Web 页面、权限管理、镜像扫描、同步复制等能力,生产环境优先选择 Harbor。
1.5.1 部署 Harbor
前置要求:服务器已经部署好 Docker、docker-compose;提前准备好 SSL 证书(沿用前面reg.doubledragon.org证书方案)
1、下载 harbor 离线安装包
# 下载harbor仓库软件包
[root@docker-node1 ~]# wget https://github.com/goharbor/harbor/releases/download/v2.15.0/harbor-offline-installer-v2.15.0.tgz
[root@docker-node1 ~]# ls
busy-latest.tar docker harbor-offline-installer-v2.15.0.tgz mario-latest.tar nginx-1.26.tar registry.tar
# 解压
[root@docker-node1 ~]# tar zxf harbor-offline-installer-v2.15.0.tgz
[root@docker-node1 ~]# ls harbor
common.sh harbor.v2.15.0.tar.gz harbor.yml.tmpl install.sh LICENSE prepare
# 移动到安装目录
[root@docker-node1 ~]# cp -rp harbor /usr/local/
# 进入harbor目录,导入离线镜像包
[root@docker-node1 ~]# cd /usr/local/harbor/
[root@docker-node1 harbor]# docker load -i harbor.v2.15.0.tar.gz
[root@docker-node1 harbor]# docker images
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
goharbor/harbor-core:v2.15.0 87a862e24da8 210MB 0B
goharbor/harbor-db:v2.15.0 e66097841983 274MB 0B
goharbor/harbor-exporter:v2.15.0 13f0dff4f807 112MB 0B
goharbor/harbor-jobservice:v2.15.0 2fe35692621f 185MB 0B
goharbor/harbor-log:v2.15.0 9e71d0bc1e73 170MB 0B
goharbor/harbor-portal:v2.15.0 b3939ccdd07f 166MB 0B
goharbor/harbor-registryctl:v2.15.0 4b2b3294a46c 166MB 0B
goharbor/nginx-photon:v2.15.0 77728976f2e8 158MB 0B
goharbor/prepare:v2.15.0 029f75920a4b 199MB 0B
goharbor/redis-photon:v2.15.0 4ed296911e8b 173MB 0B
goharbor/registry-photon:v2.15.0 5b02673a2fa2 87.7MB 0B
goharbor/trivy-adapter-photon:v2.15.0 e9d91b67c413 408MB 0B
2、配置 SSL 证书(沿用前面私有仓库证书案例) 提前把证书放到 /data/certs/
# 目录准备
mkdir -p /data/certs
cp /etc/docker/certs/doubledragon.org.crt /data/certs/
cp /etc/docker/certs/doubledragon.org.key /data/certs/
3、配置 harbor.yml
# 复制模板文件
[root@docker-node1 harbor]# cp -p harbor.yml.tmpl harbor.yml
[root@docker-node1 harbor]# vim harbor.yml
修改核心内容:
hostname: reg.doubledragon.org
https:
certificate: /data/certs/doubledragon.org.crt
private_key: /data/certs/doubledragon.org.key
harbor_admin_password: 123
注意:注释掉 https 段落会使用 HTTP 访问,生产环境禁止;hostname 必须和证书域名保持一致。
4、安装 harbor
# 预安装检查,生成配置文件
[root@docker-node1 harbor]# ./prepare
prepare base dir is set to /usr/local/harbor
Generated configuration file: /config/portal/nginx.conf
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/log/rsyslog_docker.conf
Generated configuration file: /config/nginx/nginx.conf
Generated configuration file: /config/core/env
Generated configuration file: /config/core/app.conf
Generated configuration file: /config/registry/config.yml
Generated configuration file: /config/registryctl/env
Generated configuration file: /config/registryctl/config.yml
Generated configuration file: /config/db/env
Generated configuration file: /config/jobservice/env
Generated configuration file: /config/jobservice/config.yml
copy /data/secret/tls/harbor_internal_ca.crt to shared trust ca dir as name harbor_internal_ca.crt ...
ca file /hostfs/data/secret/tls/harbor_internal_ca.crt is not exist
copy to shared trust ca dir as name storage_ca_bundle.crt ...
copy None to shared trust ca dir as name redis_tls_ca.crt ...
loaded secret from file: /data/secret/keys/secretkey
Generated configuration file: /compose_location/docker-compose.yml
Clean up the input dir
# 执行安装脚本,自动拉起所有组件
[root@docker-node1 harbor]# ./install.sh
✔ ----Harbor has been installed and started successfully.----
# 也可以手动使用docker-compose启动
# docker-compose up -d
5、验证安装
# 查看容器状态
[root@docker-node1 harbor]# docker compose ps
# 查看实时日志,排查报错
[root@docker-node1 harbor]# docker compose logs -f
# 检查服务监听端口,默认80、443
[root@docker-node1 harbor]# netstat -anplute | grep -E '80|443|5000'
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 0 36483 3460/docker-proxy
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 0 36476 3433/docker-proxy
tcp 0 0 127.0.0.1:36748 127.0.0.1:1514 ESTABLISHED 0 37180 1436/dockerd
tcp 0 0 172.20.0.1:51980 172.20.0.2:10514 ESTABLISHED 0 35453 2864/docker-proxy
tcp6 0 0 :::443 :::* LISTEN 0 36484 3466/docker-proxy
tcp6 0 0 :::80 :::* LISTEN 0 36477 3440/docker-proxy
4.5.2 harbor 仓库的维护管理
常用维护命令
# 停止Harbor所有组件
docker-compose down
# 后台启动Harbor
docker-compose up -d
# 重启Harbor
docker-compose restart
# 查看指定服务日志,例如core、registry
docker-compose logs -f [服务名]
# 进入指定容器内部
docker-compose exec [服务名] bash
备份与恢复
Harbor 数据分为:镜像存储数据卷 + PostgreSQL 数据库,两个都要备份
# 备份镜像数据卷
tar -czf harbor-backup-$(date +%F).tar.gz /data
# 单独备份registry业务数据库
docker-compose exec -T database pg_dump -U postgres registry > registry.sql
升级 Harbor
# 停止旧版本服务
docker-compose down
# 先执行上面的备份操作,备份数据库和镜像数据
# 解压新版本离线包
tar -zxf harbor-offline-installer-v2.14.0.tgz
cd harbor
# 复制原有harbor.yml配置文件到新版本目录
cp ../harbor.yml .
# 执行升级脚本
./install.sh --upgrade
上传与拉取镜像
所有 Docker 客户端节点注意两点:
- /etc/hosts 添加域名解析
- 自签名证书放到
/etc/docker/certs.d/reg.doubledragon.org/
# 登录harbor
docker login reg.doubledragon.org
# 给镜像打标签,格式:Harbor域名/项目名/镜像名:tag
[root@docker-node1 ~]# docker tag busybox:latest reg.doubledragon.org/library/busybox:latest
# 推送镜像到harbor
[root@docker-node1 ~]# docker push reg.doubledragon.org/library/busybox:latest
The push refers to repository [reg.doubledragon.org/library/busybox]
495ba00f2547: Pushed
latest: digest: sha256:91c66c844e6bba57e92e10e755e73a816d0b99edd17eb5297d9ac519ab3a8c81 size: 527
网页端 Harbor 管理
浏览器访问:https://reg.doubledragon.org(提前配置本地域名解析)
- 默认管理员账号:
admin,密码为 harbor.yml 中配置的harbor_admin_password - 可以可视化创建项目、管理用户、分配权限、查看镜像、删除镜像、查看审计日志、配置镜像复制策略、执行漏洞扫描。