• 请不要在回答技术问题时复制粘贴 AI 生成的内容
xhawk
V2EX  ›  程序员

一个 MonoRepo 复杂系统的部署问题

  •  
  •   xhawk · 7h 47m ago · 639 views

    我搞了一套财税系统,采用的是 MonoRepo 的构建方式。也就是说,在 APPs 目录下有几十个应用。前端全部用的是 Next.js ,后端用的是 FastAPI 。现在的问题是,代码托管在 GitHub ,镜像则通过阿里云的 ACR 来构建。

    核心问题是构建速度非常慢。目前有 11 个应用,其中 4-5 个是前端,6-7 个是后端服务, 后续还在增长。问题在于,有时候我可能只修改了其中一个应用,但很难控制每次只自动构建被修改的那一个。

    目前我在 GitHub 上构建时,只有一个分支,也就是 main 分支。如果单独构建每个 APP ,通常只需要 1 到 2 分钟。但一旦有十几个 APP ,每次都要全部构建一遍,速度就会越来越慢,而且我的 APP 数量还在不断增加。我在想,有没有办法在保持 GitHub 上只有一个分支的情况下,也能获得比较快速的构建体验?不知道大家在这方面有没有相关的实践经验?

    20 replies    2026-09-06 01:43:51 +08:00
    lujiaosama
        1
    lujiaosama  
       7h 39m ago
    我选择不用 MonoRepo 。
    xhawk
        2
    xhawk  
    OP
       7h 37m ago
    @lujiaosama 那有啥建议的不, 如果全部分开代码管理, 也很复杂。 因为涉及到系统间的各种调用。
    XTTX
        3
    XTTX  
       7h 16m ago
    vercel 可以选忽略构建步骤, 阿里的你应该问问 AI. 应该是很容易解决的问题
    fgwmlhdkkkw
        4
    fgwmlhdkkkw  
       7h 12m ago
    写一个简单的解析 commit msg 的脚本,然后按照约定写 commit msg 。
    milkleeeeee
        5
    milkleeeeee  
       7h 11m ago
    netnr
        6
    netnr  
       7h 8m ago
    按 yml 变动构建(增加环境变量 改注释);每个配置里面的矩阵是并行构建
    is
        7
    is  
       7h 2m ago via Android
    建个 ci 的项目把规则写进去,不懂的地方让 agent 帮忙就好了。项目依赖图什么的都好做,可能不太确认的就是 cache 机制。commit 消息也可以做个规范,方便规则匹配
    Reficul
        8
    Reficul  
       6h 24m ago
    上增量编译,bazel 之类的。
    xhawk
        9
    xhawk  
    OP
       6h 18m ago
    这个 cursor ai 给的建议, 虽然不是很满意, 但是似乎也只能这么干, 要么就是上面有人建议的采用付费的方式。
    ai 的建议, 大概意思意思 acr 构建镜像采用过滤的方式, 代码改了啥, 就构建啥就好了。

    **结论先说:仓库不要拆。慢的不是 Monorepo ,是「 main 一推就串行重打全部镜像」。**

    源码继续单仓单分支是对的。行业里 Google / Meta / Shopify 、以及 Nx / Turborepo 的做法都是:**代码合在一起,构建按依赖图只打受影响的那几个。** App 越多,越要走这条路,而不是拆仓。


    **推荐方向(这就是业内标准解):Affected Build + 远程缓存 + 只发变更。**

    1. **关掉 ACR 当 CD 引擎。** 个人版不适合 10+ 服务。构建改到你们已有的 self-hosted Actions (可并行),结果推杭州 ACR ; Dokploy 只 Redeploy 本次变更的服务。
    2. **按依赖图决定打谁,不要按「整个仓库变了」。** 例如改 `apps/fis-open-api` 只打 open-api ;改 `apps/fis-api` 打 fis-api **以及**依赖它的 open-api ;改 `packages/*` 只打引用它的前端。用 `paths-filter` 或一份很小的 affected 映射就够,不必上 Bazel 。
    3. **缓存比拆 context 更值钱。** Dockerfile 已经分层了(先 requirements / package.json )。接上 BuildKit registry cache 后,没改依赖的镜像应是秒级命中。根 context 可以留——你们前端是 pnpm workspace ,强行 per-app context 收益不大。
    4. **中期把「构建期互相 COPY 」收掉。** open-api 不要整份拷贝 fis-api/agents ,改运行时 HTTP / 抽出 `packages` 共享库; fis-web 的共享 UI 进 `packages/fis-shared`。耦合一收,affected 扇出就小,速度才会随 App 增加而近似持平。
    5. **发版钉 digest ,不要 8 个 `*-latest` 整波拉。** 未重建的服务保持旧 digest ,避免「构建快了、发布又全量」。
    rocmax
        10
    rocmax  
       6h 3m ago via Android
    建议是每次都全部构建,使用 cache 来解决重复构建耗时的问题。monorepo 强制同步整个项目的版本,防止依赖版本错位,如果选择性构建一部分就回到老路上了。

    我们用 turborepo 管理项目,我的经验是:

    如果构建产物是 docker 镜像的话使用 layer cache 可以解决大部分问题。需要注意的是构建之前需要用 turbo prune xxx --docker 来提取构建 context 以免混入其它的修改。

    如果想直接缓存 nextjs 的构建产物,turborepo 官方有付费构建缓存服务。
    也有开源版本比如
    https://github.com/ducktors/turborepo-remote-cache
    需要自己借助 s3 等来搭建。

    另外的一点是在部署 k8s 时全部构建的话产物有共同的 tag ,helm chart 中可以将它统一填到所有子项目中。如果部分购进的话又得管理版本依赖。
    members
        11
    members  
       5h 57m ago
    问题在于,有时候我可能只修改了其中一个应用,但很难控制每次只自动构建被修改的那一个。
    ---
    难在哪里?
    我们的方案是构建过程中运行一个脚本,git diff merge-base 有哪些文件改动,构建对应的服务。

    有一说一 monorepo 是真的恶心。
    perfectlife
        12
    perfectlife  
       5h 53m ago via Android
    这个我有经验,我是根据代码变更判断触发构建 monorepo 仓库下的那个项目,有一说一前端的 monorepo 仓库做 cicd 有点恶心,cicd 要求是项目最好是要标准化,monorepo 仓库感觉是恰恰相反
    xhawk
        13
    xhawk  
    OP
       5h 53m ago
    @members 这是一个很核心的问题。虽然我改了一个应用,但在自动构建时,不一定只构建这一个应用,因为应用之间是存在依赖关系的。AI 给我的建议与你的思路类似,就是通过 GitHub 的 Actions 去计算这次应该构建哪个服务。

    monorepo 在代码管理以及多项目协同与调度方面,我觉得它的表现相当优秀。但构建速度慢的问题确实让人头疼,尤其是 Next.js 的慢,尤其令人烦躁。
    rocmax
        14
    rocmax  
       5h 51m ago via Android
    @members 如果子项目各自独立的话没有问题,但是这样就不用 monorepo 了。子项目之间有依赖关系的话不分析依赖图就不知道该构建谁。
    xhawk
        15
    xhawk  
    OP
       5h 39m ago
    @rocmax 对, 感谢, 也就是这个问题的核心关键。 当然, 我也只是抛出问题, 希望能获得其他的灵感和做法。 若有的话, 欢迎给建议,我来做实验, 同时, 我也会把我最后的做法分享出来。
    members
        16
    members  
       3h 56m ago
    @rocmax #14
    我认为子项目之间不应该有代码和部署上的依赖,如果是这样就不应该拆成独立项目。

    但 monorepo 内会存在共同依赖的基础包,这是合理的。我们是配置了一个依赖关系,依赖包有改动会重新构建所有依赖了这个包的项目。

    @xhawk #13
    chongzi
        17
    chongzi  
       3h 48m ago
    应用之间不应该存在依赖关系吧?
    johnhom
        18
    johnhom  
       3h 39m ago
    可以尝试用一些 monorepo 的管理工具,比如说 nx ,turborepo ,这些都会自动计算某个版本内被 effect 到的包,还会自动计算依赖路径,能决定先构建哪个后构建哪个。这个应该才是最优解
    zengxs
        19
    zengxs  
       3h 34m ago
    monorepo 是相关的模块才放一起啊
    如果 repo 内都是相关模块,每次都重新构建很合理啊

    而且你是 nodejs + python ,这 ci build 应该也不会特别慢吧

    > 单独构建每个 APP ,通常只需要 1 到 2 分钟

    那十几个项目也就 20 分钟左右吧

    好多 c++ 项目跑一次 build 还要几个小时呢,我觉得挺正常的
    zengxs
        20
    zengxs  
       3h 33m ago
    @zengxs #19 如果不同 app 构建没有依赖关系,可以用 github action matrix 并发构建
    最后用一个 merge job 合并为最终 image 产物就行了
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   876 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 42ms · UTC 21:17 · PVG 05:17 · LAX 14:17 · JFK 17:17
    ♥ Do have faith in what you're doing.