Skip to content

私有化部署 — 总览与架构

范围:把 HiAPI Cloud 从"我们自己跑的 SaaS"改造成"能交付到客户自己集群里跑"的产品形态。代码横跨全部 Java 服务(配置外部化)、hiapi-deploy(统一 CI)、hiapi-chart(k8s 清单模板)、hiapi-cloud-nuwa(交付中心)。

相关文档:Helm Chart 指南(chart 怎么用、怎么加服务)(从零交付一个客户的完整步骤)。

⚠️ 2026-07-28 方向已变更:客户配置与交付编排收拢到 nuwa,废弃 git+SOPS+Argo 方案。本文档保留背景与配置外部化部分(仍然成立),目标形态与开发顺序请看 nuwa 交付中心,决策记录见 ADR-0008


一、这件事的真正难点不是 chart

一开始很容易以为"私有化 = 写个 Helm chart"。实际排查下来,第一优先级是配置外部化,不是 chart

原因很直接:各服务的配置(数据库地址、Redis、Nacos、第三方密钥)硬编码在 application-k8s.yaml 里,打进了 jar。这意味着同一个镜像换个客户就跑不起来 —— 而"同一个镜像在所有客户环境通用"恰恰是私有化交付的前提。chart 写得再漂亮,底下的镜像不通用,整件事就不成立。

所以顺序是:配置外部化 → 统一镜像构建 → chart → 一键装机 → 应用市场

二、分层

内容谁来装
L0 基础设施机器、k3s、存储、备份一键脚本
L1 底座MySQL / Redis / RabbitMQ / Nacos + gateway + public + admin-uichart 默认开
L2 业务应用user / finance / vem / socket / sy / task-worker / shop / storechart 按开关增量装
L3 增值应用市场里的第三方应用nuwa 应用市场

L1 是"装完就能登进后台"的最小集合。L2 按客户买了什么开关。

三、三个仓库的分工

hiapi-chart/       产品:一份 umbrella chart,渲染全部服务
hiapi-cloud-nuwa/  交付中心:客户、中间件参数、应用勾选、版本编排、YAML 下发
hiapi-deploy/      统一 CI 脚本 + 版本清单(releases/)

这条边界是刻意的:chart 里不许出现任何客户的名字,客户目录里不许出现任何模板逻辑。混在一起的结果一定是"给 A 客户改个东西顺手动了 chart,B 客户下次升级时炸掉"。

各仓库的详细用法见 Helm Chart 指南

四、配置外部化:prod profile

新增 prod profile 作为私有化/生产的标准 profile,所有外部依赖一律从环境变量读。旧环境继续用 k8s profile,存量部署不受影响。

激活方式:SPRING_PROFILES_ACTIVE=prod

环境变量清单

变量说明
MYSQL_HOST / MYSQL_PORT / MYSQL_USER / MYSQL_PASSWORD / MYSQL_DATABASE每个服务连自己的库
REDIS_HOST / REDIS_PORT / REDIS_PASSWORD / REDIS_DATABASE
RABBITMQ_HOST / RABBITMQ_PORT / RABBITMQ_USER / RABBITMQ_PASSWORD / RABBITMQ_VHOST
NACOS_ADDR / NACOS_USER / NACOS_PASSWORD / NACOS_NAMESPACE / NACOS_GROUP
SERVER_PORT / TZ / DB_TIMEZONE / SQL_SHOW / REQUEST_LOG / SHARDING_CREATE

密码没有默认值,这是刻意的

prod profile 里所有密码占位符不给默认值,缺失即启动失败。

理由:用错误的凭据连上错误的库,比起不来更糟 —— 后者你立刻知道,前者可能几天后才在数据里发现。同样的原则贯穿到 chart(缺密码时 helm 直接拒绝安装,而不是让 Pod 反复 CrashLoop)。

健康检查必须用分组端点

探针只能用 /actuator/health/readiness/actuator/health/liveness,绝不能用 /actuator/health

/actuator/health 把依赖中间件的健康也折进去。真用它做 liveness,MySQL 抖一下所有 Pod 会被同时 kill —— 故障被放大而不是被隔离。而且这个问题只在部署当天暴露。

第三方集成:未配置不能影响启动

