Docker部署turborepo(api+web)时遇权限错误:无法创建/nonexistent目录
Turborepo容器化权限错误(EACCES: permission denied, mkdir '/nonexistent')解决
问题描述
尝试将包含API和Web应用的Turborepo进行Docker容器化,参考官方示例编写对应的Dockerfile后,运行容器时出现如下权限错误:
Attaching to api, web api | Internal Error: EACCES: permission denied, mkdir '/nonexistent' api | Error: EACCES: permission denied, mkdir '/nonexistent' api exited with code 1 web | Internal Error: EACCES: permission denied, mkdir '/nonexistent' web | Error: EACCES: permission denied, mkdir '/nonexistent' web exited with code 1
提供的文件内容
Web服务Dockerfile
FROM node:18 AS base RUN npm install turbo -g RUN corepack enable # This Dockerfile is copy-pasted into our main docs at /docs/handbook/deploying-with-docker. # Make sure you update both files! FROM base AS builder # 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 # RUN apk update # Set working directory WORKDIR /app COPY . . RUN turbo prune web --docker # Add lockfile and package.json's of isolated subworkspace FROM base AS installer # RUN apk add --no-cache libc6-compat # RUN apk update WORKDIR /app # First install the dependencies (as they change less often) COPY .gitignore .gitignore COPY --from=builder /app/out/json/ . COPY --from=builder /app/out/pnpm-lock.yaml ./pnpm-lock.yaml COPY --from=builder /app/out/pnpm-workspace.yaml ./pnpm-workspace.yaml RUN pnpm install # Build the project COPY --from=builder /app/out/full/ . COPY turbo.json turbo.json # Uncomment and use build args to enable remote caching # ARG TURBO_TEAM # ENV TURBO_TEAM=$TURBO_TEAM # ARG TURBO_TOKEN # ENV TURBO_TOKEN=$TURBO_TOKEN RUN pnpm prettier:fix RUN turbo build --filter=web... FROM base AS runner WORKDIR /app # Don't run production as root RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs USER nextjs COPY --from=installer /app/apps/web/next.config.js . COPY --from=installer /app/apps/web/package.json . # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static COPY --from=installer --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public USER nextjs CMD ["pnpm", "start"]
API服务Dockerfile
FROM node:18 AS base RUN npm install turbo -g RUN corepack enable # The web Dockerfile is copy-pasted into our main docs at /docs/handbook/deploying-with-docker. # Make sure you update this Dockerfile, the Dockerfile in the web workspace and copy that over to Dockerfile in the docs. FROM base AS builder # 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 # RUN apk update # Set working directory WORKDIR /app COPY . . RUN turbo prune api --docker # Add lockfile and package.json's of isolated subworkspace FROM base AS installer # RUN apk add --no-cache libc6-compat # RUN apk update WORKDIR /app # First install dependencies (as they change less often) COPY .gitignore .gitignore COPY --from=builder /app/out/json/ . COPY --from=builder /app/out/pnpm-lock.yaml ./pnpm-lock.yaml COPY --from=builder /app/out/pnpm-workspace.yaml ./pnpm-workspace.yaml RUN pnpm install # Build the project and its dependencies COPY --from=builder /app/out/full/ . COPY turbo.json turbo.json # Uncomment and use build args to enable remote caching # ARG TURBO_TEAM # ENV TURBO_TEAM=$TURBO_TEAM # ARG TURBO_TOKEN # ENV TURBO_TOKEN=$TURBO_TOKEN RUN turbo build --filter=api... FROM base AS runner WORKDIR /app # Don't run production as root RUN addgroup --system --gid 1001 expressjs RUN adduser --system --uid 1001 expressjs USER expressjs COPY --from=installer --chown=expressjs:expressjs /app . USER expressjs CMD ["pnpm", "start"]
项目结构
├── apps ├── docker-compose.yml ├── docs ├── FUNDING.json ├── LICENSE ├── node_modules ├── package.json ├── packages ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── prettier.config.js ├── script └── turbo.json
apps/ ├── api │ ├── dist │ ├── Dockerfile │ ├── index.html │ ├── node_modules │ ├── package.json │ ├── src │ └── tsconfig.json ├── README.md └── web ├── Dockerfile ├── next.config.js ├── next-env.d.ts ├── node_modules ├── package.json ├── postcss.config.js ├── public ├── script ├── src ├── tailwind.config.js ├── tsconfig.json └── tsconfig.tsbuildinfo
解决方法
错误原因
/nonexistent是pnpm在非root用户运行时默认尝试使用的缓存目录,但该目录不存在且非root用户无权限创建。同时,当前Dockerfile存在工作目录不匹配、文件复制不完整的问题,导致启动命令无法正确执行。
Web服务Dockerfile修复
修改runner阶段内容,解决缓存目录权限并确保启动路径正确:
FROM base AS runner WORKDIR /app # 创建pnpm缓存目录并赋予当前用户权限 RUN mkdir -p /home/nextjs/.pnpm-store && chown -R nextjs:nodejs /home/nextjs/.pnpm-store ENV PNPM_HOME="/home/nextjs/.pnpm-store" ENV PATH="$PNPM_HOME:$PATH" # 创建非root用户 RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs USER nextjs # 复制完整的Web应用构建产物 COPY --from=installer --chown=nextjs:nodejs /app/apps/web ./apps/web # 切换到Web应用目录启动服务 WORKDIR /app/apps/web CMD ["pnpm", "start"]
API服务Dockerfile修复
同样修改runner阶段:
FROM base AS runner WORKDIR /app # 创建pnpm缓存目录并赋予当前用户权限 RUN mkdir -p /home/expressjs/.pnpm-store && chown -R expressjs:expressjs /home/expressjs/.pnpm-store ENV PNPM_HOME="/home/expressjs/.pnpm-store" ENV PATH="$PNPM_HOME:$PATH" # 创建非root用户 RUN addgroup --system --gid 1001 expressjs RUN adduser --system --uid 1001 expressjs USER expressjs # 复制完整的API应用构建产物 COPY --from=installer --chown=expressjs:expressjs /app/apps/api ./apps/api # 切换到API应用目录启动服务 WORKDIR /app/apps/api CMD ["pnpm", "start"]
额外注意事项
- 确保每个应用的
package.json中start命令正确:Web应用应为next start,API应用应为node dist/index.js(根据实际编译产物路径调整) - 避免复制整个
/app目录到runner阶段,仅复制对应应用的内容,减少镜像体积同时避免权限混乱 - 若使用Docker Compose,确保容器挂载的卷(如果有)权限配置正确
内容的提问来源于stack exchange,提问作者chaso
相关产品推荐
相关产品推荐

