🚀 从零到一:我在服务器上部署企业级镜像仓库 Harbor 的全过程记录
一、 前言:为什么我需要一个私有镜像仓库? 🤔
在我的微服务项目 hx-health-cloud 的开发过程中,我遇到了一个经典的需求:我需要一个地方来统一、安全地管理我们团队构建的所有 Docker 镜像。直接使用公共的 Docker Hub 不仅有速率限制,更重要的是,将包含业务代码的镜像放在公网上,始终存在安全隐患。
经过一番调研,我决定放弃轻量级的 registry 方案,直接一步到位,选择云原生计算基金会 (CNCF, Cloud Native Computing Foundation) 的毕业项目——Harbor,来为我的测试环境搭建一个功能强大的企业级私有镜像仓库。
这篇文章,将完整记录我从一台全新的 Ubuntu 服务器开始,直到成功部署并运行 Harbor 的每一个步骤、每一个命令、甚至每一次深入源码的思考。
二、 准备阶段:兵马未动,粮草先行 🛠️
在开始“施工”之前,我先确保我的“地基”是稳固的。
终端输出显示,apt 更新了软件包列表,并成功安装了 jq 及其依赖 libjq1 和 libonig5。一切顺利!
三、 核心步骤:自动化与配置的艺术 🎨
第一步:【自动化】一键获取最新版 Harbor
我不想手动去 GitHub 的 Release 页面翻找最新版本和下载链接。于是,我使用了下面这个非常酷的自动化脚本,它能帮我搞定一切。
我直接在终端完整地复制、粘贴并执行了这段脚本:
#!/bin/bash
# — 脚本开始 —
echo "🚀 正在查询 Harbor 最新稳定版本…"
# 1. 使用 GitHub API 获取最新 release 的信息
LATEST_RELEASE_URL=$(curl -s https://api.github.com/repos/goharbor/harbor/releases/latest)
# 2. 使用 jq 解析出在线安装包 (online-installer) 的下载链接
DOWNLOAD_URL=$(echo "$LATEST_RELEASE_URL" | jq -r '.assets[] | select(.name | contains("online-installer")) | .browser_download_url')
# 3. 检查是否成功获取到 URL
if [ -z "$DOWNLOAD_URL" ]; then
echo "❌ 错误:无法自动获取最新的 Harbor 下载链接。请检查网络连接或手动访问 https://github.com/goharbor/harbor/releases"
exit 1
fi
# 4. 从 URL 中提取文件名
FILENAME=$(basename "$DOWNLOAD_URL")
echo "✅ 找到最新版本文件: $FILENAME"
echo "开始下载,请稍候…"
# 5. 使用 wget 下载文件,并显示进度条
wget -q –show-progress "$DOWNLOAD_URL"
# 6. 检查下载是否成功
if [ $? -ne 0 ]; then
echo "❌ 错误:文件下载失败。"
exit 1
fi
echo "✅ 下载完成,正在解压…"
# 7. 解压下载的 tgz 文件
tar xzvf "$FILENAME"
# 8. 检查解压是否成功
if [ $? -ne 0 ]; then
echo "❌ 错误:文件解压失败。"
exit 1
fi
echo "🎉 成功!Harbor 安装文件已准备就绪,位于 'harbor' 目录中。"
echo "下一步:请进入 'harbor' 目录并配置 'harbor.yml' 文件。"
# — 脚本结束 —
终端的输出让我非常满意,它完美地执行了我的意图:
🚀 正在查询 Harbor 最新稳定版本…
✅ 找到最新版本文件: harbor-online-installer-v2.14.0.tgz
开始下载,请稍候…
harbor-online-installer-v2.14.0.tgz 100%[===================>] 11.54K –.-KB/s in 0.02s
✅ 下载完成,正在解压…
harbor/prepare
harbor/LICENSE
harbor/install.sh
harbor/common.sh
harbor/harbor.yml.tmpl
🎉 成功!Harbor 安装文件已准备就绪,位于 'harbor' 目录中。
太棒了!脚本自动帮我找到了最新的 v2.14.0 版本,并完成了下载和解压。我甚至都不需要知道版本号是多少!
第二步:个性化配置 harbor.yml
这是整个过程中唯一需要我手动“创作”的部分。
进入 harbor 目录并创建配置文件:
cd harbor
cp harbor.yml.tmpl harbor.yml
编辑配置文件:
我习惯性地输入 vim harbor.yml,结果系统提示 Command 'vim' not found。这是一个小插曲,说明我的服务器是一个非常纯净的环境。系统友好地提示我可以用 sudo apt install vim 来安装。不过,为了不节外生枝,我选择了另一个预装的编辑器 nano:
nano harbor.yml
我的配置决策:
在 nano 编辑器中,我进行了以下关键修改:
- hostname: 我没有使用域名,因为这只是一个内部测试环境。我直接将其设置为我服务器的 IP 地址:192.168.31.73。
- http.port: 为了避免与服务器上可能存在的其他服务(如 Nginx)冲突,我将默认的 80 端口改为了 81。
- https: 我用 # 注释掉了整个 https 配置块。因为这是内部测试,暂时不需要配置复杂的 HTTPS (HyperText Transfer Protocol Secure, 安全超文本传输协议)。(注意:这在生产环境中是绝对不推荐的!)
- harbor_admin_password: 我设置了一个简单的初始密码 Harbor12345。
- database.password: 我也为数据库设置了一个密码 root123。
- 其他配置(如 data_volume)我都保留了默认值。
配置完成后,我使用 cat harbor.yml 命令检查了一遍,确保修改无误。
第三步:执行安装,见证奇迹的时刻 ✨
一切准备就绪,我以 sudo 权限运行了 Harbor 的安装脚本:
sudo ./install.sh
终端的输出就像一部精彩的戏剧,上演了 Harbor 的诞生过程:
[Step 0 & 1] 环境检查 ✅:脚本首先检查了 docker 和 docker-compose 是否存在。根据我的终端日志,它确认了我的环境版本,这对于问题排查至关重要。
- Docker Version: 28.4.0
- Docker Compose Version: v2.40.0
这里有一个非常巧妙的技术细节。通过直接查看 common.sh 源码,我发现了 check_dockercompose 函数的真实逻辑。它设计得非常健壮:
这意味着,尽管脚本的 install.sh 文件中可能有一个 V1 的默认值,但它在运行时,是真真正正地使用了我系统中的 V2 插件来完成所有后续操作。这确保了脚本对新旧环境的强大兼容性。
[Step 2 & 3] 环境与配置准备 ⚙️:脚本拉取了一个名为 goharbor/prepare 的工具镜像。这个镜像是 Harbor 安装的“瑞士军刀”,它读取我的 harbor.yml,然后动态生成了所有服务(Nginx, Core, Registry, DB…)所需的配置文件,以及最终的 docker-compose.yml。
- 一个重要的警告出现了:WARNING:root:WARNING: HTTP protocol is insecure.。这正是我预料到的,因为它检测到我禁用了 HTTPS。对于测试环境,我可以接受这个风险。
[Step 4] 启动 Harbor 🚀:
- 拉取镜像: 脚本开始从 Docker Hub 拉取 Harbor 运行所需的所有服务镜像。redis, registryctl, proxy, postgresql… 看着一个个 Pulled 完成,非常有成就感。
- 启动容器: 镜像准备就绪后,脚本使用 docker compose 启动了所有服务。harbor-log, redis, harbor-db… 十个容器相继 Started。
最终的礼炮 🎉:
屏幕上打印出了那句最令人期待的话:
✔ —-Harbor has been installed and started successfully.—-
成功了!整个过程自动化程度非常高,我需要做的只是修改一份配置文件。
四、 验证与展望 🔭
我现在可以通过浏览器访问 http://192.168.31.73:81,使用 admin 和我设置的密码 Harbor12345 登录我的私有镜像仓库了。
接下来,我就可以为我的 hx-health-cloud 项目创建私有项目,并将 hx-auth, hx-gateway 等服务的镜像推送到这里,实现开发、测试流程的闭环。
这次部署经历非常顺畅,Harbor 的自动化安装脚本做得非常出色。它再次证明了,选择一个优秀的、社区成熟的开源项目,能极大地提升我们的工作效率。
总结与图表分析
表格总结
| 准备阶段 | 登录服务器 & 安装 jq | ssh, sudo apt install -y jq | ✅ jq 安装成功 | jq 是自动化脚本的关键依赖 |
| 第一步 | 自动下载并解压最新版 | curl, jq, wget, tar | ✅ harbor 目录及安装文件就绪 | 实现了版本解耦,无需手动查找 |
| 第二步 | 个性化配置 | cp, nano harbor.yml | ✅ harbor.yml 配置完成 | 关键:修改 hostname 和密码 |
| 第三步 | 执行安装 | sudo ./install.sh | ✅ 所有 Harbor 容器成功启动 | 脚本自动化了所有复杂操作 |
| 验证阶段 | 访问 UI & 推送镜像 | 浏览器, docker login/push | ✅ 成功登录并推送镜像 | 证明整个仓库功能正常 |
Mermaid 流程图:Harbor 部署之路
#mermaid-svg-BnJ8rn8CAu5J8T6k {font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:14px;fill:#2C3E50;}#mermaid-svg-BnJ8rn8CAu5J8T6k .error-icon{fill:hsl(348.1481481481, 75.7009345794%, 46.9607843137%);}#mermaid-svg-BnJ8rn8CAu5J8T6k .error-text{fill:rgb(44.5981308413, 225.9018691588, 190.0887850466);stroke:rgb(44.5981308413, 225.9018691588, 190.0887850466);}#mermaid-svg-BnJ8rn8CAu5J8T6k .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-BnJ8rn8CAu5J8T6k .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BnJ8rn8CAu5J8T6k .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BnJ8rn8CAu5J8T6k .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BnJ8rn8CAu5J8T6k .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BnJ8rn8CAu5J8T6k .marker{fill:#7F8C8D;stroke:#7F8C8D;}#mermaid-svg-BnJ8rn8CAu5J8T6k .marker.cross{stroke:#7F8C8D;}#mermaid-svg-BnJ8rn8CAu5J8T6k svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:14px;}#mermaid-svg-BnJ8rn8CAu5J8T6k .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-BnJ8rn8CAu5J8T6k .cluster-label text{fill:rgb(44.5981308413, 225.9018691588, 190.0887850466);}#mermaid-svg-BnJ8rn8CAu5J8T6k .cluster-label span{color:rgb(44.5981308413, 225.9018691588, 190.0887850466);}#mermaid-svg-BnJ8rn8CAu5J8T6k .label text,#mermaid-svg-BnJ8rn8CAu5J8T6k span{fill:#fff;color:#fff;}#mermaid-svg-BnJ8rn8CAu5J8T6k .node rect,#mermaid-svg-BnJ8rn8CAu5J8T6k .node circle,#mermaid-svg-BnJ8rn8CAu5J8T6k .node ellipse,#mermaid-svg-BnJ8rn8CAu5J8T6k .node polygon,#mermaid-svg-BnJ8rn8CAu5J8T6k .node path{fill:#1ABC9C;stroke:hsl(168.1481481481, 35.7009345794%, 31.9607843137%);stroke-width:1px;}#mermaid-svg-BnJ8rn8CAu5J8T6k .node .label{text-align:center;}#mermaid-svg-BnJ8rn8CAu5J8T6k .node.clickable{cursor:pointer;}#mermaid-svg-BnJ8rn8CAu5J8T6k .arrowheadPath{fill:undefined;}#mermaid-svg-BnJ8rn8CAu5J8T6k .edgePath .path{stroke:#7F8C8D;stroke-width:2.0px;}#mermaid-svg-BnJ8rn8CAu5J8T6k .flowchart-link{stroke:#7F8C8D;fill:none;}#mermaid-svg-BnJ8rn8CAu5J8T6k .edgeLabel{background-color:hsl(48.1481481481, 75.7009345794%, 41.9607843137%);text-align:center;}#mermaid-svg-BnJ8rn8CAu5J8T6k .edgeLabel rect{opacity:0.5;background-color:hsl(48.1481481481, 75.7009345794%, 41.9607843137%);fill:hsl(48.1481481481, 75.7009345794%, 41.9607843137%);}#mermaid-svg-BnJ8rn8CAu5J8T6k .cluster rect{fill:hsl(348.1481481481, 75.7009345794%, 46.9607843137%);stroke:hsl(348.1481481481, 35.7009345794%, 36.9607843137%);stroke-width:1px;}#mermaid-svg-BnJ8rn8CAu5J8T6k .cluster text{fill:rgb(44.5981308413, 225.9018691588, 190.0887850466);}#mermaid-svg-BnJ8rn8CAu5J8T6k .cluster span{color:rgb(44.5981308413, 225.9018691588, 190.0887850466);}#mermaid-svg-BnJ8rn8CAu5J8T6k div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(348.1481481481, 75.7009345794%, 46.9607843137%);border:1px solid undefined;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BnJ8rn8CAu5J8T6k :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-BnJ8rn8CAu5J8T6k .start>*{fill:#58D68D!important;stroke:#28B463!important;stroke-width:2px!important;}#mermaid-svg-BnJ8rn8CAu5J8T6k .start span{fill:#58D68D!important;stroke:#28B463!important;stroke-width:2px!important;}#mermaid-svg-BnJ8rn8CAu5J8T6k .process>*{fill:#85C1E9!important;stroke:#3498DB!important;stroke-width:2px!important;}#mermaid-svg-BnJ8rn8CAu5J8T6k .process span{fill:#85C1E9!important;stroke:#3498DB!important;stroke-width:2px!important;}#mermaid-svg-BnJ8rn8CAu5J8T6k .decision>*{fill:#F39C12!important;stroke:#D35400!important;stroke-width:2px!important;}#mermaid-svg-BnJ8rn8CAu5J8T6k .decision span{fill:#F39C12!important;stroke:#D35400!important;stroke-width:2px!important;}#mermaid-svg-BnJ8rn8CAu5J8T6k .success>*{fill:#58D68D!important;stroke:#28B463!important;stroke-width:2px!important;}#mermaid-svg-BnJ8rn8CAu5J8T6k .success span{fill:#58D68D!important;stroke:#28B463!important;stroke-width:2px!important;}#mermaid-svg-BnJ8rn8CAu5J8T6k .failure>*{fill:#E74C3C!important;stroke:#C0392B!important;stroke-width:2px!important;color:white!important;}#mermaid-svg-BnJ8rn8CAu5J8T6k .failure span{fill:#E74C3C!important;stroke:#C0392B!important;stroke-width:2px!important;color:white!important;}是是否否开始: 准备服务器安装依赖 'jq'运行自动化脚本下载Harbor下载并解压成功?进入 'harbor' 目录配置 'harbor.yml' 文件运行 'install.sh' 脚本所有容器启动成功?通过浏览器访问UI登录并推送镜像进行验证部署成功 🎉检查网络或脚本错误检查Docker或配置错误
Sequence Diagram: install.sh 脚本的内部工作流
#mermaid-svg-vyvCqJpAfTBWzwPp {font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-vyvCqJpAfTBWzwPp .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-vyvCqJpAfTBWzwPp .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-vyvCqJpAfTBWzwPp .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-vyvCqJpAfTBWzwPp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vyvCqJpAfTBWzwPp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vyvCqJpAfTBWzwPp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vyvCqJpAfTBWzwPp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vyvCqJpAfTBWzwPp .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-vyvCqJpAfTBWzwPp .marker.cross{stroke:#0b0b0b;}#mermaid-svg-vyvCqJpAfTBWzwPp svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vyvCqJpAfTBWzwPp .actor{stroke:#5DADE2;fill:#AED6F1;}#mermaid-svg-vyvCqJpAfTBWzwPp text.actor>tspan{fill:#333;stroke:none;}#mermaid-svg-vyvCqJpAfTBWzwPp .actor-line{stroke:grey;}#mermaid-svg-vyvCqJpAfTBWzwPp .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-vyvCqJpAfTBWzwPp .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-vyvCqJpAfTBWzwPp #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-vyvCqJpAfTBWzwPp .sequenceNumber{fill:#f4f4f4;}#mermaid-svg-vyvCqJpAfTBWzwPp #sequencenumber{fill:#333;}#mermaid-svg-vyvCqJpAfTBWzwPp #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-vyvCqJpAfTBWzwPp .messageText{fill:#333;stroke:#333;}#mermaid-svg-vyvCqJpAfTBWzwPp .labelBox{stroke:#5DADE2;fill:#AED6F1;}#mermaid-svg-vyvCqJpAfTBWzwPp .labelText,#mermaid-svg-vyvCqJpAfTBWzwPp .labelText>tspan{fill:#333;stroke:none;}#mermaid-svg-vyvCqJpAfTBWzwPp .loopText,#mermaid-svg-vyvCqJpAfTBWzwPp .loopText>tspan{fill:#333;stroke:none;}#mermaid-svg-vyvCqJpAfTBWzwPp .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:#5DADE2;fill:#5DADE2;}#mermaid-svg-vyvCqJpAfTBWzwPp .note{stroke:hsl(52.6829268293, 60%, 73.9215686275%);fill:#fff5ad;}#mermaid-svg-vyvCqJpAfTBWzwPp .noteText,#mermaid-svg-vyvCqJpAfTBWzwPp .noteText>tspan{fill:#333;stroke:none;}#mermaid-svg-vyvCqJpAfTBWzwPp .activation0{fill:hsl(-79.4117647059, 100%, 93.3333333333%);stroke:hsl(-79.4117647059, 100%, 83.3333333333%);}#mermaid-svg-vyvCqJpAfTBWzwPp .activation1{fill:hsl(-79.4117647059, 100%, 93.3333333333%);stroke:hsl(-79.4117647059, 100%, 83.3333333333%);}#mermaid-svg-vyvCqJpAfTBWzwPp .activation2{fill:hsl(-79.4117647059, 100%, 93.3333333333%);stroke:hsl(-79.4117647059, 100%, 83.3333333333%);}#mermaid-svg-vyvCqJpAfTBWzwPp .actorPopupMenu{position:absolute;}#mermaid-svg-vyvCqJpAfTBWzwPp .actorPopupMenuPanel{position:absolute;fill:#AED6F1;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-vyvCqJpAfTBWzwPp .actor-man line{stroke:#5DADE2;fill:#AED6F1;}#mermaid-svg-vyvCqJpAfTBWzwPp .actor-man circle,#mermaid-svg-vyvCqJpAfTBWzwPp line{stroke:#5DADE2;fill:#AED6F1;stroke-width:2px;}#mermaid-svg-vyvCqJpAfTBWzwPp :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}用户"安装脚本""goharbor/prepare""Docker Compose"sudo ./install.sh检查环境 (Docker, Compose)拉取并运行读取 harbor.yml, 生成所有配置文件返回生成的配置调用 'docker compose up -d'拉取所有服务镜像创建并启动所有容器返回启动成功信息显示 "Harbor installed successfully"用户"安装脚本""goharbor/prepare""Docker Compose"
State Diagram: Harbor 服务的状态
#mermaid-svg-Pez8C35d3TqnqIoS {font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Pez8C35d3TqnqIoS .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-Pez8C35d3TqnqIoS .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-Pez8C35d3TqnqIoS .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-Pez8C35d3TqnqIoS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Pez8C35d3TqnqIoS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Pez8C35d3TqnqIoS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Pez8C35d3TqnqIoS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Pez8C35d3TqnqIoS .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-Pez8C35d3TqnqIoS .marker.cross{stroke:#0b0b0b;}#mermaid-svg-Pez8C35d3TqnqIoS svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Pez8C35d3TqnqIoS defs #statediagram-barbEnd{fill:#5D6D7E;stroke:#5D6D7E;}#mermaid-svg-Pez8C35d3TqnqIoS g.stateGroup text{fill:hsl(40.5882352941, 60%, 83.3333333333%);stroke:none;font-size:10px;}#mermaid-svg-Pez8C35d3TqnqIoS g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-Pez8C35d3TqnqIoS g.stateGroup .state-title{font-weight:bolder;fill:#333;}#mermaid-svg-Pez8C35d3TqnqIoS g.stateGroup rect{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);}#mermaid-svg-Pez8C35d3TqnqIoS g.stateGroup line{stroke:#0b0b0b;stroke-width:1;}#mermaid-svg-Pez8C35d3TqnqIoS .transition{stroke:#5D6D7E;stroke-width:1;fill:none;}#mermaid-svg-Pez8C35d3TqnqIoS .stateGroup .composit{fill:#f4f4f4;border-bottom:1px;}#mermaid-svg-Pez8C35d3TqnqIoS .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-Pez8C35d3TqnqIoS .state-note{stroke:hsl(52.6829268293, 60%, 73.9215686275%);fill:#fff5ad;}#mermaid-svg-Pez8C35d3TqnqIoS .state-note text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-Pez8C35d3TqnqIoS .stateLabel .box{stroke:none;stroke-width:0;fill:#fff4dd;opacity:0.5;}#mermaid-svg-Pez8C35d3TqnqIoS .edgeLabel .label rect{fill:#fff4dd;opacity:0.5;}#mermaid-svg-Pez8C35d3TqnqIoS .edgeLabel .label text{fill:#333;}#mermaid-svg-Pez8C35d3TqnqIoS .label div .edgeLabel{color:#333;}#mermaid-svg-Pez8C35d3TqnqIoS .stateLabel text{fill:#333;font-size:10px;font-weight:bold;}#mermaid-svg-Pez8C35d3TqnqIoS .node circle.state-start{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-Pez8C35d3TqnqIoS .node .fork-join{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-Pez8C35d3TqnqIoS .node circle.state-end{fill:hsl(40.5882352941, 60%, 83.3333333333%);stroke:#f4f4f4;stroke-width:1.5;}#mermaid-svg-Pez8C35d3TqnqIoS .end-state-inner{fill:#f4f4f4;stroke-width:1.5;}#mermaid-svg-Pez8C35d3TqnqIoS .node rect{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);stroke-width:1px;}#mermaid-svg-Pez8C35d3TqnqIoS .node polygon{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);stroke-width:1px;}#mermaid-svg-Pez8C35d3TqnqIoS #statediagram-barbEnd{fill:#0b0b0b;}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram-cluster rect{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);stroke-width:1px;}#mermaid-svg-Pez8C35d3TqnqIoS .cluster-label,#mermaid-svg-Pez8C35d3TqnqIoS .nodeLabel{color:#333;}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram-state .divider{stroke:hsl(40.5882352941, 60%, 83.3333333333%);}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram-cluster.statediagram-cluster .inner{fill:#f4f4f4;}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram-cluster.statediagram-cluster-alt .inner{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram-state rect.divider{stroke-dasharray:10,10;fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-Pez8C35d3TqnqIoS .note-edge{stroke-dasharray:5;}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram-note rect{fill:#fff5ad;stroke:hsl(52.6829268293, 60%, 73.9215686275%);stroke-width:1px;rx:0;ry:0;}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram-note rect{fill:#fff5ad;stroke:hsl(52.6829268293, 60%, 73.9215686275%);stroke-width:1px;rx:0;ry:0;}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram-note text{fill:#333;}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram-note .nodeLabel{color:#333;}#mermaid-svg-Pez8C35d3TqnqIoS .statediagram .edgeLabel{color:red;}#mermaid-svg-Pez8C35d3TqnqIoS #dependencyStart,#mermaid-svg-Pez8C35d3TqnqIoS #dependencyEnd{fill:#0b0b0b;stroke:#0b0b0b;stroke-width:1;}#mermaid-svg-Pez8C35d3TqnqIoS :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}执行 install.sh所有容器启动成功执行 docker compose down执行 docker compose up日常使用卸载未安装安装中运行中已停止
Class Diagram: Harbor 核心组件简化关系

Entity Relationship Diagram: Harbor 核心数据实体
#mermaid-svg-KLEwK75SRIxgMCto {font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-KLEwK75SRIxgMCto .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-KLEwK75SRIxgMCto .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-KLEwK75SRIxgMCto .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-KLEwK75SRIxgMCto .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KLEwK75SRIxgMCto .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KLEwK75SRIxgMCto .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KLEwK75SRIxgMCto .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KLEwK75SRIxgMCto .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-KLEwK75SRIxgMCto .marker.cross{stroke:#0b0b0b;}#mermaid-svg-KLEwK75SRIxgMCto svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KLEwK75SRIxgMCto .entityBox{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);}#mermaid-svg-KLEwK75SRIxgMCto .attributeBoxOdd{fill:#ffffff;stroke:hsl(40.5882352941, 60%, 83.3333333333%);}#mermaid-svg-KLEwK75SRIxgMCto .attributeBoxEven{fill:#f2f2f2;stroke:hsl(40.5882352941, 60%, 83.3333333333%);}#mermaid-svg-KLEwK75SRIxgMCto .relationshipLabelBox{fill:hsl(220.5882352941, 100%, 98.3333333333%);opacity:0.7;background-color:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-KLEwK75SRIxgMCto .relationshipLabelBox rect{opacity:0.5;}#mermaid-svg-KLEwK75SRIxgMCto .relationshipLine{stroke:#0b0b0b;}#mermaid-svg-KLEwK75SRIxgMCto :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}PROJECTintproject_idPKstringnameboolis_publicREPOSITORYintrepo_idPKintproject_idFKstringnameARTIFACTintartifact_idPKintrepo_idFKstringtagstringdigestUSER包含包含管理
思维导图 (Markdown 格式)
- Harbor 私有镜像仓库部署实战
- 一、 准备阶段 🛠️
- 服务器: Ubuntu 22.04 LTS, IP: 192.168.31.73
- 登录: 通过 SSH 成功登录
- 安装依赖: 使用 apt 安装 jq 工具
- 二、 核心部署步骤 🎨
- 1. 自动化下载 (第一步)
- 方式: 使用包含 curl 和 jq 的 Shell 脚本
- 目的: 自动获取 GitHub 最新稳定版的 online-installer
- 结果: 成功下载并解压 harbor-online-installer-v2.14.0.tgz
- 2. 个性化配置 (第二步)
- 文件: harbor.yml (由 harbor.yml.tmpl 复制而来)
- 编辑器: 使用 nano (因为 vim 未预装)
- 关键修改:
- hostname: 192.168.31.73 (使用 IP)
- http.port: 81 (避免端口冲突)
- https: 注释掉 (测试环境简化)
- harbor_admin_password: Harbor12345
- database.password: root123
- 3. 执行安装 (第三步)
- 命令: sudo ./install.sh
- 过程:
- 环境检查 (Docker 28.4.0, Docker Compose v2.40.0)
- 配置准备 (使用 goharbor/prepare 镜像)
- 启动服务 (拉取所有镜像并用 docker compose up 启动)
- 1. 自动化下载 (第一步)
- 一、 准备阶段 🛠️
- 结果: 终端显示 Harbor has been installed and started successfully
- 访问: 浏览器打开 http://192.168.31.73:81
- 登录: 用户名 admin,密码 Harbor12345
- 后续操作:
- 创建项目 (如 hx-health-cloud)
- docker login
- docker push 推送业务镜像
- 自动化脚本 极大简化了下载流程
- harbor.yml 是唯一需要手动配置的核心
- install.sh 封装了所有复杂性,实现了“一键部署”




