# ============================================ # 3D家具安装展示系统 - 优化版Dockerfile # 优先使用本地缓存,支持离线构建 # ============================================ # ============================================ # 阶段 1: 基础镜像 # ============================================ FROM node:18-alpine AS base # 使用阿里云镜像源加速(中国网络优化) RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories # 安装基础运行时依赖 RUN apk add --no-cache \ libc6-compat \ ca-certificates \ openssl3 # ============================================ # 阶段 2: 依赖安装 (deps) # ============================================ FROM base AS deps # 安装构建时依赖 RUN apk add --no-cache --virtual .build-deps \ python3 \ make \ g++ \ pkgconfig \ openssl-dev WORKDIR /app # 复制package文件 COPY package.json package-lock.json* ./ # 检查是否有本地缓存的node_modules COPY cache/node_modules* ./cache_node_modules/ 2>/dev/null || true # 配置npm使用国内镜像源 RUN npm config set registry https://registry.npmmirror.com/ # 智能安装依赖:优先使用缓存,然后网络安装 RUN set -ex && \ # 如果有本地缓存,先复制关键包 if [ -d "./cache_node_modules" ]; then \ echo "🔄 发现本地依赖缓存,正在复制..." && \ mkdir -p node_modules && \ # 复制关键包 for pkg in "@prisma" ".prisma" "prisma" "sharp" "next" "react" "react-dom" "@aws-sdk" "three" "gsap"; do \ if [ -d "./cache_node_modules/$pkg" ]; then \ echo "📦 复制缓存包: $pkg" && \ cp -r "./cache_node_modules/$pkg" "./node_modules/" || true; \ fi; \ done; \ fi && \ # 执行npm install(会跳过已存在的包) echo "📥 安装剩余依赖..." && \ npm ci --prefer-offline --no-audit || npm install --prefer-offline --no-audit # 清理构建依赖 RUN apk del .build-deps && \ npm config delete registry && \ rm -rf ./cache_node_modules # ============================================ # 阶段 3: 构建应用 (builder) # ============================================ FROM base AS builder # 构建参数 ARG DATABASE_URL="" ARG NEXTAUTH_URL="" ARG APP_PUBLIC_URL="" # 环境变量 ENV DATABASE_URL=${DATABASE_URL} ENV NEXTAUTH_URL=${NEXTAUTH_URL} ENV APP_PUBLIC_URL=${APP_PUBLIC_URL} ENV NEXT_TELEMETRY_DISABLED=1 ENV NODE_ENV=production WORKDIR /app # 安装OpenSSL(Prisma需要) RUN apk add --no-cache openssl3 # 从deps阶段复制node_modules COPY --from=deps /app/node_modules ./node_modules # 复制应用源代码 COPY . . # 复制本地Prisma引擎缓存(如果存在) COPY cache/prisma-engines* ./prisma/engine-cache/ 2>/dev/null || true # 配置Prisma引擎缓存路径 ENV PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING=1 ENV PRISMA_ENGINE_CACHE_PATH=/app/prisma/engine-cache/libquery_engine-linux-musl-openssl-3.0.x.so.node ENV PRISMA_SCHEMA_ENGINE_CACHE_PATH=/app/prisma/engine-cache/schema-engine-linux-musl-openssl-3.0.x # 智能生成Prisma Client:优先使用本地引擎 RUN set -ex && \ # 检查本地引擎缓存 if [ -f "${PRISMA_ENGINE_CACHE_PATH}" ]; then \ echo "🔧 使用本地Prisma查询引擎缓存" && \ export PRISMA_QUERY_ENGINE_LIBRARY="${PRISMA_ENGINE_CACHE_PATH}" && \ export PRISMA_CLIENT_ENGINE_TYPE=library && \ export PRISMA_CLI_QUERY_ENGINE_TYPE=library; \ else \ echo "⚠️ 本地Prisma引擎缓存不可用,将在线下载"; \ fi && \ if [ -f "${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" ]; then \ echo "🔧 使用本地Prisma schema引擎缓存" && \ export PRISMA_SCHEMA_ENGINE_BINARY="${PRISMA_SCHEMA_ENGINE_CACHE_PATH}"; \ fi && \ # 生成Prisma Client if npx prisma generate; then \ echo "✅ Prisma Client生成成功"; \ else \ echo "⚠️ 官方源失败,尝试镜像源..." && \ PRISMA_ENGINES_MIRROR="https://registry.npmmirror.com/-/binary/prisma/" npx prisma generate; \ fi # 构建Next.js应用 RUN set -ex && \ echo "🏗️ 构建Next.js应用..." && \ npm run build && \ echo "✅ 构建完成" # 验证构建产物 RUN if [ ! -f ".next/standalone/server.js" ]; then \ echo "❌ standalone输出未生成,请检查next.config.js配置" >&2 && \ exit 1; \ fi # ============================================ # 阶段 4: 生产运行 (runner) # ============================================ FROM base AS runner WORKDIR /app # 生产环境变量 ENV NODE_ENV=production ENV NEXT_TELEMETRY_DISABLED=1 ENV PORT=3000 ENV HOSTNAME="0.0.0.0" # 安装运行时依赖 RUN apk add --no-cache \ # 字体支持(3D渲染可能需要) fontconfig \ ttf-dejavu \ # 图像处理(Sharp需要) vips-dev # 创建非root用户 RUN addgroup --system --gid 1001 nodejs && \ adduser --system --uid 1001 nextjs # 复制构建产物 COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static # 复制必要文件 COPY --from=builder --chown=nextjs:nodejs /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma # 复制关键运行时模块 COPY --from=builder --chown=nextjs:nodejs /app/node_modules/.prisma ./node_modules/.prisma COPY --from=builder --chown=nextjs:nodejs /app/node_modules/@prisma ./node_modules/@prisma COPY --from=builder --chown=nextjs:nodejs /app/node_modules/prisma ./node_modules/prisma COPY --from=builder --chown=nextjs:nodejs /app/node_modules/.bin ./node_modules/.bin # 创建上传目录 RUN mkdir -p /app/uploads && \ chown -R nextjs:nodejs /app/uploads && \ chmod -R 755 /app/uploads # 切换到非root用户 USER nextjs EXPOSE 3000 # 健康检查 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:3000/api/health || exit 1 # 启动应用 CMD ["node", "server.js"]