一、构建企业级 Docker 私有仓库 Harbor
1.1 Harbor 介绍
Docker 容器应用的开发和运行离不开可靠的镜像管理。虽然 Docker 官方也提供了公共的镜像仓库(Docker Hub),但从安全 和效率等方面考虑,部署私有环境内的 Registry 也是非常必要的。
Harbor 是由 VMware 公司开源的企业级 Docker Registry 管理项目,主要功能包括:
| 功能 | 说明 |
|---|---|
| 权限管理(RBAC) | 基于角色的访问控制,精细化管理用户权限 |
| LDAP 集成 | 支持与企业 LDAP/AD 认证系统对接 |
| 日志审核 | 记录所有镜像操作日志,便于审计 |
| 管理界面 | 提供图形化 Web 管理界面 |
| 自我注册 | 用户可自行注册账号 |
| 镜像复制 | 支持跨 Harbor 实例的镜像同步 |
| 中文支持 | 原生支持中文界面 |
1.2 环境要求
| 角色 | 客户端(Client) | 服务器端(Harbor) |
|---|---|---|
| 主机名 | hd1 | harbor |
| IP 地址 | 192.168.1.11 | 192.168.1.12 |
| 软件安装 | Docker | Docker |
| 硬件配置 | 2vCPU / 2G 内存 | 4vCPU / 4G 内存 |
1.3 下载离线包
从 Harbor 官方 GitHub Releases 页面下载离线安装包:
文件名示例:harbor-offline-installer-v2.11.0.tgz
离线包包含了 Harbor 运行所需的所有容器镜像,无需联网即可安装,适合内网环境。
1.4 安装过程
创建安装目录
在 Harbor 服务器(192.168.1.12)上操作:
bash
[root@harbor ~]# mkdir /data/install -p
[root@harbor ~]# cd /data/install/
解压安装包
bash
[root@harbor install]# mv /root/zxvf harbor-offline-installer-v2.11.0.tgz .
[root@harbor install]# tar zxvf harbor-offline-installer-v2.11.0.tgz
[root@harbor install]# cd harbor
#把模板文件的后缀去掉
[root@harbor harbor]# cp harbor.yml.tmpl harbor.yml
修改配置文件
bash
#这个是harbor的主配置文件
[root@harbor harbor]# vim harbor.yml
关键修改:禁用 HTTPS(使用 HTTP 协议)及证书和私钥文件
由于是实验环境,我们使用 HTTP 协议访问 Harbor,需要注释掉 HTTPS 相关的证书和私钥配置。

注意:生产环境建议启用 HTTPS,以保证传输安全。
Harbor 默认管理员账号密码:admin / Harbor12345,可以在主配置文件中进行修改

