Dockerfile 3.6 KB

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