ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

CubeStudio离线部署实战:信创环境下Harbor镜像仓库搭建与避坑指南

CubeStudio离线部署实战:信创环境下Harbor镜像仓库搭建与避坑指南 1. 先理清需求CubeStudio 离线部署的真实难点在哪1.1 完全无外网的环境差的不只是网络接到一个信创项目要求把 CubeStudio 部署到完全无外网的内网里。我第一反应不是去看 CubeStudio 的安装文档而是先搞清楚现场的网络边界和可用资产。因为这类容器化平台本身部署不难难的是镜像怎么进去、依赖怎么补齐、后续节点怎么统一拉取。所谓“完全无外网”指的是业务内网在物理上或安全策略上和互联网断开不能访问 Docker Hub也不一定有自己的软件源。这不是少一条网线的问题而是整个部署路径都要反过来设计你在外网准备好的所有东西必须在一个受限窗口内搬进去。对外行来说可能觉得把安装包复制进去就行但实际动起手来你会发现容器镜像、编排文件、环境变量、数据卷权限、架构差异每一项都可能卡住一两天。我这次部署 CubeStudio目标环境是国产 CPU 国产操作系统的组合也就是常说的信创环境。CPU 是 ARM 架构的鲲鹏和飞腾操作系统是麒麟 V10 和统信 UOS。这两个架构差异直接把很多“能在 x86 上跑”的镜像挡在门外。所以离线部署的第一件事不是拷包而是确认你要的镜像在这个架构上有没有对应的标签如果有再谈导出和搬运。1.2 为什么一定要引入 Harbor可能有人会问既然内网不能联网为什么不让我直接拿移动硬盘一个个拷贝镜像 tar 包到每台服务器上docker load在小规模、单节点、镜像数量少的时候确实可以但 CubeStudio 这类平台通常由多个服务组件组成可能有 web 前端、后端服务、任务调度、数据库、对象存储等一二十个镜像。如果业务节点再扩展到十几台直接拷 tar 包的问题很快暴露每台机器都要导一遍镜像 tag 不统一升级时旧包残留没有人知道哪台机器上是哪个版本。Harbor 在这里充当的是“内网镜像总仓库”的角色。它本身可以离线安装里带了一整套 Harbor 服务镜像部署好之后各业务节点只需要通过docker pull从 Harbor 拉取镜像即可。Harbor 提供项目管理、权限控制、镜像复制、清理策略和 Web 界面对信创环境里常见的多团队多人协作来说非常必要。尤其当 CubeStudio 有后续版本升级只需要在准备区导出新镜像推送到 Harbor再让业务节点重新 pull整个升级链路就闭环了。1.3 我最终采用的部署链路这次项目里我实际用的链路可以分成三段第一段准备区。找一台能访问外网的 Linux 机器在上面拉取 CubeStudio 全量镜像按架构分别导出成 tar 包连同安装编排文件、依赖工具、校验文件一起整理成离线包。第二段隔离区。把离线包拷入内网 Harbor 服务器。Harbor 服务器不直接访问外网只通过离线安装包完成部署。离线包里所有镜像先docker load到本机再推送到 Harbor 的指定项目下。第三段业务区。CubeStudio 的每台业务节点配置好对 Harbor 的访问信任然后通过编排文件指定镜像地址为 Harbor 地址统一从内网仓库拉取启动。另外有些现场存在一台“临时出口机”也就是能同时访问外网和内网的双网卡机器。这种机器可以作为中转把外网镜像拉到本机再直接推送到内网 Harbor。这个方法效率很高但安全风险也最明显我后面会专门写一节讲它的用法和约束。2. 有网环境准备把镜像包做扎实后面才不返工2.1 梳理镜像清单和硬件架构离线部署最容易犯的错是到了现场才发现少了一个镜像。我习惯在准备区先把组件清单核对清楚让 CubeStudio 的厂商或实施文档给出完整的镜像列表。镜像清单我一般整理成images.txt每一行一个镜像全名加版本号格式大致是harbor.xxx.com/cubestudio/cubestudio-server:2.6.0 harbor.xxx.com/cubestudio/cubestudio-worker:2.6.0 harbor.xxx.com/cubestudio/cubestudio-web:2.6.0注意这里只是示例命名真实项目里按厂商给的 registry 路径来。整理清单时还要标注出架构比如 x86_64 还是 arm64。信创现场最常见的就是在 x86 电脑上导出的镜像拿到鲲鹏服务器上 load 成功但启动直接exec format error这就是典型的架构不匹配。确认架构后拉镜像时要带上--platform。比如在为 ARM64 准备镜像时可以这样写docker pull --platform linux/arm64 harbor.xxx.com/cubestudio/cubestudio-server:2.6.0如果镜像源本身没有这个架构的 tag这一步就会直接报错早发现早找厂商要 arm64 版本总比到现场翻车强。2.2 导出镜像的几种姿势导出镜像最常用的是docker save一条命令就能把镜像打包成 tardocker save -o cubestudio-server-2.6.0-arm64.tar harbor.xxx.com/cubestudio/cubestudio-server:2.6.0镜像多的时候我习惯写一个小脚本批量处理while read img; do name$(echo $img | tr / _ | tr : _) docker pull --platform linux/arm64 $img docker save -o ${name}.tar $img done images.txt如果你对镜像完整性要求更高还可以用 skopeo 来做导出。skopeo 能直接从 registry 层面复制镜像不依赖本地 Docker 守护进程而且可以更精细地指定平台命令大致如下skopeo copy docker://harbor.xxx.com/cubestudio/cubestudio-server:2.6.0 \ docker-archive:cubestudio-server-2.6.0-arm64.tar:harbor.xxx.com/cubestudio/cubestudio-server:2.6.0两种方式各有优劣。docker save简单直接适合大多数实施人员skopeo 更接近 registry 原数据如果你的镜像源来自多个不同 registry用 skopeo 可以减少本地 Docker 环境的干扰。但无论用哪种我都不建议把多个镜像塞进一个超大 tar 包除非现场确实有这样的封装要求。分开导出到了现场可以单独 load某个镜像有问题时不会牵一发动全身。2.3 离线包的目录结构、校验和最小化镜像打完之后不能随手丢一个U盘就走。离线包的目录结构要清晰尤其当同时有 x86 和 arm64 两套镜像时必须分开放。我一般会按下面的方式组织offline-cubestudio/ ├── readme.txt ├── checksums.sha256 ├── images/ │ ├── arm64/ │ │ ├── cubestudio-server-2.6.0-arm64.tar │ │ └── ... │ └── x86_64/ │ ├── cubestudio-server-2.6.0-x86_64.tar │ └── ... ├── compose/ │ └── docker-compose.yml └── scripts/ ├── load_images.sh └── push_images.sh生成校验文件这一步很多人会省掉但现场验证时特别有用sha256sum images/arm64/*.tar images/x86_64/*.tar checksums.sha256在准备区机器上也可以随机抽一个 tar 包做 load 验证docker load -i images/arm64/cubestudio-server-2.6.0-arm64.tar验证之后再删掉本机加载出的镜像避免准备区机器磁盘被挤爆。离线包里的 compose 文件、环境变量文件也都要一并带上最好在 readme.txt 里写清楚现场步骤和默认密码修改要求。记住离线包不是镜像 tar 的堆砌而是一个可以交付给任何实施人员的完整资产。3. Harbor 内网私有仓库离线安装与避坑3.1 离线安装 Harbor 的前置条件Harbor 的离线安装包可以在有外网的机器上下载到达内网后直接使用。比如 Harbor v2.10.1 对应的离线包是harbor-offline-installer-v2.10.1.tgz这个包里面已经包含了 Harbor 自身需要的所有镜像 tar安装过程不需要再访问外网。但安装前必须确认几件事Harbor 服务器上有 Docker 环境。我建议 Docker 版本不低于 20.10太旧容易触发兼容问题。安装了 docker-compose 插件或docker-compose命令。Harbor 安装脚本靠 compose 拉起整套服务没有它寸步难行。磁盘空间足够。Harbor 自身镜像包解压后占用大概几个 GB再加后续 CubeStudio 镜像建议预留至少 200GB。如果镜像量大500GB 都不算多。80 端口没有被占用。Harbor 默认监听 80如果机器上已经有 nginx 或其他 Web 服务端口会冲突。离线包拷入内网后解压并进入目录tar -xzf harbor-offline-installer-v2.10.1.tgz cd harbor然后修改harbor.yml再执行./install.sh即可。install.sh会自动 load 包内镜像并启动 Harbor整个过程不需要网络。3.2 harbor.yml 关键配置与密码策略harbor.yml是安装前唯一需要重点改的文件。以下是我常用的最小配置hostname: 192.168.209.133 http: port: 80 harbor_admin_password: ChangeMe_StrongPass2025 data_volume: /data/harbor database: password: ChangeMe_DBPass2025hostname可以填内网 IP也可以填内网 DNS 能解析的域名。如果后续要用域名访问尽量在这里就写域名避免后面改起来麻烦。data_volume是 Harbor 的数据目录建议挂在大容量数据盘上不要放在系统盘。harbor_admin_password和database.password必须改成强密码现场如果安全要求高还要在安装完成后立刻修改不要保留默认。如果你的内网环境要求 HTTPS 访问 Harbor可以配置证书和私钥https: port: 443 certificate: /data/certs/harbor.crt private_key: /data/certs/harbor.key但信创内网很多还没有统一证书体系最省事的是先用 HTTP 跑通后续再加 HTTPS。别一上来就搞证书客户端信任链的问题比镜像搬运还麻烦。配置完成后执行sudo ./install.sh安装结束看到Harbor has been installed and started successfully.就说明服务起来了。验证一下docker compose ps curl http://192.168.209.133/api/v2.0/health如果返回的 JSON 里组件状态都是healthyHarbor 的安装就基本算完成。3.3 Docker 客户端怎么信任内网 HarborHarbor 装好之后要让所有业务节点能登录和拉取镜像。这一步最大的坑是 HTTP/HTTPS 不匹配。Docker 默认会用 HTTPS 访问仓库地址如果你的 Harbor 只开了 HTTP推送时会直接报错Error response from daemon: Get https://192.168.209.133/v2/: http: server gave HTTP response to HTTPS client解决方式是修改 Docker daemon 配置把 Harbor 地址加入insecure-registriesmkdir -p /etc/docker cat /etc/docker/daemon.json EOF { insecure-registries: [192.168.209.133] } EOF systemctl restart docker重启之后可以用下面的命令确认配置生效docker info | grep -i Insecure Registries如果 Harbor 用的是自签名 HTTPS就不要简单加insecure-registries更规范的做法是把 CA 证书放到客户端的/etc/docker/certs.d/192.168.209.133/ca.crt目录然后重启 Docker。这样客户端能验证服务端身份安全性和兼容性都比裸 HTTP 好。我这里只想提醒一个细节修改daemon.json后必须重启 Docker不是 reload 就够有时候 reload 不生效得重启守护进程才刷新。3.4 创建项目并完成第一轮镜像推送Harbor Web 界面登录后第一步是创建一个项目比如cubestudio。项目权限可以设为私有实施阶段先用管理员账号操作后面再分配合适的成员权限。创建好项目后准备区导出的镜像 tar 包在 Harbor 服务器上 load 进去然后打上 Harbor 地址的 tag再 push。在 Harbor 服务器上执行docker load -i images/arm64/cubestudio-server-2.6.0-arm64.tar docker tag harbor.xxx.com/cubestudio/cubestudio-server:2.6.0 192.168.209.133/cubestudio/cubestudio-server:2.6.0 docker login 192.168.209.133 -u admin docker push 192.168.209.133/cubestudio/cubestudio-server:2.6.0如果离线包里的镜像 tag 还是原始 registry 路径可以在 load 之后批量打 tag。这里最重要的原则是所有镜像在 Harbor 里的命名要统一后续业务节点才能用同一套编排文件。否则每台机器改一堆 tag极易出错。4. 临时出口机中转无外网环境下最实用的补位手段4.1 出口机的角色和网络规划有些信创现场并非严格的“物理拔线”而是业务内网无法访问外网但存在一两台双网卡机器一边连着外网一边连着内网。这种机器我习惯叫它“出口机”或者“中转机”。出口机的作用是在部署窗口期充当镜像的搬运工。它的外网口可以从镜像源拉取新镜像内网口又能直接访问 Harbor 或者业务网络所以可以省掉“人肉拷贝 tar 包”这个过程直接镜像流式转储。这个手段效率高但对网络管理和安全的要求也高。网络规划上收窄端口比做应用层限制更管用。外网口的访问控制列表只允许从这台机器主动访问外网镜像站不允许外部访问进来内网口只开放到内网 Harbor 和业务节点的必要端口。如果云环境有安全组就把这台出口机放在一个单独的隔离子网里不要和其他业务混在一起。4.2 在出口机上完成镜像的拉取、改标签和推送出口机上只需要一个 Docker 环境。具体操作步骤如下第一步从外网镜像源拉取镜像docker pull harbor.xxx.com/cubestudio/cubestudio-server:2.6.0第二步把镜像 tag 改成内网 Harbor 的地址docker tag harbor.xxx.com/cubestudio/cubestudio-server:2.6.0 192.168.209.133/cubestudio/cubestudio-server:2.6.0第三步登录内网 Harbor 并推送docker login 192.168.209.133 -u admin docker push 192.168.209.133/cubestudio/cubestudio-server:2.6.0如果出口机到 Harbor 之间的网络不稳定或者跨防火墙无法直接访问 80/443 端口就不要硬推。改回土办法在出口机上docker save导出 tar拷贝到 Harbor 服务器 load再 push。虽然多了一步但容错率更高也方便留一份离线存档。4.3 安全兜底中转机用完必须“消失”出口机最大的隐患是“被遗忘”。很多项目部署完这台能访问外网的机器就一直留在内网角落里等于在内网开了个口子。这在信创环境里是非常敏感的事。我自己的做法是给出口机设一个明确的“生命周期”。部署窗口期结束立即从防火墙上删除外网访问规则更彻底的做法是拔出外网网线或者直接把系统重装回内网专用状态。如果是第三方临时提供的机器还要在交接单上写明“不再允许接入外网”避免后面被人无意中把网线插回去。另外出口机上不要长期保留镜像和登录凭据。推送完成后及时清理临时镜像docker system prune -a docker logout 192.168.209.1334.4 如果连出口机都不允许存在怎么办很多高安全等级的内网是不允许任何双网卡机器出现的。遇到这种情况只能回到全离线人工搬运的模式。U盘或者移动硬盘拷贝 tar 包到目标机器docker load。这时候离线包的目录结构和校验文件就特别重要。现场服务器不一定认 exFAT有些国产操作系统对 NTFS 支持也不太完善我建议移动硬盘用 exFAT 分区提前在准备区机器上挂载测试。拷贝完成后先sha256sum -c checksums.sha256再执行 load不校验就 load 是现场最容易踩的坑。5. CubeStudio 在信创服务器上的落地部署5.1 信创 OS 和硬件架构检查CubeStudio 正式部署前先花十分钟确认现场硬件和系统状态。以下命令是每台业务节点必跑的cat /etc/os-release uname -m lscpu | grep Architecture docker version docker infouname -m会告诉你内核架构是aarch64还是x86_64。很多信创操作系统虽然界面和 CentOS 很像但内核架构和软件生态不同。Docker 版本和存储驱动也要确认docker info里如果看到overlay2就没问题如果是老的devicemapper建议先整改再部署。麒麟 V10 和统信 UOS 上Docker 可能已经被系统预装也可能只装了 containerd 而没有 Docker CLI。如果只有 containerd可以用nerdctl代替 Docker 命令或者离线安装 Docker。厂商提供的离线包中如果依赖 Docker 命令尽量统一装成 Docker CE 对应的国内发行版避免混用。5.2 CubeStudio 编排文件改造离线包里的docker-compose.yml通常写的是原始镜像源地址比如harbor.xxx.com/cubestudio/xxx。现在需要把这些地址统一替换成内网 Harbor 地址。我一般先备份原文件cp docker-compose.yml docker-compose.yml.bak然后做批量替换sed -i s#harbor.xxx.com/cubestudio/#192.168.209.133/cubestudio/#g docker-compose.yml替换后打开文件检查一下有没有遗漏。重点看这些位置所有image:字段依赖镜像的 build 参数如果用不到构建保持镜像拉取即可环境变量里如果也写到了镜像仓库地址要一并替换除了镜像地址CubeStudio 的编排文件里通常还有数据库密码、Redis 密码、对象存储配置等环境变量。信创环境下不能沿用默认密码这些都要改成符合现场要求的值。改动之后建议先在测试节点试跑一次确认服务能起来再往所有节点推广。5.3 从 Harbor 拉取镜像并启动服务所有业务节点配置好 Harbor 信任后进入 CubeStudio 编排目录执行docker compose pull docker compose up -d docker compose ps如果是旧的docker-compose命令则把docker compose换成docker-compose。看到所有服务状态为Up之后再查看启动日志docker compose logs -f重点看有没有Permission denied、exec format error、no such file or directory之类的异常。前两个分别指向数据卷权限和镜像架构问题最后一个往往意味着数据目录或配置文件缺失。启动正常后通过浏览器访问 CubeStudio 的 Web 界面完成初始化配置。如果现场没有 DNS客户端 hosts 文件需要把 Dashboard 域名解析到部署节点 IP或者直接用 IP 访问。5.4 信创环境特有的坑架构标签和加速卡驱动信创部署和普通 x86 环境最大的差异有两个。第一是镜像架构。很多公开镜像只提供amd64架构在飞腾、鲲鹏上跑不起来。这个不是靠离线包能解决的必须在准备阶段找厂商要对应架构版本或者自行构建。现场如果出现exec format error不用怀疑先查镜像架构。第二是加速卡。CubeStudio 如果涉及模型训练或推理信创环境往往会配昇腾、寒武纪这类国产加速卡。这意味着不仅要装镜像还要把所有驱动、运行时、固件一起离线准备好。Docker 启动时还要正确透传设备docker run --device /dev/davinci0 ...或者使用厂商提供的 runtime。这类问题在前期调研阶段就要确认别等部署时才发现镜像里缺驱动。6. 常见问题与排查技巧实录6.1 Harbor 推送失败get https://192.168.209.133/v2/ 与 dial tcp 192.168.209.133这个报错在离线部署现场非常高频。我见过至少有三种情况第一种Harbor 是 HTTPDocker 默认走 HTTPS。报错一般是http: server gave HTTP response to HTTPS client。解决方法就是前面说的在客户端/etc/docker/daemon.json里配置insecure-registries。第二种Harbor 端口不是默认端口。如果你把 Harbor 配置成监听 8080但推送命令还写成192.168.209.133/cubestudio/xxxDocker 会默认访问 443最后出现dial tcp 192.168.209.133:443: connect: connection refused这时要把端口显式写在地址里docker push 192.168.209.133:8080/cubestudio/cubestudio-server:2.6.0并且insecure-registries里也写完整端口。第三种IP 不通或防火墙拦截。现象是dial tcp 192.168.209.133:80: i/o timeout而不是connection refused。先用telnet或nc测试端口nc -vz 192.168.209.133 80如果端口不通顺序检查 Harbor 所在机器的防火墙、云安全组、内网路由。注意有些国产操作系统默认开了 firewalld需要放行端口。6.2 Windows Server 2022 离线部署 WSL containers 的坑有些现场会拿 Windows Server 2022 当管理机或临时服务器想在上面离线跑 Linux 容器实际上这条路坑不少。Windows Server 2022 上直接装 Docker Desktop 并不被官方推荐更实用的方式是装 WSL2然后在 WSL 里跑 Docker Engine。离线安装 WSL2 的关键步骤是启用 Windows 功能dism /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart重启服务器。离线安装 WSL2 内核更新包wsl_update_x64.msi这是最容易漏的组件。离线导入一个 Ubuntu 发行版wsl --import Ubuntu D:\wsl\Ubuntu ubuntu.tar.gz --version 2进入 WSL 后离线安装 Docker Engine 的 deb 包并配置好/etc/docker/daemon.json。很多人只做了第 1 和第 4 步没做第 3 步结果wsl --set-default-version 2直接失败。记住WSL2 内核更新包是独立的 MSI不是 WSL 功能启用就能自动完成的。如果服务器硬件没有开启虚拟化VirtualMachinePlatform功能无法启用WSL2 也跑不起来这种属于硬件限制别指望软件绕过。6.3 Ubuntu 离线导入 Harbor 镜像包的那些坑把 Harbor 离线包搬到 Ubuntu 上安装时有几个很常见的问题如果离线包里的harbor.v2.10.1.tar.gz体积比较大导入时容易出现磁盘不足。系统报no space left on device但df -h看根目录明明还有空间是因为 Docker 的数据目录可能在另一个分区。用docker info查Docker Root Dir确认镜像存储空间是否足够。Ubuntu 上如果同时装了新版docker compose插件和旧版docker-composeHarbor 的install.sh可能会识别混乱。建议只保留一种方式并确认docker compose version如果几十个镜像导入后Harbor Web 界面一直打不开先看 80 端口是否被占用ss -lntp | grep :80被占用时要么停掉占用服务要么把 Harbor 的 HTTP 端口改成 8080并在所有客户端地址中带上端口。我整理了一份速查表方便现场快速对号入座现象主要原因快速排查或解决推送时报http: server gave HTTP response to HTTPS client客户端用 HTTPS 访问 HTTP Harbor配置insecure-registries并重启 docker推送时报dial tcp ...:443: connection refusedHarbor 没监听 443或端口不符检查 Harbor 实际端口显式带端口推送时报dial tcp ...:80: i/o timeout网络不通或防火墙拦截nc -vz测试端口检查安全组和 firewalldload 镜像时报no space left on deviceDocker 数据目录所在分区空间不足清理旧镜像或把>
RELATED READING

延伸阅读

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