Umami 3.0.3 构建失败问题修复
Umami 3.0.3 构建失败问题修复
上个月本地部署了 umami,但是今天在修复一个 bug 时,自动构建报错了。
[00:01:36 +0ms] #14 [runner 6/12] RUN pnpm --allow-build='@prisma/engines' add npm-run-all dotenv chalk semver prisma@6.19.0 @prisma/adapter-pg@6.19.0
[00:01:36 +652ms] #14 77.12 Progress: resolved 162, reused 0, downloaded 147, added 0
[00:01:37 +1.0s] #14 78.12 Progress: resolved 185, reused 0, downloaded 182, added 0
[00:01:38 +1.0s] #14 79.12 Progress: resolved 185, reused 0, downloaded 183, added 0
[00:01:39 +999ms] #14 80.12 Progress: resolved 187, reused 0, downloaded 184, added 0
[00:01:40 +950ms] #14 81.07 Packages: +188
[00:01:40 +0ms] #14 81.07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
[00:01:40 +202ms] #14 81.12 Progress: resolved 188, reused 0, downloaded 186, added 29
[00:01:41 +849ms] #14 82.12 Progress: resolved 188, reused 0, downloaded 188, added 187
[00:01:42 +1.0s] #14 83.15 Progress: resolved 188, reused 0, downloaded 188, added 188
[00:01:43 +188ms] #14 83.15 Progress: resolved 188, reused 0, downloaded 188, added 188, done
[00:01:43 +0ms] #14 83.19 .../node_modules/@prisma/engines postinstall$ node scripts/postinstall.js
[00:01:45 +2.9s] #14 86.25 .../node_modules/@prisma/engines postinstall: Done
[00:01:46 +285ms] #14 86.53
[00:01:46 +0ms] #14 86.53 dependencies:
[00:01:46 +0ms] #14 86.53 + @prisma/adapter-pg 6.19.0 (7.8.0 is available)
[00:01:46 +0ms] #14 86.53 + chalk 5.6.2
[00:01:46 +0ms] #14 86.53 + dotenv 17.4.2
[00:01:46 +0ms] #14 86.53 + npm-run-all 4.1.5
[00:01:46 +0ms] #14 86.53 + prisma 6.19.0 (7.8.0 is available)
[00:01:46 +0ms] #14 86.53 + semver 7.8.0
[00:01:46 +0ms] #14 86.53
[00:01:46 +212ms] #14 86.60 [ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: prisma@6.19.0
[00:01:46 +0ms] #14 86.60
[00:01:46 +0ms] #14 86.60 Run "pnpm approve-builds" to pick which dependencies should be allowed to run scripts.
[00:01:46 +289ms] #14 ERROR: process "/bin/sh -c pnpm --allow-build='@prisma/engines' add npm-run-all dotenv chalk semver prisma@${PRISMA_VERSION} @prisma/adapter-pg@${PRISMA_VERSION}" did not complete successfully: exit code: 1
[00:01:53 +6.6s] ------
[00:01:53 +0ms] > [runner 6/12] RUN pnpm --allow-build='@prisma/engines' add npm-run-all dotenv chalk semver prisma@6.19.0 @prisma/adapter-pg@6.19.0:
[00:01:53 +0ms] 86.53 + @prisma/adapter-pg 6.19.0 (7.8.0 is available)
[00:01:53 +0ms] 86.53 + chalk 5.6.2
[00:01:53 +0ms] 86.53 + dotenv 17.4.2
[00:01:53 +0ms] 86.53 + npm-run-all 4.1.5
[00:01:53 +0ms] 86.53 + prisma 6.19.0 (7.8.0 is available)
[00:01:53 +0ms] 86.53 + semver 7.8.0
[00:01:53 +0ms] 86.53
[00:01:53 +0ms] 86.60 [ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: prisma@6.19.0
[00:01:53 +0ms] 86.60
[00:01:53 +0ms] 86.60 Run "pnpm approve-builds" to pick which dependencies should be allowed to run scripts.
[00:01:53 +0ms] ------
[00:01:53 +0ms] WARNING: current commit information was not captured by the build: git was not found in the system: exec: "git": executable file not found in $PATH
[00:01:53 +1ms] Dockerfile:45
[00:01:53 +0ms] --------------------
[00:01:53 +0ms] 44 | # Script dependencies
[00:01:53 +0ms] 45 | >>> RUN pnpm --allow-build='@prisma/engines' add npm-run-all dotenv chalk semver \
[00:01:53 +0ms] 46 | >>> prisma@${PRISMA_VERSION} \
[00:01:53 +0ms] 47 | >>> @prisma/adapter-pg@${PRISMA_VERSION}
[00:01:53 +0ms] 48 |
[00:01:53 +0ms] --------------------
[00:01:53 +0ms] ERROR: failed to build: failed to solve: process "/bin/sh -c pnpm --allow-build='@prisma/engines' add npm-run-all dotenv chalk semver prisma@${PRISMA_VERSION} @prisma/adapter-pg@${PRISMA_VERSION}" did not complete successfully: exit code: 1
[00:01:53 +12ms] exit code: 1, signal: -1, duration: 1.8m
CNB 自动的 AI 分析提供了几个方案,但是改了几次都没成功。最后还是在项目中直接把错误日志发给了 Codex,让它直接修改 Dockerfile。
Codex 的方案
原因是 runner 阶段执行 pnpm add 时没有复制 pnpm-workspace.yaml,pnpm 10 读不到项目里的 onlyBuiltDependencies 白名单;同时命令只允许了 @prisma/engines,导致 prisma@6.19.0 的 build script 被拦截,触发:
[ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: prisma@6.19.0
我改了 Dockerfile:8:
- deps 阶段复制
pnpm-workspace.yaml,让安装依赖时也读取 build-script 白名单 - 全局 pnpm 固定为
pnpm@10 - runner 阶段复制
pnpm-workspace.yaml - runner 阶段创建最小
package.json,然后用pnpm add -w ...安装脚本依赖,避免 workspace root 安装歧义 - 移除了只允许
@prisma/engines的--allow-build,改为使用项目已有白名单,其中已经包含prisma
修改前的 Dockerfile
ARG NODE_IMAGE_VERSION="22-alpine"
# Install dependencies only when needed
FROM node:${NODE_IMAGE_VERSION} AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm
RUN pnpm install --frozen-lockfile
# Rebuild the source code only when needed
FROM node:${NODE_IMAGE_VERSION} AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
COPY docker/middleware.ts ./src
ARG BASE_PATH
ENV BASE_PATH=$BASE_PATH
ENV NEXT_TELEMETRY_DISABLED=1
ENV DATABASE_URL="postgresql://user:pass@localhost:5432/dummy"
RUN npm run build-docker
# Production image, copy all the files and run next
FROM node:${NODE_IMAGE_VERSION} AS runner
WORKDIR /app
ARG PRISMA_VERSION="6.19.0"
ARG NODE_OPTIONS
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_OPTIONS=$NODE_OPTIONS
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
RUN set -x \
&& apk add --no-cache curl \
&& npm install -g pnpm
# Script dependencies
RUN pnpm --allow-build='@prisma/engines' add npm-run-all dotenv chalk semver \
prisma@${PRISMA_VERSION} \
@prisma/adapter-pg@${PRISMA_VERSION}
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder /app/prisma ./prisma
COPY --from=builder /app/scripts ./scripts
COPY --from=builder /app/generated ./generated
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV HOSTNAME=0.0.0.0
ENV PORT=3000
CMD ["pnpm", "start-docker"]
修改后的 Dockerfile
ARG NODE_IMAGE_VERSION="22-alpine"
# Install dependencies only when needed
FROM node:${NODE_IMAGE_VERSION} AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
RUN npm install -g pnpm@10
RUN pnpm install --frozen-lockfile
# Rebuild the source code only when needed
FROM node:${NODE_IMAGE_VERSION} AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
COPY docker/middleware.ts ./src
ARG BASE_PATH
ENV BASE_PATH=$BASE_PATH
ENV NEXT_TELEMETRY_DISABLED=1
ENV DATABASE_URL="postgresql://user:pass@localhost:5432/dummy"
RUN npm run build-docker
# Production image, copy all the files and run next
FROM node:${NODE_IMAGE_VERSION} AS runner
WORKDIR /app
ARG PRISMA_VERSION="6.19.0"
ARG NODE_OPTIONS
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_OPTIONS=$NODE_OPTIONS
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
RUN set -x \
&& apk add --no-cache curl \
&& npm install -g pnpm@10
# Script dependencies
COPY pnpm-workspace.yaml ./
RUN printf '{"name":"umami-runner","private":true,"version":"0.0.0"}\n' > package.json \
&& pnpm add -w npm-run-all dotenv chalk semver \
prisma@${PRISMA_VERSION} \
@prisma/adapter-pg@${PRISMA_VERSION}
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder /app/prisma ./prisma
COPY --from=builder /app/scripts ./scripts
COPY --from=builder /app/generated ./generated
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV HOSTNAME=0.0.0.0
ENV PORT=3000
CMD ["pnpm", "start-docker"]
改动的稍微有些多,但是这个版本已经可以正常构建了。
保守方案
由于提供的是编译的错误日志,AI 自然就根据错误日志的内容来提供解决方案。
pnpm-workspace.yaml 文件中确实是有 ignoredBuiltDependencies 和 onlyBuiltDependencies 等配置,但是这个 Dockerfile 在一个月前还是可以正常构建的。
最近一段时间发生了什么会导致这个问题呢?
由于是运行到 pnpm 命令的脚本报错的,自然就是去 npmjs 上看一下 pnpm 是否有什么改动,果然上个月发布了 11 版本。
于是尝试仅仅把两处 npm install -g pnpm 改成 npm install -g pnpm@10,然后构建就成功了。
由于本人前端并不太了解,为了避免构建脚本改动过大造成未知的影响,最后还是采用第二种比较保守的方案。
pnpm 10 和 11 的对比
问了下豆包 10 和 11 的区别:
| 维度 | pnpm 10 | pnpm 11 |
|---|---|---|
| Node.js 支持 | 18+ | 22+(仅 ESM) |
| 存储索引 | 多 JSON 文件 | 单一 SQLite(index.db) |
| 安全默认 | 宽松(无最小发布龄) | 严格(1 天延迟 + 阻止外部依赖) |
| 构建脚本控制 | 多配置分散 | 统一 allowBuilds |
| 全局安装 | 共享依赖,易冲突 | 完全隔离,独立目录 |
| 发布依赖 | 调用 npm CLI | 原生实现,无 npm 依赖 |
| 性能 | 快(硬链接) | 更快(SQLite+ 减少 I/O) |
其中 构建脚本控制 的改动大概率就是造成本次构建失败的原因。pnpm 11 统一为 allowBuilds,默认仅允许受信任包执行构建脚本,以减少恶意代码执行风险。