Jenkins Vue 流水线构建 OOM(exit 137)复发的问题

Jenkins Vue 流水线构建 OOM(exit 137)复发的问题

记录时间:2026-08-21
环境:Jenkins 2.568.1(K8s 动态 Slave,devops 命名空间)/ 共享库 vueHelmDevopsByk8s 流水线 / node 容器 gzeport-node-pnpm:20(node 20.19.5 + pnpm 10.22.0)/ 项目 sccg-vue-gzeport-market-vue(Vue3 + TS + vite 7.3.6,5531 模块)
关联笔记:[Jenkins Vue流水线构建异常排查-pnpm版本-husky-构建脚本拦截-OOM](./Jenkins Vue流水线构建异常排查-pnpm版本-husky-构建脚本拦截-OOM.md)(2026-07-16,track-ui-xc 同因 OOM 首次爆发)

一、问题现象

sccg-vue-gzeport-market-vue #19 构建(分支 origin/dev)在前端构建阶段失败,构建耗时 5min41s:

✓ 5531 modules transformed.
rendering chunks...
Killed
 ELIFECYCLE  Command failed with exit code 137.
  • exit 137 = 128 + 9(SIGKILL),node 容器 limits.memory: 6Gi 被 cgroup OOM Kill
  • 失败点在 rendering chunks...(vite/rollup 打包最后阶段,内存峰值区)
  • 同日早些时候的 #18 构建成功。峰值内存本就在 6Gi 临界区波动,业务提交带来的模块数量差异即可跨过红线

二、排查过程

2.1 确认 137 的来源

Jenkins 日志无 JS 异常堆栈、无磁盘满,Killed 出现在 shell 层,排除应用报错,指向内核杀进程。node 容器 limits 6Gi,判定 cgroup 内存超限。

2.2 定位内存峰值构成:业务 build 脚本并行双进程

日志回显业务 package.jsonbuild:uat 脚本:

> market@3.0.0 build:uat /home/jenkins/agent/workspace/sccg-vue-gzeport-market-vue
> vue-tsc --noEmit & vite build --mode uat

单个 &(后台并行)让两个 Node 进程同时跑:

  • vue-tsc --noEmit:TS 全量类型检查,大项目吃 1~2G
  • vite build:5531 模块转换 + chunk 渲染,4~5G 以上

流水线的 NODE_OPTIONS=--max-old-space-size=4096 是环境变量,对容器内所有 Node 进程生效,两个进程各自最多 4G 堆,叠加冲破 6Gi 容器上限。与 2026-07-16 track-ui-xc 的 OOM 同因(见关联笔记)。

2.3 发现 vue-tsc 在 CI 里纯浪费

构建日志里 vue-tsc 输出了约 200 个 TS 类型错误(TS2304/TS2694/TS2300/TS2322……),但构建照样往下走直到 vite OOM。机制上:& 把 vue-tsc 放进后台后,shell 不会等待它,其退出状态没有被显式 wait 收集,失败不影响脚本最终退出码——npm script 实际反映的是前台 vite build 的结果。类型检查在 CI 里既不拦截质量,又每次白占 1~2G 内存和几分钟时间。

三、根因分析

层面 事实
直接原因 业务 build:uat& 并行跑 vue-tsc 与 vite,双进程内存峰值叠加超容器 limit
放大器 NODE_OPTIONS 无法按进程区分,两进程各享堆上限
恶化趋势 模块数增长到 5531,峰值逐步跨过 6Gi 红线
根本问题 vue-tsc 在 CI 无拦截作用(退出码被 & 丢弃),纯属无效内存开销

历史脉络(同一根因两轮爆发):

时间 项目 模块数 内存动作 结果
2026-07-16 track-ui-xc 4353 4Gi → 6Gi 仍 OOM,后靠 SKIP_TYPE_CHECK 跳过 vue-tsc 通过
2026-08-21 market-vue 5531 6Gi → 8Gi 重跑构建通过

SKIP_TYPE_CHECK(流水线绕过 npm script 直接 pnpm exec vite build)后来按「流水线统一走 package.json 的 build 脚本」约定移除(track-ui-xc Jenkinsfile 留有注释),新流水线不再实现该开关。因此本轮的约束是:

  1. 不改业务仓库的 build 脚本(归属业务团队)
  2. 不绕过 package.json build 约定(红线)
  3. 内存上限 8Gi(集群可用上限)