私有化客户大概率不用 Stripe、AWS IoT 这类集成。原则是没配就不加载,而不是加载后报错

已排查过全部第三方集成,结论:

  • 短信(阿里云)、邮件(SMTP)按 mid 从数据库读配置、调用时才 checkConfig,不配不影响启动
  • 对象存储 OSS/COS/S3 是运行时 new XxxUploadFileService(config),不是 Bean
  • 7 个支付渠道没有 @Value/@PostConstruct/静态初始化,微信与支付宝官方直连都是懒加载客户端缓存
  • 全库只有 2 处 @ConditionalOnProperty(StripeConnectLogicAwsIotAutoConfiguration),都已加上条件

新增第三方集成时请守住这条线:不要在 Bean 初始化阶段读必填配置

五、镜像:一套构建方式,语义化 tag

构建统一走 jib

7 个 Java 服务(gateway / public / user / finance / vem / sy / task-worker)全部用 jib-maven-plugin 直接推 registry,不需要 docker daemon —— 流水线因此不用配 docker 环境。

各仓库里保留的 Dockerfile 仅供本地应急,正式镜像不走它。⚠️ base 镜像在 Dockerfile 和 pom 的 <jib><from> 各写一份,改版本要两处同时改

base 镜像统一为 registry.cn-hangzhou.aliyuncs.com/hiapi/jdk:21

历史坑:曾经有服务用 com.spotify:docker-maven-plugin,硬编码了内网 daemon http://192.168.50.3:2375,而且没有 <executions> 根本不绑生命周期 —— 是一段既连不上又不会执行的死配置。已全部清除,不要从 git 历史里翻出来抄。

只有 git tag 能触发正式构建

bash
git tag v1.4.2 && git push origin v1.4.2

流水线用标签触发(正则 ^v\d+\.\d+\.\d+$),推送两个 tag:

tag用途
1.4.2部署用,chart 里引用这个
1.4.2-31d0268溯源用,精确定位到 commit

永远不要用 latest —— 它让"客户现在跑的是什么"变成一个不可回答的问题。

临时构建可以 VERSION=0.0.0-dev ./build.sh,这个版本号一眼能看出不是正式版。

构建脚本在 hiapi-deploy/ci/build.sh,自动识别四种项目类型(jib / Dockerfile / package.json / go.mod)。各服务流水线 clone hiapi-deploy 后调用它,改一次全仓库生效。

admin-ui 走 GitHub Actions

前端必须用 docker 构建(Java 那几个走 jib 不需要),而 GitHub Actions 自带 buildx 和缓存,省得在 Codeup 上单独配 docker 环境。一次构建双推送:ghcr.io(GitHub 生态)+ 阿里云 ACR(国内客户拉取,ghcr 在国内经常超时)。

⚠️ Actions 跑在境外,NPM_REGISTRY 必须覆盖成官方源,默认的 npmmirror 在境外又慢又容易超时。

镜像公开与授权闸门是矛盾的

admin-ui 设为公开仓后客户拉镜像不需要 imagePullSecret,很方便。但这与"license 到期即停发 ACR 凭据"的思路直接冲突 —— 公开镜像谁都能拉,凭据闸门对它不起作用。

admin-ui 只是前端壳,可以接受。hiapi-cloud-public 的 JNI 保护模块绝不能进公开仓。

六、当前状态与已知缺口

可用:prod profile(7 个服务在 JDK 21 上验证启动通过)、统一 CI 脚本、umbrella chart(含自带 Nacos、建库 Job、依赖矩阵)。

注意:曾经的 hiapi-customers(git 仓库 + SOPS/age 加密客户配置)已于 2026-07-28 废弃 —— 规模从 3 个独立客户重估到每年 100~200 个之后,手工建客户目录的模式不成立,客户配置改由 nuwa 承载。

还缺:

缺口影响
bitnami 依赖未 vendored 进 chart 包无外网的客户机器装不上,详见 Chart 指南
最小底座未在真集群端到端跑过需要一个可用集群
shop / store 没有镜像构建方式,服务发现仍是 Eureka 未迁 Nacos未正式立项,chart 里保持关闭
编译目标版本混用 17/18/21JDK 21 运行时向下兼容,不影响部署,建议随某次全量构建收敛

跨会话待办见仓库根 TODO.md