第三篇:拯救 OOM 与构建中断:Next.js 在 Docker 中的静态生成(SSG)避坑指南
摘要 :跨过了依赖和编译的鸿沟,next build 跑到了 14/30 时突然 Worker 崩溃退出。本文将揭示 Next.js 在容器环境中做静态页面预渲染(SSG)时,面临的数据库连接陷阱与内存爆炸问题。

1. 现象:诡异的 Worker 退出
bash
Generating static pages using 15 workers (14/30)
⨯ Next.js build worker exited with code: 1 and signal: null
The command '/bin/sh -c npm run build' returned a non-zero code: 1
注意两个细节:进度卡在 14/30,且报错是 Worker exited with code: 1 and signal: null。这绝对不是代码语法错误,而是运行时环境崩溃。
2. 坑位一:SSG 与容器网络隔离的死锁
场景还原 :报错的页面是 /server-test,这个页面里包含了 prisma.user.findMany() 这样的数据库查询代码。
原理剖析 :
Next.js 默认会尝试静态生成(SSG)所有页面。在执行 next build 时,它会在 Docker 容器内真实地执行这些页面组件的代码 来生成 HTML。
但是!Docker 的 Build 阶段是网络隔离的。容器里根本没有配置数据库的连接地址(即使配了,也连不上宿主机或云数据库),导致 Prisma 查询超时或直接抛出连接异常,进而导致 Worker 进程崩溃。
解决方案:对于需要动态数据的页面,坚决拒绝 SSG。
typescript
// src/app/server-test/page.tsx
export const dynamic = 'force-dynamic' // 强制标记为动态渲染(SSR),构建时不执行
3. 坑位二:高并发 Worker 导致的隐形 OOM
场景还原 :即使解决了数据库问题,在高配服务器上(比如 8核16G)构建,依然可能遇到 signal: null(通常是 SIGKILL,即 OOM 被杀)。
原理剖析 :
日志显示 using 15 workers。Next.js 为了加速构建,会根据 CPU 核心数启动大量 Worker 并发渲染页面。每个 Worker 都是一个独立的 Node.js V8 引擎实例。
如果你有大量页面,或者某些页面组件非常庞大(引入了复杂的图表库等),15 个 Worker 瞬间吃满内存,触发操作系统的 OOM Killer,直接干掉进程,连 GC 的机会都不给。
解决方案:限制 Worker 数量,用时间换空间。
dockerfile
ENV NODE_OPTIONS="--max-old-space-size=8192"
# 强制限制构建并发数为 2,虽然慢,但极其稳定
ENV NEXT_WORKER_THREADS=2
4. 总结:构建高可用 Next.js Docker 镜像的四条军规
- 禁止在构建期请求外网:字体、图片等静态资源必须本地化或走内部代理。
- 不要在依赖安装阶段自作聪明 :别用
--omit=dev,信任standalone的打包能力。 - 不要迷信新版构建工具:Turbopack 很快,但在处理 CSS Modules 新规范时仍有瑕疵,准备好备用方案(如文件级拷贝)。
- 明确页面的渲染模式 :凡是依赖后端状态(DB、Cookie、Headers)的页面,必须加
dynamic = 'force-dynamic',否则在 Docker 构建阶段必死无疑。