flnxi-Wu/Dockerfile
WuYongJie f646b71813
Some checks failed
CI Check / check (push) Has been cancelled
chore: 初始化本地仓库并同步最近改动
2025-11-18 17:50:16 +08:00

202 lines
6.9 KiB
Docker
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ============================================
# 阶段 1: 基础镜像
# ============================================
FROM node:18-alpine AS base
# 使用阿里云镜像源加速(所有阶段统一配置)
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
# ============================================
# 阶段 2: 依赖安装 (deps)
# ============================================
FROM base AS deps
# 安装构建时依赖(使用虚拟包,便于后续清理)
# 注意:cairo/pango 主要用于 canvas(可选依赖),sharp 不需要这些
# 如果 canvas 安装失败,应用仍可使用 ag-psd 的 fallback 方法
RUN apk add --no-cache --virtual .build-deps \
libc6-compat \
openssl3 \
openssl-dev \
# Canvas 相关依赖(可选,用于 ag-psd 的 canvas 支持)
cairo \
cairo-dev \
pango \
pango-dev \
jpeg-dev \
giflib-dev \
librsvg \
pixman-dev \
# 编译工具(用于编译原生模块)
python3 \
make \
g++ \
pkgconfig
WORKDIR /app
# 复制依赖文件(放在前面以利用 Docker 缓存)
COPY package.json package-lock.json* ./
# 配置 npm(仅在构建阶段,使用国内镜像源加速)
# 注意:这些配置不会进入最终镜像
# sharp 的二进制文件通过环境变量配置,而不是 npm config
RUN npm config set registry https://registry.npmmirror.com/
# 安装所有依赖(包括 devDependencies,构建时需要)
# 使用缓存挂载加速 npm install(需要 BuildKit: DOCKER_BUILDKIT=1)
# 注意:canvas 是可选依赖,如果安装失败,npm ci 不会失败,但会警告
# 如果 npm ci 失败(通常是 package-lock.json 问题),构建会停止
RUN --mount=type=cache,target=/root/.npm \
npm ci --prefer-offline --no-audit
# 清理构建依赖和 npm 配置(保留运行时所需的库)
RUN apk del .build-deps && \
# 清理 npm 配置(不在运行镜像中保留)
npm config delete registry && \
# 只保留运行时库
apk add --no-cache \
libc6-compat \
ca-certificates \
openssl3
# ============================================
# 阶段 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
WORKDIR /app
# 安装 OpenSSL 3(让 Prisma 能够检测到,消除警告)
RUN apk add --no-cache openssl3
# 设置构建环境变量
ENV NODE_ENV=production
# 从 deps 阶段复制 node_modules(包含所有依赖)
COPY --from=deps /app/node_modules ./node_modules
# 复制应用源代码(放在后面,因为源代码变化更频繁)
# 使用 .dockerignore 排除不需要的文件
COPY . .
# 生成 Prisma Client(需要完整的 node_modules)
# 注意:binaryTargets 已指定 linux-musl-openssl-3.0.x,即使检测失败也会使用正确的二进制
RUN npx prisma generate
# 验证关键依赖是否已安装
RUN if [ ! -d "node_modules/.prisma" ]; then \
echo "错误: Prisma Client 未生成" >&2 && exit 1; \
fi
# 构建 Next.js 应用(standalone 模式)
# 允许构建时出现预渲染错误(这些页面会在运行时动态渲染)
RUN npm run build || (echo "构建完成,但部分页面预渲染失败(这是预期的,这些页面将在运行时动态渲染)" && exit 0)
# 验证构建产物
RUN if [ ! -f ".next/standalone/server.js" ]; then \
echo "错误: standalone 输出未生成,请检查 next.config.js 中的 output: 'standalone'" >&2 && exit 1; \
fi
# 为可选模块创建占位符(确保 COPY 不会失败)
# 如果 canvas 未安装,创建一个空占位符目录
RUN if [ ! -d "node_modules/canvas" ]; then \
echo "Canvas 未安装,创建占位符目录" && \
mkdir -p node_modules/canvas && \
echo '{"name":"canvas-placeholder"}' > node_modules/canvas/package.json; \
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"
# 只安装运行时必需的库(最小化镜像大小)
# sharp 只需要基本的系统库,不需要 cairo/pango
# 但如果 canvas 被安装(可选依赖),则需要这些库
RUN apk add --no-cache \
libc6-compat \
ca-certificates \
openssl3 \
# Canvas 运行时库(如果 canvas 被安装则需要,否则可忽略)
# 注意:如果 canvas 未安装,这些库不会造成问题,只是占用一点空间
cairo \
pango \
jpeg \
giflib \
librsvg \
pixman \
# 字体支持(canvas 渲染中文时需要)
fontconfig \
ttf-dejavu
# 创建非 root 用户
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# 从 builder 阶段复制构建产物
# standalone 输出包含所有必需的依赖和 server.js
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# 复制必要的额外文件
# 1. public 目录(静态资源)
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
# 2. Prisma schema 和迁移文件(运行时可能需要)
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma
# 3. lib 目录(包含 configLoader 等运行时模块)
COPY --from=builder --chown=nextjs:nodejs /app/lib ./lib
# 4. 补充关键模块(standalone 输出可能未完整包含)
# 复制 Prisma Client(必需)
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/.prisma ./node_modules/.prisma
# 复制 Prisma 包,确保运行时存在 @prisma/client 及其生成器
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/@prisma ./node_modules/@prisma
# 复制 Canvas 模块(可选依赖)
# 如果 canvas 未安装,builder 阶段已创建占位符,所以这个 COPY 不会失败
# 在运行时,如果 canvas 是占位符,应用会使用 ag-psd 的 fallback 方法
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/canvas ./node_modules/canvas
# 复制 ag-psd 模块
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/ag-psd ./node_modules/ag-psd
# 清理占位符(如果 canvas 是占位符,删除它)
RUN if [ -f "./node_modules/canvas/package.json" ] && grep -q "canvas-placeholder" ./node_modules/canvas/package.json 2>/dev/null; then \
echo "Canvas 未安装,清理占位符,使用 ag-psd fallback" && \
rm -rf ./node_modules/canvas; \
fi
# 创建上传目录并设置权限
RUN mkdir -p /app/uploads && \
chown -R nextjs:nodejs /app/uploads && \
chmod -R 755 /app/uploads
# 切换到非 root 用户
USER nextjs
EXPOSE 3000
# 使用 standalone 输出的 server.js
CMD ["node", "server.js"]