Dockerfile
2,894 bytes
| 1 | # syntax=docker/dockerfile:1 |
|---|---|
| 2 | |
| 3 | # --------------------------------------------------------------------------- |
| 4 | # Roundtable — multi-stage build producing a standalone Next.js server image. |
| 5 | # Base is debian-slim (not alpine) so the Prisma engine "just works". |
| 6 | # --------------------------------------------------------------------------- |
| 7 | FROM node:20-bookworm-slim AS base |
| 8 | ENV PNPM_HOME=/pnpm |
| 9 | ENV PATH=$PNPM_HOME:$PATH |
| 10 | RUN corepack enable |
| 11 | RUN apt-get update \ |
| 12 | && apt-get install -y --no-install-recommends openssl ca-certificates \ |
| 13 | && rm -rf /var/lib/apt/lists/* |
| 14 | WORKDIR /app |
| 15 | |
| 16 | # --- Install dependencies (cached on the lockfile) ------------------------- |
| 17 | FROM base AS deps |
| 18 | COPY package.json pnpm-lock.yaml ./ |
| 19 | RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile |
| 20 | |
| 21 | # --- Build the app (standalone output) ------------------------------------- |
| 22 | FROM base AS builder |
| 23 | COPY --from=deps /app/node_modules ./node_modules |
| 24 | COPY . . |
| 25 | ENV NEXT_TELEMETRY_DISABLED=1 |
| 26 | # No runtime secrets needed to compile; env is validated at runtime instead. |
| 27 | ENV SKIP_ENV_VALIDATION=1 |
| 28 | # Produce the self-contained standalone server for the runtime stage. |
| 29 | ENV BUILD_STANDALONE=1 |
| 30 | RUN pnpm prisma generate |
| 31 | RUN pnpm build |
| 32 | |
| 33 | # --- Prisma CLI for the entrypoint ---------------------------------------- |
| 34 | # The entrypoint applies the schema at boot, which needs the CLI and its whole |
| 35 | # dependency tree. Lifting that out of the pnpm store means chasing symlinks |
| 36 | # through one store directory per transitive package, so it is installed once |
| 37 | # more here with npm, whose flat layout copies as a single directory. |
| 38 | # |
| 39 | # The version is read from package.json, so it can never drift from the client |
| 40 | # the app was generated against. |
| 41 | FROM base AS prismacli |
| 42 | WORKDIR /prisma-cli |
| 43 | COPY package.json ./ |
| 44 | RUN npm install --omit=dev --no-package-lock \ |
| 45 | "prisma@$(node -p "require('./package.json').devDependencies.prisma")" |
| 46 | |
| 47 | # --- Runtime image --------------------------------------------------------- |
| 48 | FROM base AS runner |
| 49 | ENV NODE_ENV=production |
| 50 | ENV NEXT_TELEMETRY_DISABLED=1 |
| 51 | ENV PORT=3000 |
| 52 | ENV HOSTNAME=0.0.0.0 |
| 53 | |
| 54 | RUN groupadd -g 1001 nodejs && useradd -u 1001 -g nodejs -m nextjs |
| 55 | |
| 56 | # Standalone server + assets. |
| 57 | COPY --from=builder /app/public ./public |
| 58 | COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ |
| 59 | COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static |
| 60 | |
| 61 | # Schema plus the CLI that applies it at boot. The CLI stays outside |
| 62 | # ./node_modules on purpose: a second @prisma directory beside the standalone |
| 63 | # bundle would shadow the generated client Next already traced into it, and the |
| 64 | # app would start against an empty client. |
| 65 | COPY --from=builder /app/prisma ./prisma |
| 66 | COPY --from=prismacli /prisma-cli/node_modules /prisma-cli/node_modules |
| 67 | |
| 68 | COPY --chown=nextjs:nodejs docker/entrypoint.sh ./entrypoint.sh |
| 69 | RUN chmod +x ./entrypoint.sh |
| 70 | |
| 71 | USER nextjs |
| 72 | EXPOSE 3000 |
| 73 | CMD ["./entrypoint.sh"] |
| 74 | |