建议修改一个简单好记的密码。这里我们修改成123456
安装 Docker Compose
Harbor 使用 Docker Compose 进行容器编排,因此需要先安装 docker-compose。
bash
# 上传 docker-compose-linux-x86_64 文件到 harbor 机器,直接拷贝到 PATH 目录,加执行权限即可
[root@harbor harbor]# mv docker-compose-linux-x86_64 /usr/bin/docker-compose
[root@harbor harbor]# chmod +x /usr/bin/docker-compose
# 验证安装
[root@harbor harbor]# docker-compose --version
补充知识点:Docker Compose 简介
Docker Compose 是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。Compose 的工程配置文件默认为
docker-compose.yml,Docker Compose 可以管理多个 Docker 实例(容器),实现一键启动/停止整个应用栈。
安装 Harbor
bash
[root@harbor harbor]# ./install.sh
安装成功输出示例:
[Step 5]: starting Harbor ...
[+] Running 10/10
✔ Network harbor_harbor Created 0.3s
✔ Container harbor-log Started 0.6s
✔ Container harbor-db Started 1.1s
✔ Container registry Started 1.2s
✔ Container harbor-portal Started 1.2s
✔ Container redis Started 1.2s
✔ Container registryctl Started 1.2s
✔ Container harbor-core Started 1.5s
✔ Container harbor-jobservice Started 1.8s
✔ Container nginx Started 2.0s
✔ ----Harbor has been installed and started successfully.----
install.sh脚本会自动:
- 创建 Harbor 所需的 Docker 网络
- 拉取/加载所有依赖的镜像
- 启动所有 Harbor 服务容器(包括 nginx、redis、数据库等)
Harbor 服务管理
常用命令:
| 命令 | 作用 | 适用场景 |
|---|---|---|
docker-compose up -d |
创建并启动所有服务(后台) | 日常部署、启动项目 |
docker-compose up(无 -d) |
创建并启动所有服务(前台,日志输出到终端) | 调试、查看实时日志 |
docker-compose start |
启动已有的容器(不创建新的) | 重启之前停止的服务(前提是容器还存在) |
docker-compose down |
停止并删除所有容器、网络等资源 | 彻底清理环境 |
docker-compose stop |
停止所有容器,但保留容器和网络 | 临时暂停服务 |
bash
# 进入 Harbor 安装目录
[root@harbor harbor]# cd /data/install/harbor
# 停止 Harbor
[root@harbor harbor]# docker-compose stop
[+] Stopping 9/9
✔ Container harbor-jobservice Stopped 0.2s
✔ Container nginx Stopped 0.2s
✔ Container registryctl Stopped 0.2s
✔ Container harbor-portal Stopped 0.1s
✔ Container harbor-core Stopped 0.2s
✔ Container registry Stopped 0.2s
✔ Container redis Stopped 0.2s
✔ Container harbor-db Stopped 0.2s
✔ Container harbor-log Stopped
# 启动 Harbor
[root@harbor harbor]# docker-compose start
在执行docker-compose stop的时候,我们发现有九个容器被关闭了。这九个容器是哪来的呢?
这是因为harbor在安装时,自带了一个docker-compose.yml文件,包含了Harbor 的 9 个组件容器。这个文件我们是不需要去动的
如果 docker-compose start 启动 Harbor 后还是访问不了,建议重启虚拟机。
二、Harbor 图形界面
2.1 访问 Harbor
在浏览器中输入:http://192.168.1.12
访问正常会显示 Harbor 登录界面。

2.2 登录
| 字段 | 默认值 |
|---|---|
| 用户名 | admin |
| 密码 | 123456 |
| 默认密码是Harbor12345,我们之前已经修改为123456,直接登陆即可 |

2.3 界面说明
library项目:Harbor 默认的公开镜像仓库,所有基础镜像默认放在这里。- 用户可以在
library中上传和下载镜像(无需登录即可拉取公开镜像)。

2.4 新建项目
- 点击 新建项目(New Project)
- 输入项目名称(如
test) - 勾选 "公开"(Public)选项,让项目可以被公开访问(项目配额限制为-1代表不作限制)
- 点击确认
注意 :如果不勾选"公开",项目默认是私有的,这样在拉取镜像时,需要先 docker login 才能拉取镜像。

