如何在Dockerfile中基于Turborepo构建Astro.build应用
问题
我的Dockerfile配置如下:
FROM node:lts-alpine AS base FROM base AS builder RUN apk update && apk add --no-cache libc6-compat # Set working directory WORKDIR /repo RUN npm install -g turbo COPY . . COPY ./apps/page/.env.docker ./apps/page/.env RUN turbo prune --scope=@myturborepo/page --docker # Add lockfile and package.json's of isolated subworkspace FROM base AS installer RUN apk update && apk add --no-cache libc6-compat WORKDIR /repo # First install the dependencies (as they change less often) COPY --from=builder /repo/out/json/ . COPY --from=builder /repo/out/pnpm-lock.yaml ./pnpm-lock.yaml RUN corepack enable RUN pnpm install --frozen-lockfile COPY --from=builder /repo/out/full/ . RUN pnpm dlx turbo run build --filter=@myturborepo/page FROM base AS production WORKDIR /app ENV NODE_ENV=production COPY --from=installer /repo/apps/page/astro.config.mjs . COPY --from=installer /repo/apps/page/package.json . COPY --from=installer /repo/apps/page/node_modules . COPY --from=installer /repo/apps/page/dist ./dist # Don't run production as root RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 astrojs USER astrojs ARG PORT=4321 ENV PORT=$PORT ENV HOST="0.0.0.0" CMD ["node", "dist/server/entry.mjs"]
参考Next.js示例编写,但运行时提示找不到已在package.json中声明的react包。查看容器内文件发现,node_modules中的符号链接指向../../node_modules,因turbo prune等操作导致该路径不存在。尝试全量复制应用构建虽能运行,但镜像体积达700MB左右,而同类Next.js镜像仅约190MB。请问遗漏了哪些步骤或操作有误?
解决方案
问题根源
- pnpm软链接失效:pnpm采用 workspace 级共享依赖策略,
apps/page/node_modules里的依赖是指向仓库根目录../../node_modules的软链接。但生产阶段只复制了apps/page/node_modules,根目录的依赖文件夹不存在,导致软链接失效,找不到react这类共享依赖。 - 镜像未精简依赖:全量复制会带上devDependencies和未用到的冗余依赖,直接导致镜像体积暴涨。
修复步骤
1. 生成独立的生产依赖目录
在installer阶段完成构建后,进入apps/page目录单独安装仅生产依赖,规避软链接问题:
# 在installer阶段的build命令后新增以下内容 WORKDIR /repo/apps/page RUN pnpm install --prod --frozen-lockfile
2. 调整生产镜像的文件复制逻辑
生产阶段直接复制installer阶段中page目录下的独立生产依赖,而非原workspace的软链接依赖:
FROM base AS production WORKDIR /app ENV NODE_ENV=production # 直接从installer的page目录复制文件,确保依赖路径有效 COPY --from=installer /repo/apps/page/astro.config.mjs . COPY --from=installer /repo/apps/page/package.json . COPY --from=installer /repo/apps/page/node_modules ./node_modules COPY --from=installer /repo/apps/page/dist ./dist # 后续用户权限配置不变 RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 astrojs USER astrojs ARG PORT=4321 ENV PORT=$PORT ENV HOST="0.0.0.0" CMD ["node", "dist/server/entry.mjs"]
3. 额外体积精简技巧(可选)
- 清理apk缓存:在每个
apk命令后追加&& rm -rf /var/cache/apk/*,减少镜像层体积。 - 用
pnpm prune --prod替代单独安装:在installer阶段构建完成后,执行pnpm prune --prod清理dev依赖,再复制到生产镜像。
完整修复后的Dockerfile
FROM node:lts-alpine AS base FROM base AS builder RUN apk update && apk add --no-cache libc6-compat && rm -rf /var/cache/apk/* WORKDIR /repo RUN npm install -g turbo COPY . . COPY ./apps/page/.env.docker ./apps/page/.env RUN turbo prune --scope=@myturborepo/page --docker FROM base AS installer RUN apk update && apk add --no-cache libc6-compat && rm -rf /var/cache/apk/* WORKDIR /repo COPY --from=builder /repo/out/json/ . COPY --from=builder /repo/out/pnpm-lock.yaml ./pnpm-lock.yaml RUN corepack enable RUN pnpm install --frozen-lockfile COPY --from=builder /repo/out/full/ . RUN pnpm dlx turbo run build --filter=@myturborepo/page # 生成page的独立生产依赖目录 WORKDIR /repo/apps/page RUN pnpm install --prod --frozen-lockfile FROM base AS production WORKDIR /app ENV NODE_ENV=production COPY --from=installer /repo/apps/page/astro.config.mjs . COPY --from=installer /repo/apps/page/package.json . COPY --from=installer /repo/apps/page/node_modules ./node_modules COPY --from=installer /repo/apps/page/dist ./dist RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 astrojs USER astrojs ARG PORT=4321 ENV PORT=$PORT ENV HOST="0.0.0.0" CMD ["node", "dist/server/entry.mjs"]
内容的提问来源于stack exchange,提问作者Arjen
相关产品推荐
相关产品推荐

