Dockerfile 3.7 KB

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