三、测试使用 Harbor 私有镜像仓库
3.1 客户端配置(hd1 主机)
修改 Docker 主配置文件,添加 Harbor 仓库地址到安全列表:
bash
[root@hd1 ~]# vim /etc/docker/daemon.json
注意!所有要使用这个私人仓库的服务器都需要进行修改
json
{
"iptables": true, # 关键修复
"ip-masq": true, #辅助
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://docker.1ms.run",
"https://docker.xuanyuan.me"
],
"insecure-registries": ["192.168.1.12", "harbor"]
}
insecure-registries:告诉 Docker 允许使用 HTTP 协议访问这些仓库(不加会报 HTTPS 错误)
使配置生效:
bash
[root@hd1 ~]# systemctl daemon-reload && systemctl restart docker
[root@hd1 ~]# systemctl status docker
3.2 登录 Harbor
docker login harbor主机IP
bash
[root@hd1 ~]# docker login 192.168.1.12
Username: admin
Password: 123456
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/#credentials-store
Login Succeeded
登录成功后,Docker 会在 ~/.docker/config.json 中保存认证信息。后续再进行登录时,无需密码即可登录
3.3 为镜像打标签
要将镜像推送到 Harbor,需要按照格式 仓库地址/项目名/镜像名:标签 打标签:
bash
# 查看本地镜像
[root@hd1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
volume latest c2d6bed5a25f 29 hours ago 209MB
tomcat8 v2 79d40edca7c2 30 hours ago 747MB
# 给本地的httpd_silm:v1镜像打标签(格式:harbor地址(域名也可)/项目名/镜像名:标签)
[root@hd1 ~]# docker tag httpd_silm:v1 192.168.1.12/test/httpdsl:v1
#打完标签,可以在本地看到
[root@hd1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.1.12/test/httpdsl v1 00237382377a 15 hours ago 11.1MB
httpd_silm v1 00237382377a 15 hours ago 11.1MB
标签格式解析:
192.168.1.12:Harbor 仓库地址test:项目名称(在 Harbor 中创建的项目)centos:镜像名称v1:标签(版本号)
3.4 上传镜像到 Harbor
bash
#标签中已经有了harbor的地址,之前又已经docker login 了harbor主机,所以可以直接推送
[root@hd1 ~]# docker push 192.168.1.12/test/httpdsl:v1
The push refers to repository [192.168.1.12/test/httpdsl]
15e949c13c72: Pushed
v1: digest: sha256:30e8aef6c41135b3c9ae653ff840d9235898d94826f5058ad972903a8b76d9b3 size: 528
上传成功后,可以在 Harbor Web 界面中 test 项目下看到该镜像。

注意!推送前必须先 docker login 192.168.1.12认证身份,否则会报 unauthorized 错误
3.5 从 Harbor 下载镜像
bash
#配置harbor主机,充当另一台主机
[root@harbord harbor]# vim /etc/docker/daemon.json
{
"iptables": true,
"ip-masq": true,
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://docker.1ms.run",
"https://docker.xuanyuan.me"
],
"insecure-registries": ["192.168.1.12", "harbor"]
}
#刷新配置,重启服务
[root@harbord harbor]# systemctl daemon-reload && systemctl restart docker
#重新启动harbor服务(因为重启docker会导致harbor服务关闭。所以最好还是在非harbor主机进行验证)
[root@harbord harbor]# docker-compose up -d
# Harbor 拉取镜像
[root@harbord harbor]# docker pull 192.168.1.12/test/httpdsl:v1
v1: Pulling from test/httpdsl
8a27c271bd57: Pull complete
Digest: sha256:30e8aef6c41135b3c9ae653ff840d9235898d94826f5058ad972903a8b76d9b3
Status: Downloaded newer image for 192.168.1.12/test/httpdsl:v1
192.168.1.12/test/httpdsl:v1
#查看镜像
[root@harbord harbor]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.1.12/test/httpdsl v1 00237382377a 15 hours ago 11.1MB
如果是从harbor私有仓库中拉取,必须先使用 docker login 仓库地址 进行登录验证身份再进行拉取
使用harbor的快速总结
1.对应主机要安装docker
2.要修改/etc/docker/daemon.json配置文件,增加harbor仓库的地址
3.在私有项目中拉取,必须先docker login harborIP登录验证身份
踩坑经历
在客户端配置完毕之后,我在h1主机准备进行登录,结果报错:
bash
[root@hd1 h1]# docker login 192.168.1.12
Username: admin
Password:
Error response from daemon: Get "http://192.168.1.12/v2/": dial tcp 192.168.1.12:80: connect: connection refused
经过排查,发现可能是harbor主机80端口未开启。
在harbor主机使用docker-compose ps,发现九个容器只有一个运行
bash
[root@localhost harbor]# docker-compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
harbor-log goharbor/harbor-log:v2.13.4 "/bin/sh -c /usr/loc..." log 40 minutes ago Up 13 minutes (healthy) 127.0.0.1:1514->10514/tcp
尝试重启,结果报错(大概意思是Docker 在尝试创建 Harbor 所需的网络时,无法操作 iptables 规则,因为找不到名为 DOCKER 的链)
bash
[root@localhost harbor]# docker-compose up -d
[+] Running 1/0
✘ Network harbor_harbor Error 0.0s
failed to create network harbor_harbor: Error response from daemon: Failed to Setup IP tables: Unable to enable SKIP DNAT rule: (iptables failed: iptables --wait -t nat -I DOCKER -i br-3ed1ec0cfd48 -j RETURN: iptables: No chain/target/match by that name.
(exit status 1))
所以问题是Docker 的 iptables 规则与系统防火墙(Firewalld)冲突 ,导致 Harbor 无法正确创建内部网络(harbor_harbor)
为什么会出现这个冲突?
- CentOS / Rocky / AlmaLinux 等系统默认使用 Firewalld
- Docker 自己也会操作 iptables 创建网络规则
- 两者经常"打架",尤其在离线安装包 、虚拟机 、重启多次的环境中特别容易出现
解决问题
我们需要在客户端进行配置,
bash{
"iptables": true, # 关键修复
"ip-masq": true, #辅助
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://docker.1ms.run",
"https://docker.xuanyuan.me"
],
"insecure-registries": ["192.168.1.12", "harbor"]
}
"iptables": true
- 作用 :明确告诉 Docker 我要自己管理 iptables 规则。
- 系统里 Firewalld(或 iptables)与 Docker 产生了冲突,导致创建网络时无法插入
SKIP DNAT规则。 - 很多 CentOS/RHEL 类系统默认会和 Docker 打架,加上这个参数可以让 Docker 正确处理 NAT 和网络规则。
"ip-masq": true
- 作用:启用 IP 伪装(Masquerading),让容器能正常访问外部网络。
- 通常和
iptables一起使用,确保网络连通性。
生产环境提醒
- 强烈建议后面开启 HTTPS(生产环境用 HTTP 非常不安全)。
- 可以考虑把 Harbor 端口改成 8080 等非标准端口,避免和系统其他服务冲突。
四、申请阿里云容器镜像仓库
4.1 阿里云个人仓库基本配置
- 登录 www.aliyun.com,使用淘宝或支付宝账号扫码登录。
- 在搜索框中输入 "镜像" ,点击搜索结果的 "容器镜像服务"。

