From 7591f001c1fd4f5b1ffdd74ebb15232c5a862280 Mon Sep 17 00:00:00 2001 From: Chever John Date: Thu, 21 Aug 2025 16:47:05 +0800 Subject: [PATCH] build(docker): build frontend and server inside container; remove host build deps --- docker/Dockerfile.dev | 39 +++++++++++++++++++++++------ docker/Dockerfile.prod | 47 ++++++++++++++++++++++++++++------- docker/docker-compose.dev.yml | 1 - scripts/dev-up.sh | 12 ++------- scripts/prod-build.sh | 12 ++------- scripts/prod-up.sh | 7 ++---- 6 files changed, 75 insertions(+), 43 deletions(-) diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev index 53fcdd9..5b08a2b 100644 --- a/docker/Dockerfile.dev +++ b/docker/Dockerfile.dev @@ -1,19 +1,42 @@ -FROM node:20-bullseye-slim +###### +# Multi-stage dev image that builds frontend and server inside container +###### + +# ---------- Frontend builder ---------- +FROM node:20-bullseye-slim AS frontend-builder +ENV npm_config_registry=https://registry.npmmirror.com +WORKDIR /app +COPY package.json ./ +COPY pnpm-lock.yaml ./ +RUN npm install --no-audit --no-fund +COPY . . +RUN npm run build + +# ---------- Server builder ---------- +FROM node:20-bullseye-slim AS server-builder ENV npm_config_registry=https://registry.npmmirror.com ENV npm_config_build_from_source=true - -# Build prerequisites for native modules (better-sqlite3) RUN apt-get update \ && apt-get install -y --no-install-recommends python3 make g++ \ && rm -rf /var/lib/apt/lists/* +WORKDIR /app/server +COPY server/package.json ./package.json +RUN npm install --no-audit --no-fund --build-from-source +COPY server/tsconfig.json ./tsconfig.json +COPY server/src ./src +RUN npm run build +# ---------- Runtime ---------- +FROM node:20-bullseye-slim +ENV npm_config_registry=https://registry.npmmirror.com WORKDIR /app +ENV PORT=3004 +ENV DB_PATH=/data/purchase.db -# Use host-built frontend; only run server here -COPY server/package.json server/tsconfig.json ./server/ -COPY server/src ./server/src - -RUN cd server && npm install --build-from-source && npm run build +COPY --from=server-builder /app/server/dist ./server/dist +COPY --from=server-builder /app/server/node_modules ./server/node_modules +COPY server/package.json ./server/package.json +COPY --from=frontend-builder /app/dist ./frontend EXPOSE 3004 CMD ["node", "server/dist/index.js"] diff --git a/docker/Dockerfile.prod b/docker/Dockerfile.prod index d45b008..14149c4 100644 --- a/docker/Dockerfile.prod +++ b/docker/Dockerfile.prod @@ -1,4 +1,21 @@ -FROM node:20-bullseye-slim +###### +# Multi-stage production image that builds EVERYTHING inside containers +###### + +# ---------- Frontend builder ---------- +FROM node:20-bullseye-slim AS frontend-builder +ENV npm_config_registry=https://registry.npmmirror.com +WORKDIR /app + +# Install frontend deps and build (root project) +COPY package.json ./ +COPY pnpm-lock.yaml ./ +RUN npm install --no-audit --no-fund +COPY . . +RUN npm run build + +# ---------- Server builder ---------- +FROM node:20-bullseye-slim AS server-builder ENV npm_config_registry=https://registry.npmmirror.com ENV npm_config_build_from_source=true @@ -7,19 +24,31 @@ RUN apt-get update \ && apt-get install -y --no-install-recommends python3 make g++ \ && rm -rf /var/lib/apt/lists/* +WORKDIR /app/server +COPY server/package.json ./package.json +RUN npm install --no-audit --no-fund --build-from-source +COPY server/tsconfig.json ./tsconfig.json +COPY server/src ./src +RUN npm run build +# Prune dev deps after build; keep native modules compiled for runtime +RUN npm prune --omit=dev + +# ---------- Runtime ---------- +FROM node:20-bullseye-slim +ENV npm_config_registry=https://registry.npmmirror.com WORKDIR /app -# Install server deps in container (native modules match linux/amd64) -COPY server/package.json ./server/package.json -RUN cd server && npm install --omit=dev --build-from-source - -# Copy server runtime and prebuilt frontend from host -COPY server/dist ./server/dist -COPY dist ./frontend - ENV PORT=3004 ENV DB_PATH=/data/purchase.db +# Server runtime +COPY --from=server-builder /app/server/dist ./server/dist +COPY --from=server-builder /app/server/node_modules ./server/node_modules +COPY server/package.json ./server/package.json + +# Prebuilt frontend (from frontend-builder) +COPY --from=frontend-builder /app/dist ./frontend + EXPOSE 3004 CMD ["node", "server/dist/index.js"] diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 3703aad..f9edb4c 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -11,7 +11,6 @@ services: - DB_PATH=/data/purchase.db volumes: - dm_db:/data - - ../dist:/app/frontend:ro restart: unless-stopped volumes: diff --git a/scripts/dev-up.sh b/scripts/dev-up.sh index 1114eb1..d67d6bd 100644 --- a/scripts/dev-up.sh +++ b/scripts/dev-up.sh @@ -24,20 +24,12 @@ fi echo "- 宿主机: ${HOST_OS}/${HOST_ARCH}" echo "- 容器镜像平台: ${DOCKER_PLATFORM} (Docker 仅支持 linux/*;可通过 DOCKER_PLATFORM 覆盖)" -echo "- 将使用外部构建的前端 (dist/)" +echo "- 在容器内编译前端与后端" SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) ROOT_DIR=$(cd "$SCRIPT_DIR/.." && pwd) -if [ ! -d "$ROOT_DIR/node_modules" ]; then - echo "[提示] 未检测到 node_modules,将安装依赖 (pnpm install)" - (cd "$ROOT_DIR" && pnpm install) -fi - -if [ ! -d "$ROOT_DIR/dist" ]; then - echo "[提示] 未检测到 dist/,将进行前端构建 (pnpm build)" - (cd "$ROOT_DIR" && pnpm run build) -fi +# 不再依赖宿主机 node_modules 或 dist,全部在容器内完成 echo "[步骤] 启动 Docker Compose (开发)" (cd "$ROOT_DIR/docker" && DOCKER_PLATFORM=${DOCKER_PLATFORM} docker compose -f docker-compose.dev.yml up -d --build) diff --git a/scripts/prod-build.sh b/scripts/prod-build.sh index a9f7dd2..ef7b319 100644 --- a/scripts/prod-build.sh +++ b/scripts/prod-build.sh @@ -2,21 +2,13 @@ set -euo pipefail echo "[Dream-Machine] 生产镜像构建" -echo "- 环境要求: 前端包 dist/ 已在宿主机构建完成" +echo "- 在容器内编译前端与后端" echo "- 目标平台: linux/amd64" SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) ROOT_DIR=$(cd "$SCRIPT_DIR/.." && pwd) -if [ ! -d "$ROOT_DIR/dist" ]; then - echo "[错误] 未检测到 dist/。请先在宿主机运行: pnpm run build" - exit 1 -fi - -echo "[步骤] 安装并构建后端 (宿主机)" -(cd "$ROOT_DIR/server" && pnpm install && pnpm run build) - -echo "[步骤] 构建生产镜像 (仅打包、禁止在容器内构建)" +echo "[步骤] 构建生产镜像 (容器内完成所有构建)" (cd "$ROOT_DIR/docker" && docker buildx build --platform linux/amd64 -f Dockerfile.prod -t dm-purchase-api:prod ..) echo "[完成] 镜像: dm-purchase-api:prod" diff --git a/scripts/prod-up.sh b/scripts/prod-up.sh index 1413573..e424a18 100644 --- a/scripts/prod-up.sh +++ b/scripts/prod-up.sh @@ -3,15 +3,12 @@ set -euo pipefail echo "[Dream-Machine] 生产环境启动" echo "- 目标平台: linux/amd64" -echo "- 将使用宿主机构建的前端 (dist/)" +echo "- 在容器内编译前端与后端" SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) ROOT_DIR=$(cd "$SCRIPT_DIR/.." && pwd) -if [ ! -d "$ROOT_DIR/dist" ]; then - echo "[错误] 未检测到 dist/。请先在宿主机运行: pnpm run build" - exit 1 -fi +# 不再依赖宿主机预构建,改为 Dockerfile 内构建 echo "[步骤] 启动 Docker Compose (生产)" (cd "$ROOT_DIR/docker" && docker compose -f docker-compose.prod.yml up -d --build)