Dockerfile 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. # syntax=docker/dockerfile:1
  2. ARG NODE_VERSION=24
  3. ARG OPT_DIR="/opt"
  4. ARG PNPM_HOME="/root/.local/share/pnpm"
  5. ##
  6. ## base — official Node.js image with pnpm + turbo
  7. ##
  8. FROM node:24-bookworm AS base
  9. ARG OPT_DIR
  10. ARG PNPM_HOME
  11. WORKDIR $OPT_DIR
  12. # Install pnpm (standalone script, no version hardcoding)
  13. RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL=/bin/sh sh -
  14. ENV PNPM_HOME=$PNPM_HOME
  15. ENV PATH="$PNPM_HOME:$PNPM_HOME/bin:$PATH"
  16. # Install turbo globally
  17. RUN pnpm add turbo --global
  18. ##
  19. ## pruner — turbo prune for Docker-optimized monorepo subset
  20. ##
  21. FROM base AS pruner
  22. ARG OPT_DIR
  23. WORKDIR $OPT_DIR
  24. COPY . .
  25. # Include @growi/pdf-converter because @growi/pdf-converter-client has a turbo
  26. # task dependency on @growi/pdf-converter#gen:swagger-spec (generates the OpenAPI
  27. # spec that orval uses to build the client). Without it, turbo cannot resolve
  28. # the cross-package task dependency in the pruned workspace.
  29. RUN turbo prune @growi/app @growi/pdf-converter --docker
  30. ##
  31. ## deps — dependency installation (layer cached when only source changes)
  32. ##
  33. FROM base AS deps
  34. ARG OPT_DIR
  35. ARG PNPM_HOME
  36. ENV PNPM_HOME=$PNPM_HOME
  37. ENV PATH="$PNPM_HOME:$PNPM_HOME/bin:$PATH"
  38. WORKDIR $OPT_DIR
  39. # Copy only package manifests and lockfile for dependency caching
  40. COPY --from=pruner $OPT_DIR/out/json/ .
  41. # Separate store path keeps the BuildKit cache mount away from the pnpm bootstrap store.
  42. # --ignore-scripts: postinstall (prisma generate) needs full source, runs in builder stage.
  43. RUN --mount=type=cache,target=/root/.pnpm-store,sharing=locked \
  44. pnpm install --frozen-lockfile --ignore-scripts --store-dir /root/.pnpm-store
  45. ##
  46. ## builder — build + produce artifacts
  47. ##
  48. FROM deps AS builder
  49. ARG OPT_DIR
  50. WORKDIR $OPT_DIR
  51. # Copy full source on top of installed dependencies
  52. COPY --from=pruner $OPT_DIR/out/full/ .
  53. # turbo prune does not include root-level config files in its output.
  54. # tsconfig.base.json is referenced by most packages via "extends": "../../tsconfig.base.json"
  55. COPY tsconfig.base.json .
  56. # Build
  57. RUN turbo run clean
  58. RUN turbo run build --filter @growi/app
  59. # Produce artifacts
  60. RUN bash apps/app/bin/assemble-prod.sh
  61. # Stage artifacts into a clean directory for COPY --from
  62. RUN mkdir -p /tmp/release/apps/app && \
  63. cp package.json /tmp/release/ && \
  64. cp -a node_modules /tmp/release/ && \
  65. cp -a apps/app/.next apps/app/config apps/app/dist apps/app/public \
  66. apps/app/resource apps/app/tmp \
  67. apps/app/package.json apps/app/node_modules \
  68. apps/app/next.config.js \
  69. /tmp/release/apps/app/ && \
  70. (cp apps/app/.env.production* /tmp/release/apps/app/ 2>/dev/null || true)
  71. ##
  72. ## release — DHI runtime (no shell, no additional binaries)
  73. ##
  74. FROM dhi.io/node:24-debian13 AS release
  75. ARG OPT_DIR
  76. ENV NODE_ENV="production"
  77. ENV appDir="$OPT_DIR/growi"
  78. # Copy artifacts from builder (no shell required)
  79. WORKDIR ${appDir}
  80. COPY --from=builder --chown=node:node /tmp/release/ ${appDir}/
  81. # Copy TypeScript entrypoint
  82. COPY --chown=node:node apps/app/docker/docker-entrypoint.ts /docker-entrypoint.ts
  83. # Switch back to root for entrypoint (it handles privilege drop)
  84. USER root
  85. WORKDIR ${appDir}/apps/app
  86. # OCI standard labels
  87. LABEL org.opencontainers.image.source="https://github.com/weseek/growi"
  88. LABEL org.opencontainers.image.title="GROWI"
  89. LABEL org.opencontainers.image.description="Team collaboration wiki using Markdown"
  90. LABEL org.opencontainers.image.vendor="WESEEK, Inc."
  91. VOLUME /data
  92. EXPOSE 3000
  93. ENTRYPOINT ["node", "/docker-entrypoint.ts"]