- 选择 管理控制台 → 选择 个人版。

我们选择个人版

- 选择 命名空间 → 点击 创建命名空间 ,输入自定义命名空间名称(如
kisaki_mi)。

- 点击 访问凭证 → 选择 设置固定密码 (此密码用于
docker login,不要与阿里云登录密码相同)。

⚠️ 此密码仅用于容器镜像服务,不要与阿里云(支付宝)登录密码相同。
4.2 创建镜像仓库
- 创建命名空间之后,我们开始创建镜像仓库(创建的仓库名最好和你要上传的镜像名相对应,避免搞混,如
httpd仓库,我们就上传httpd的镜像)。

- 选择 本地仓库 → 点击 创建镜像仓库。

- 创建成功后,在镜像仓库列表中可以看到。

4.3 推送镜像到阿里云个人仓库
关于如何登录和推送,拉取,个人仓库页的操作指南有详细说明

bash
# 1. 登录阿里云 Docker Registry
[root@hd1 ~]# docker login --username=ksisaki443 crpi-tpa4crtg4ht0cwkw.cn-hangzhou.personal.cr.aliyuncs.com
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/#credentials-store
Login Succeeded
# 2. 给本地镜像打标签(按照提供的模板进行修改即可)
[root@hd1 ~]# docker tag httpd_silm:v1 crpi-tpa4crtg4ht0cwkw.cn-hangzhou.personal.cr.aliyuncs.com/kisaki_mi/httpd:s1
#可以看到源镜像和我们打标签的镜像
[root@hd1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
crpi-tpa4crtg4ht0cwkw.cn-hangzhou.personal.cr.aliyuncs.com/kisaki_mi/httpd s1 00237382377a 16 hours ago 11.1MB
httpd_silm v1 00237382377a 16 hours ago 11.1MB
# 3. 推送镜像到阿里云
[root@hd1 ~]# docker push crpi-tpa4crtg4ht0cwkw.cn-hangzhou.personal.cr.aliyuncs.com/kisaki_mi/httpd:s1
The push refers to repository [crpi-tpa4crtg4ht0cwkw.cn-hangzhou.personal.cr.aliyuncs.com/kisaki_mi/httpd]
15e949c13c72: Pushed
s1: digest: sha256:30e8aef6c41135b3c9ae653ff840d9235898d94826f5058ad972903a8b76d9b3 size: 528
推送的时候,我们只需要按照操作指南里的指引操作就行了。打标签语句的模板:
docker tag ImageId crpi-tpa4crtg4ht0cwkw.cn-hangzhou.personal.cr.aliyuncs.com/kisaki_mi/httpd:镜像版本号
我们只需要把**ImageId改成我们要推送的 本地镜像名:标签**,把 httpd:镜像版本号 改成 httpd:自己的标签 即可
注意,不要修改左边的httpd,否则会在阿里云创建一个新的仓库
在阿里云个人仓库可以看到,已经上传完毕:

细节补充:我们上传的明明是9M的,上传却只有4M多,这是因为Docker 镜像在推送时进行了压缩,并且阿里云容器镜像服务显示的是"压缩后的实际存储大小"
五、核心知识点总结
5.1 Harbor vs 官方 Docker Hub
| 对比项 | Docker Hub(公共) | Harbor(私有) |
|---|---|---|
| 访问控制 | 公开/私有仓库 | 细粒度 RBAC 权限管理 |
| 安全性 | 依赖用户管理 | 企业级安全审计、LDAP 集成 |
| 部署位置 | 云端(Docker 官方) | 本地/内网部署 |
| 镜像拉取速度 | 受网络影响(尤其国内) | 内网拉取极快 |
| 成本 | 免费(有限制) | 开源免费,自己维护 |
5.2 私有仓库使用流程
1. 部署 Harbor
├── 安装 Docker
├── 安装 Docker Compose
├── 配置 harbor.yml(禁用 HTTPS)
└── 执行 install.sh
2. 客户端配置
├── 修改 daemon.json(添加 insecure-registries)
└── 重启 Docker
3. 镜像操作
├── docker login <仓库地址>
├── docker tag <原镜像> <仓库地址>/<项目>/<镜像名>:<标签>
└── docker push <仓库地址>/<项目>/<镜像名>:<标签>
5.3 核心命令速查
| 命令 | 说明 |
|---|---|
docker login 192.168.1.12 |
登录 Harbor 私有仓库 |
docker tag nginx:latest 192.168.1.12/test/nginx:v1 |
为镜像打标签 |
docker push 192.168.1.12/test/nginx:v1 |
推送镜像到私有仓库 |
docker pull 192.168.1.12/test/nginx:v1 |
从私有仓库拉取镜像 |
docker rmi 192.168.1.12/test/nginx:v1 |
删除本地镜像 |
5.4 常见错误处理
| 错误信息 | 原因 | 解决方法 |
|---|---|---|
http: server gave HTTP response to HTTPS client |
Docker 默认使用 HTTPS,但 Harbor 是 HTTP | 在 daemon.json 中添加 "insecure-registries": ["192.168.1.12"] |
denied: requested access to the resource is denied |
未登录或没有权限 | 先执行 docker login 192.168.1.12 |
unauthorized: authentication required |
登录凭证无效 | 检查用户名/密码,重新 docker login |
六、扩展知识:Docker Compose 简介
Docker Compose 是 Docker 官方提供的容器编排工具,用于定义和运行多个容器的应用。
- 配置文件 :
docker-compose.yml(默认) - 工作原理:通过一个 YAML 文件定义多个服务(容器),通过一条命令启动/停止所有容器
- Harbor 与 Compose 的关系:Harbor 实际上是由多个容器组成的应用(nginx、redis、数据库、registry 等),通过 Docker Compose 统一管理
常用 Compose 命令:
| 命令 | 说明 |
|---|---|
docker-compose up -d |
后台启动所有服务 |
docker-compose stop |
停止所有服务 |
docker-compose start |
启动已停止的服务 |
docker-compose down |
停止并删除所有容器 |
docker-compose logs -f |
实时查看日志 |
docker-compose ps |
查看服务状态 |