ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

离线环境部署实践:GitHub私有仓库到内网Harbor/Nexus的完整链路

离线环境部署实践:GitHub私有仓库到内网Harbor/Nexus的完整链路 GitHub 上的代码还静静地躺在私有仓库里目标服务器却在隔离网络环境中上面连一个依赖包都没有。最要命的是这次的交付不是一台机器而是好几台 ARM 设备架构还不一样。我当时的第一个想法是完蛋这怎么搞第二个想法是既然没有网络那就自己做一个仓库中转站。于是就有了这份实践记录。它既包含了 GitHub 私有仓库侧的代码和制品准备也包含了用 Harbor 承接容器镜像、用 Nexus 承接 tar.gz 和二进制包、最后在内网完成部署的完整链路。这篇东西不是官方文档的复述而是我从零到一跑通之后留下的笔记适合正在做私有化项目交付、离线环境部署、或者需要把外部开源组件系统性地搬进企业内网的运维和开发朋友参考。即便你的目标不是 ARM 设备链路中的大部分环节同样可以直接照搬。1. 为什么我把 GitHub 私有仓库当成部署链路的起点先交代一下背景。我这次要交付的是一个边缘计算相关项目代码托管在 GitHub 私有仓库里编译产物、模型权重、运行环境镜像分散在不同位置。目标机器是 RK3588 开发板部署 YOLOv8 推理服务现场环境完全隔离除了带着一台笔记本进现场没有任何外网能力。刚开始我很自然地想直接把代码打包带过去不就行了但很快就发现事情没那么简单。1.1 这一轮部署面临的真实约束首先代码本身有依赖。YOLOv8 从 Python 侧有 ultralytics 包、opencv、torch从部署侧有 ONNX Runtime、rknn-toolkit2 这类工具链这些依赖散落在 GitHub、PyPI、Release 附件里光靠 git clone 一次根本带不全。其次硬件平台特殊。RK3588 是 ARM 架构有些组件在 PC 上装好了没用必须在目标机上跑。你不可能指望现场慢慢编译因为交叉编译工具链、系统依赖库、Python wheel 包都得提前准备好。更麻烦的是团队协作。代码不止我一个人在动分支、tag、发行说明都在 GitHub 私有仓库里维护。我如果只带一份代码拷贝进现场回头升级、补 bug、同步变更会变得非常痛苦。所以必须建立一个可复用的机制GitHub 私有仓库作为源头内网私有仓库作为中转目标机器从内网仓库拉取物料完成部署。1.2 部署链路的三个角色与三种搬运模式整条链路可以拆成三个角色对应三种不同的搬运需求角色承载内容对应工具搬运模式源头仓库源码、文档、构建脚本GitHub 私有仓库代码快照 / 增量同步制品中转容器镜像Harbor私有镜像仓库公网拉取后转存 Harbor制品中转tar.gz、wheel 包、二进制NexusRaw 仓库直接上传 / 脚本自动同步代码属于高频变动内容适合用 git 协议本身来处理哪怕离线也有git bundle这种稳妥方案。容器镜像则必须依赖 Docker Registry 协议Harbor 是最好用也最稳的选择。tar.gz 这类静态制品扔到 Nexus 的 Raw 仓库里管理最直观因为它的生命周期和版本完全由你自己定义。1.3 整体流程设计从源头到内网的一次完整通路我在动手之前先画了一张执行顺序图不用任何工具就是纸笔整个流程分成四步GitHub 私有仓库侧完成代码、令牌、Release 产物、Actions 流水线的准备。在外网跳板机或者你笔记本上把需要的东西拉下来转存到内网私有仓库。目标环境登录内网 Harbor 和 Nexus按部署脚本拉取对应版本。在目标机器上完成安装和验证。后面所有章节基本就是按这四步展开的。如果你觉得我只需要其中某一段可以直接跳到对应章节每段都独立成篇。2. GitHub 私有仓库侧的准备工作代码、令牌与 Release 产物很多人一提到 GitHub 私有仓库第一反应就是建立仓库、把代码推上去、加了权限就行。但作为部署链路的源头私有仓库要承担的东西比这多得多。它不仅要保证代码能溯源还要保证制品有稳定的下载入口、权限边界清晰甚至要为后续的自动化流转提供接口。2.1 创建私有仓库时的几个参数选择新建仓库时大多数人只关心 Public / Private 的选择但实际上这里埋了不少决策点。仓库名和描述建议带统一前缀比如edge-yolov8-inference描述里写明硬件平台RK3588和用途。这会在你维护多个仓库时省下大量记忆成本。初始化选项README、.gitignore建议勾上尤其.gitignore对 Python 项目很重要可以避免把weights/、venv/、__pycache__这些大目录推上来。License 先不选企业私有项目通常在法务确认后才补省得后面改来改去。默认分支直接设为main不要再用master和现代工具链的默认值保持一致也少一点无意义的转换操作。2.2 Personal Access Token 的粒度与安全边界私有仓库的 CI/CD 和脚本不能每次都用密码交互式登录。这里需要 Personal Access TokenPAT而选择 PAT 类型时必须想清楚它会被用到什么场景。我这次用了 fine-grained token而不是传统的 classic token原因很简单fine-grained token 可以精确到某个仓库、某几项权限即使泄露了影响面也控制在一个很小的范围内。针对这次部署我申请的权限是Contents读取代码内容方便脚本拉取指定 tag。Packages读取 GitHub Container Registry 的镜像。Metadata默认必需的最小权限。Administration只读查看 release 状态用于确认制品是否打好。有效期我设了 90 天因为这是一个阶段性交付项目。如果你做长期维护建议考虑用 GitHub App 的安装令牌它有自动轮换机制比 PAT 更安全。另外PAT 我从未放进代码里也没有写进部署脚本而是存放在密码管理器中内网环境里需要用到时由跳板机上的运维小号统一管理这个后面会专门说。2.3 用 Release 和 Package 功能固化部署制品私有仓库里最容易被忽略的功能就是 Release。我强烈建议所有部署相关的产物都通过 GitHub Actions 自动构建后上传到对应仓库的 Release 页面而不是手动用scp或者网盘传来传去。原因有两个。第一Release 自带版本和完整性概念你发布一个v1.2.0附件就是明确的yolov8s_rk3588_v1.2.0.tar.gz不会出现那个最终版本到底在哪个文件夹里的混乱。第二Release 的下载链接是稳定 URL内网同步脚本可以直接通过 API 解析最新版下载完全不需要人工介入。我这次在 Actions 里写了三步式流水线先在 x86 的 runner 上完成基础构建再把产物上传到 Release最后执行一个同步任务把必要的 wheel 包推到 Nexus。GitHub Container Registryghcr.io我也用起来了比如ghcr.io/your-org/edge-yolov8-api:v1.2.0这样的镜像地址后续可以直接转到 Harbor。2.4 分支保护与 Actions Secrets 配置部署项目的特殊性在于main分支往往直接对应可发布状态如果谁都能往上推很容易把半成品带进交付现场。我在仓库设置里开启了分支保护规则核心是两条要求 Pull Request 通过后再合并、禁止直接推送main。这套规则在团队里运行了一个月效果立竿见影——至少不会有人再把调试用的临时文件混进主线。Actions Secrets 配置同样要重视。Nexus 的用户名密码、Harbor 的登录令牌、以及内网仓库地址都放进了 Secrets 而不是写死在 workflow 文件里。这样做的好处是即使仓库被 fork 或者某个开发者误公开机密信息也不会跟着流出去。3. 把代码搬进隔离网络git bundle 与中转仓库的组合打法代码是所有部署链路里最活的部分它不像镜像那样打包就定型也不像 tar.gz 那样一次成型。我这次需要的代码包括推理服务源码、rknn-toolkit2 的 Python 绑定、以及几个配置仓库。把它们从 GitHub 私有仓库搬到隔离网络我用的是git bundle加内网裸仓库的组合方案。3.1 直接 git clone 到跳板机的现实困境可能有人会觉得先在一台能访问 GitHub 的跳板机上git clone然后scp整个目录进去不就行了实际操作时你会发现两个问题。一是仓库里往往有 Git LFS 文件或者体积不小的二进制资源直接在公网上 clone 会非常慢而且一旦中间网络抖动整个 clone 进程很容易失败没有断点继续的能力。二是你 scp 过去的目录是带了.git的完整工作副本到了内网之后很难再跟源仓库做增量同步做不到改一行代码同步一个 commit的轻量更新。3.2 git bundle一个完整到不能再完整的离线快照git bundle可以把整个仓库的历史、分支、标签打包成单个文件。它比直接打包.git目录更规范因为它本质上是一个只读的 Git 传输表示接收方可以像对待远程仓库一样对待这个 bundle 文件。我当时的操作是这样的# 在能访问 GitHub 的机器上 git clone --bare https://github.com/your-org/edge-yolov8-inference.git cd edge-yolov8-inference.git git bundle create edge-yolov8-inference.bundle --all # 验证 bundle 文件完整性 git bundle verify edge-yolov8-inference.bundle这里我用的是--bare克隆生成的是纯 Git 数据库没有工作目录所以 bundle 文件会小一些也避免把临时文件、未跟踪文件一并带进去。--all会把所有分支和 tag 都打进 bundle交付现场如果需要某个历史版本也能随时取出来。3.3 内网目标环境如何接收和推送把 bundle 文件带进内网之后我建议先建一个裸仓库作为内网权威源而不是直接在目标机器上还原工作副本。原因很简单多台设备要从同一个源拉代码内网总得有一个服务端角色。# 内网服务器上 mkdir /srv/git/edge-yolov8-inference.git cd /srv/git/edge-yolov8-inference.git git init --bare # 从 bundle 文件导入完整历史 git fetch /path/to/edge-yolov8-inference.bundle refs/heads/*:refs/heads/* git fetch /path/to/edge-yolov8-inference.bundle refs/tags/*:refs/tags/*执行完后内网服务器就有了一个完整的 Git 仓库目标机器再从这个本地仓库拉代码git clone ssh://gitinternal-server/srv/git/edge-yolov8-inference.git这里需要说明一下当前内网服务器可能没有 Git 服务端软件比如 Gitea、GitLab直接用git init --bare配合 SSH 就能跑起来SSH 权限通过系统用户的 authorized_keys 来控制。对团队协作要求高的场景再上 Gitea 或 GitLab 不迟。3.4 后续增量更新避免全量 bundle 的笨办法第一次全量 bundle 没问题但每次小改都重新打一个几百 MB 的 bundle 就太蠢了。我后来改用git fetch加git push的方式做增量同步。流程是这样的外网机器上保留一个镜像仓库定期执行git fetch origin --prune git push internal --prune --tags这里internal是内网裸仓库的 SSH remote。--prune会删除远端已经不存在的分支引用防止内网仓库留下过期分支。需要注意git push internal --prune --tags会强制推送所有分支到对应 inner bare 仓库适合内网权威源完全跟随外网仓库的场景。如果内网仓库同时还有本地自定义分支就不能这么干否则会把别人推上去的东西冲掉。增量同步我建议做成定时任务比如每 30 分钟跑一次。对于私有项目交付同步频率别太高避免频繁推送导致内网仓库 refs 膨胀。4. 部署私有镜像仓库为什么选 Harbor以及那套让人头痛的证书代码搬过去了接下来处理容器镜像。YOLOv8 的推理服务我封装成了 Docker 镜像里面包括推理 API、依赖库甚至模型转换工具链。外网环境里一般直接docker pull官方镜像或ghcr.io里的私有镜像就行但隔离网络里必须有中转站。4.1 为什么不用裸 Docker Registry 而非要用 Harbor第一反应是搭一个 Docker Registry 不就行了确实裸 registry 也能用但如果一个人用还好一旦多人多团队用痛点立刻出现没有 Web 界面查一个镜像 tag 存在与否都要敲 API。没有 Project 级权限所有人默认是管理员很容易误删镜像。没有镜像清理和回收机制时间长了磁盘会被旧 tag 撑爆。没有镜像复制功能从一个 Harbor 到另一个 Harbor 的跨环境同步得自己写脚本。Harbor 把这些都做成开箱即用的功能。我用的是 v2.x 离线安装包部署在离目标环境最近的服务器上选择离线包是因为现场没有外网需要一次性把 Harbor 本身的镜像和依赖全部带进去。4.2 Harbor 离线安装与配置细节离线包解开后核心工作就是改harbor.yml。我遇到的关键配置项有三个。hostname建议直接用内网 IP 或者内网 DNS 名不要用 localhost否则目标机 pull 镜像时会解析到自身。harbor_admin_password必须改掉默认值而且要足够长因为 Harbor 是内网制品的核心入口一旦被爆破整个部署物料就暴露了。这里有个非常容易踩的坑Harbor 默认会启用 HTTPS。如果只在内网用我们可以配置自签名证书但目标机器很多每台都要信任证书会很痛苦。我的做法是在内网 DNS 上给 Harbor 分配一个稳定域名然后用内网 CA 签发一张证书各目标机把这个 CA 加入系统信任列表。如果你完全不想搞证书体系Harbor 也支持 HTTP 部署只需要在harbor.yml里把https段落注释掉同时目标机的 Docker daemon 配置里加上insecure-registries。我这次为了减少现场踩坑最终走了 HTTP 加内网白名单的方案后面会说怎么配置。安装过程本身不复杂sudo ./install.sh但安装前的磁盘空间检查一定要做。Harbor 用的 PostgreSQL、Registry、Redis 组件加起来至少需要 20GB 空闲空间如果/data分区不够后面镜像转存跑到一半罢工你会非常被动。建议在安装前执行docker info确认存储驱动和剩余空间。4.3 用 Project 和机器人账号做环境隔离Harbor 里最值得花心思的是 Project 设计。我按目标环境拆分了 project比如rk3588-prod、rk3588-staging每个 project 单独分配允许拉取的机器人账号。这样即使某个环境的凭据泄露攻击者也只能拿到对应环境的镜像不能把别的环境也扫一遍。机器人账号的权限只勾选拉取Pull不勾推送到任意 project 的权限。真正推送镜像的操作交给一个独立的 CI 账号或者管理员账号。这个习惯看起来繁琐但在多环境交付场景里能避免非常尴尬的测试镜像被推到生产仓库事故。4.4 外网镜像转存 Harbor 的标准操作镜像转存是每次部署前都要做的事不可手工docker tagdocker push一个一个来我把它写成了脚本。假设需要从 ghcr.io 拉取官方镜像并同步到 Harbor#!/usr/bin/env bash set -euo pipefail SRC_IMAGEghcr.io/your-org/edge-yolov8-api:v1.2.0 DST_HARBORharbor.internal.example.com DST_PROJECTrk3588-prod docker pull $SRC_IMAGE docker tag $SRC_IMAGE $DST_HARBOR/$DST_PROJECT/edge-yolov8-api:v1.2.0 docker login $DST_HARBOR -u $HARBOR_USER -p $HARBOR_PASS docker push $DST_HARBOR/$DST_PROJECT/edge-yolov8-api:v1.2.0这套命令在离网现场同样适用只是把ghcr.io换成内网 Harbor 地址而已。需要注意docker tag时 tag 一定是不可变版本号比如v1.2.0千万别用latest否则你会面临昨天明明部署成功了今天 pull 下来却不是同一个镜像的诡异问题。如果你的镜像数量很大或者本机 Docker daemon 磁盘紧张可以用skopeo直接完成跨仓库复制不用在本地落盘skopeo copy docker://ghcr.io/your-org/edge-yolov8-api:v1.2.0 docker://harbor.internal.example.com/rk3588-prod/edge-yolov8-api:v1.2.0 --dest-creds $HARBOR_USER:$HARBOR_PASS我实测下来这一招对转存大量镜像特别省事速度也快因为少了 docker daemon 这一层。5. tar.gz 和二进制制品的私有化存放Nexus Raw 仓库实战模型权重、RKNN 转换工具链、Python wheel 包、一键部署脚本这些既不是代码也不是镜像但它们同样是部署链路里不可或缺的制品。GitHub 的 Release 适合承载但隔离网络里必须有一个可以反复拉取的内网位置。我选了 Nexus Repository 的 Raw 仓库。5.1 为什么不用 Git LFS 或者直接扔对象存储Git LFS 是一个方案但免费额度很小企业自建 Git 服务虽然在带宽和存储上可控LFS 却会让git clone变慢而且在目标机器上每次拉取大文件都会卡很久。对象存储如 MinIO也可以但用它管理软件包时版本元数据、命名规范、依赖关系都得自己造轮子对交付项目来说太重了。Nexus 的 Raw 仓库本质是一个带 REST API 的通用文件托管服务。你可以把它理解成内网的简单对象存储 版本化目录用 curl 就能上传下载脚本集成非常方便。5.2 创建 Raw 仓库和上传命令Nexus 安装后在后台创建一个 Raw 仓库名字我建议带环境上下文比如edge-artifacts-prod部署时 Blob Store 单独指向一个数据盘。仓库创建好后上传一个 tar.gz 非常直接curl -u $NEXUS_USER:$NEXUS_PASS \ --upload-file yolov8s_rk3588_v1.2.0.tar.gz \ https://nexus.internal.example.com/repository/edge-artifacts-prod/yolov8/yolov8s_rk3588_v1.2.0.tar.gz注意我在这里用了版本路径v1.2.0而且在仓库里建了yolov8/子目录。Nexus Raw 仓库的路径规则完全由你决定但强烈建议按组件名/版本/文件名三层组织这样后期写批量同步脚本时能直接用版本号正则匹配。5.3 KubeKey 场景把 tar.gz 推到私有仓库再部署这次部署还有一个绕不开的场景目标机器的 AI 推理环境需要先装一套容器运行时和 Kubernetes 工具链我参考了 KubeKey 的离线部署思路。KubeKey 本身有一个很关键的问题官方默认从 GitHub Release 下载所需的kubekey-bin等 tar.gz 包离线环境根本拉不到。我的做法是分两步。第一步在外网机器上用curl -L把 GitHub Release 里所有需要的 tar.gz 拉到本地第二步写一个循环脚本按 KubeKey 的目录结构全部推到 Nexus Raw 仓库。比如curl -u $NEXUS_USER:$NEXUS_PASS \ --upload-file kubekey-bin-v3.0.0-linux-amd64.tar.gz \ https://nexus.internal.example.com/repository/edge-artifacts-prod/kubekey/kubekey-bin-v3.0.0-linux-amd64.tar.gz然后在内网目标机器安装时把安装命令里的下载 URL 替换成 Nexus 地址或者预先下载到本地目录再执行安装。这样 KubeKey 在离网状态下一步一步校验哈希、解压、部署完全不会卡在 GitHub 连接那一步。5.4 部署脚本里的 URL 替换策略制品一旦进了 Nexus内网部署脚本就可以统一走从仓库拉取的逻辑。我在所有部署脚本里维护了一个变量文件例如ARTIFACT_BASEhttps://nexus.internal.example.com/repository/edge-artifacts-prod KUBEKEY_PKG$ARTIFACT_BASE/kubekey/kubekey-bin-v3.0.0-linux-amd64.tar.gz YOLO_PKG$ARTIFACT_BASE/yolov8/yolov8s_rk3588_v1.2.0.tar.gz这样当版本升级时只需要更改变量文件里的版本号后面所有curl -O和校验逻辑自动跟着走。这个习惯保证了部署过程可重复不会出现手动下载了旧包脚本又拉了个新包的版本错乱。6. 一次完整落地RK3588 设备离线部署 YOLOv8 的复盘前面的章节都是组件级实践这一节我会完整串一遍。按我的经验端到端的部署才是最考验细节的任何一环漏了都会在现场返工。6.1 现场环境与前置物料清单目标设备RK3588 开发板系统为 Ubuntu 22.04ARM64内存 16GB磁盘 64GB。现场没有外网但有一个小型内网交换机Harbor、Nexus、Git 裸仓库部署在一台 x86 机架上。进入现场前物料清单如下物料来源中转位置体积edge-yolov8-inference 源码GitHub 私有仓库内网裸仓库12MByolov8s_rk3588_v1.2.0.tar.gzGitHub ReleaseNexus3.1GBrknn-toolkit2 相关 wheel 包GitHub Release / PyPINexus420MB推理服务 Docker 镜像ghcr.ioHarbor1.8GBHarbor / Nexus 离线包官网现场机架已安装这里我特别想说一句物料清单一定在出发前就要列好到现场再发现少东西就只能干瞪眼。6.2 串行执行链路从代码到推理服务的四步第一步代码。在目标板上git clone ssh://gitinternal-server/srv/git/edge-yolov8-inference.git切换到部署 tagv1.2.0。这一步依赖内网 SSH 用户提前在 authorized_keys 里加了现场机器的公钥。第二步依赖。从 Nexus 拉取 wheel 包并安装cd /opt/edge-yolov8 pip install --no-index --find-links/opt/wheels \ rknn-toolkit2-1.6.0-cp310-cp310-linux_aarch64.whl这里必须强调--no-index否则 pip 会尝试访问 PyPI在隔离网络里直接卡死。把需要的 wheel 包都放到本地目录后用--find-links指向本地目录安装速度反而比在线还快。第三步镜像。RK3588 上的推理服务一部分组件我选择用 Docker 跑因为依赖冲突太多。在/etc/docker/daemon.json里配置好 insecure-registriesharbor.internal.example.com然后systemctl restart docker。登录 Harbor直接拉取目标 project 的镜像docker login harbor.internal.example.com -u $ROBOT_USER -p $ROBOT_TOKEN docker pull harbor.internal.example.com/rk3588-prod/edge-yolov8-api:v1.2.0 docker compose up -d第四步模型权重和配置。把目标设备要用的.rknn模型文件从 Nexus 拉取放到指定目录。到这里推理服务的前后端链路已经全部在本地打转没有任何外网依赖。6.3 现场实际踩到的三个坑第一个坑出在 Docker 证书上。我没有给 Harbor 配 HTTPS而是用 HTTP 加 insecure-registries。但在 RK3588 上Docker 的 systemd 启动脚本里有自己的insecure-registries默认值直接修改/etc/docker/daemon.json后没有及时 reload。重启 docker 时一度提示certificate signed by unknown authority后来确认是 daemon.json 配置没生效systemctl daemon-reload再加systemctl restart docker才解决。实际配置正确后HTTP 在内网里跑完全没问题。第二个坑是镜像 tag 漂移。我在转存时不小心把一个镜像 tag 写成了latest结果第二天在另一台机器上部署时拉到的镜像和昨天校验过的 SHA 不一致。排查了很久最后发现是 Harbor 的 project 里有人其实是脚本重新推送了一次。从那之后我把所有推送命令的 tag 强制改成版本号并在 deploy 脚本里用--digest固定镜像摘要彻底杜绝了漂移。第三个坑是磁盘空间。Nexus 的 Blob Store 默认存放在系统盘转了 3.1GB 的模型包后系统盘一度满了。现场扩容很麻烦我不得不把 Blob Store 迁移到独立数据盘。建议你在 Nexus 创建时就指定数据盘路径别等到爆了再改。6.4 部署完成的验证清单我在每次部署结束后都会按清单逐项验证缺一不可docker ps中推理服务容器处于 healthy 状态。curl http://127.0.0.1:8080/health返回200。用测试图片调用推理 API返回的检测框数量符合预期。模型版本和权重 SHA 与 Nexus 上的记录一致。重启设备后服务能通过 systemd 或 Docker restart policy 自动拉起。这套验证流程看起来简单但它能挡住 90% 的交付类返工问题。在离网现场宁可多花十分钟验证也不要带着侥幸心理离开。7. 这套实践里我认为值得长期保留的经验跑完整个流程后有几个经验已经沉淀成了我自己的固定做法这里分享给遇到类似场景的朋友。第一所有制品必须不可变。不管代码 tag、镜像 tag、tar.gz 文件名一旦发布内容就不要再改。如果确实需要修复就发一个新版本号v1.2.1。这个看似死板的规矩在多人协作和内网交付里能避免大量到底是哪个包的争执。第二把同步工作脚本化并纳入版本管理。无论是 ghcr 到 Harbor 的镜像同步还是 GitHub Release 到 Nexus 的 tar.gz 同步都应该写成脚本放到 GitHub 私有仓库里管理。脚本本身也是代码也要走版本控制不要在外网机器上写一堆没有备份的临时代码。第三令牌和密码走最小权限原则。GitHub 的 PAT 只给该给的仓库权限Harbor 只给拉取权限Nexus 只给对应仓库的read/write。权限越大泄露后不可控的破坏力越大。跳板机、CI 账号、现场装机账号全部单独创建不要混用管理员。第四内网源优先考虑 HTTP 加白名单的折中方案。证书体系在团队规模小、网络隔离严格的项目里投入产出比很低。先用 HTTP 把链路跑通让业务顺利交付后续如果安全审计要求严再逐步引入内网 CA 和 TLS。我在 RK3588 现场就是用 HTTP 跑完验收的事后在测试环境才把证书补上。最后我想说一点个人体会。GitHub 私有仓库在这个链路里不仅仅是代码存放地它实际上是整个交付体系的事实源头。所有版本、制品、发布说明、构建流程都以它为锚点。只要源头清晰中间不管加多少层中转最终部署的可控性都不会太差。反过来如果源头乱糟糟就算 Harbor 和 Nexus 搭得再好现场也是一团浆糊。所以动手搭仓库之前先把版本规范和制品命名规范定清楚这事比安装任何一个软件都重要。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进