三条约束同时成立时,CI 侧只剩资源调整一条路;根治必须业务团队改脚本。

四、解决方案

4.1 流水线侧(已实施并验证):内存扩到集群上限

vars/vueHelmDevopsByk8s.groovy

参数 旧值 新值 说明
node 容器 limits.memory 6Gi 8Gi 集群可用上限,无法再高
node 容器 requests.memory 2Gi 4Gi 提高调度保留值,降低被调度到剩余内存不足节点的概率;limit > request 本身仍是超卖设计
–max-old-space-size 4096 6144 每个 Node 进程各自的 V8 old space 上限(NODE_OPTIONS 无法按进程区分),为堆外原生内存、Buffer、线程栈等预留总体 cgroup 空间;实际余量取决于两进程内存峰值是否重叠

注意:这是过渡垫片不是根治。项目模块继续增长后仍会顶到 8Gi,届时没有再加内存的空间。

4.2 业务侧(根本解,待推动)

package.jsonbuild:* 脚本按推进顺序:

  • 短期:改为 vite build --mode uat(CI 跳过无拦截作用的类型检查,本地由 IDE 承担)
  • 中长期(推荐架构):类型检查独立成脚本,PR/MR 阶段跑 pnpm typecheck 拦截质量,发布构建只跑 vite build。类型检查与生产构建是两个 CI 职责,分阶段比塞进一个 build 脚本清晰:
    {
    "typecheck": "vue-tsc --noEmit",
    "build:uat": "vite build --mode uat"
    }
    
  • 若必须保留在一个脚本里:修完存量 TS 错误后改串行 vue-tsc --noEmit && vite build --mode uat

注意:不能直接把 & 改成 && 了事——当前代码有约 200 个 TS 错误,串行后 CI 会立刻全红,必须先修错误或先去掉 vue-tsc。

五、验证

共享库推送 + Jenkins 重载后重跑 market-vue:构建通过,vite 越过 rendering chunks 阶段完成打包,不再被 OOM Kill。

# 后续观测(可选):构建期间容器内存峰值,确认与 8Gi 上限的余量
kubectl top pod <market-vue 构建 Pod> -n devops

六、注意事项

exit 137 = SIGKILL,不能只凭退出码定性——容器场景最常见原因是 cgroup OOM Kill,但也可能是人为 kill -9、节点内存压力、编排系统强杀(本例耗时 5min41s 未超 15min 流水线超时,可排除超时强杀)。Killed 出现在 shell 层且无 JS 堆栈时优先怀疑内存超限,再用以下命令确认 OOMKilled

kubectl get pod <pod> -n devops -o jsonpath='{.status.containerStatuses[*].state.terminated.reason}'

Jenkins 动态 Slave Pod 构建结束即删除,取证需提前配置 podRetention 保留失败 Pod。区别于 heap out of memory(JS 异常,V8 堆内不足),两者处理方向不同。

& 的退出码陷阱——后台进程的退出状态不被 shell 等待和收集,脚本退出码只反映前台最后一条命令;CI 里放任何检查命令在 & 后面(后台)都等于没放。

  • CI 资源类故障(OOM)先分析进程行为再考虑加资源;本例加内存三轮(4→6→8Gi)都是在为同一个无效进程买单,8Gi 已到头
  • 禁止流水线绕过 package.json 的 build 脚本直接调 vite(SKIP_TYPE_CHECK 路线已按约定移除,勿再引入)
  • NODE_OPTIONS 对容器内所有 Node 进程生效,无法按进程区分堆上限
  • 大项目(4000+ 模块)接入时留意 build 脚本是否用 & 并行类型检查,接入前就该让业务侧改掉

七、参考资料

  • 关联笔记:[Jenkins Vue流水线构建异常排查-pnpm版本-husky-构建脚本拦截-OOM](./Jenkins Vue流水线构建异常排查-pnpm版本-husky-构建脚本拦截-OOM.md)
  • vite 官方 Troubleshooting(构建内存)
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