# === 阶段1:构建 Backend === FROM python:3.11-slim AS backend-builder ARG APT_MIRROR=mirrors.tuna.tsinghua.edu.cn ARG PIP_INDEX=https://pypi.tuna.tsinghua.edu.cn/simple RUN set -ex && \ rm -f /etc/apt/sources.list && \ rm -rf /etc/apt/sources.list.d/* && \ echo "deb http://${APT_MIRROR}/debian bookworm main contrib non-free non-free-firmware" > /etc/apt/sources.list && \ echo "deb http://${APT_MIRROR}/debian bookworm-updates main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \ echo "deb http://${APT_MIRROR}/debian-security bookworm-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \ apt-get update && \ apt-get install -y --no-install-recommends ffmpeg && \ rm -rf /var/lib/apt/lists/* ENV PATH="/usr/bin:${PATH}" ENV HF_ENDPOINT=https://hf-mirror.com WORKDIR /tmp/backend # 先复制 requirements.txt 利用层缓存 COPY ./backend/requirements.txt /tmp/backend/requirements.txt RUN pip install --no-cache-dir -i ${PIP_INDEX} -r requirements.txt COPY ./backend /tmp/backend # === 阶段2:构建 Frontend === # Node 18-alpine 跑不动 Tailwind v4 / Vite 6(前者要求 Node 20+,后者推荐 Node 20+), # 升到 node:20-alpine。alpine 走 musl,pnpm 会按 lockfile 拉 *-linux-x64-musl native binary。 FROM node:20-alpine AS frontend-builder # pnpm 版本 pin 到 9 系列: # - lockfile (BillNote_frontend/pnpm-lock.yaml) 是 lockfileVersion '9.0',由 pnpm 9 生成 # - pnpm 11+ 要求 Node 22+,与 node:20 不兼容(ERR_UNKNOWN_BUILTIN_MODULE) # - 不用 @latest 避免上游 pnpm 升级悄悄破坏 CI RUN corepack enable && corepack prepare pnpm@9.15.0 --activate WORKDIR /tmp/frontend # 先复制 package.json + lockfile 利用依赖层缓存 # --frozen-lockfile 保证 CI 与本地开发依赖版本一致,杜绝 semver 漂移引入的破坏性升级 COPY ./BillNote_frontend/package.json ./BillNote_frontend/pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile COPY ./BillNote_frontend /tmp/frontend # 设置环境变量,告诉 vite.config.ts 这是 Docker 构建 ENV DOCKER_BUILD=1 RUN pnpm run build # === 阶段3:完整应用镜像 === FROM python:3.11-slim ARG APT_MIRROR=mirrors.tuna.tsinghua.edu.cn # 安装必要的运行时依赖 RUN set -ex && \ rm -f /etc/apt/sources.list && \ rm -rf /etc/apt/sources.list.d/* && \ echo "deb http://${APT_MIRROR}/debian bookworm main contrib non-free non-free-firmware" > /etc/apt/sources.list && \ echo "deb http://${APT_MIRROR}/debian bookworm-updates main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \ echo "deb http://${APT_MIRROR}/debian-security bookworm-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \ apt-get update && \ apt-get install -y --no-install-recommends ffmpeg nginx supervisor procps && \ rm -rf /var/lib/apt/lists/* ENV PATH="/usr/bin:${PATH}" ENV HF_ENDPOINT=https://hf-mirror.com ENV PYTHONUNBUFFERED=1 # 复制 Python 依赖 COPY --from=backend-builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages COPY --from=backend-builder /usr/local/bin /usr/local/bin # 复制 backend 代码 COPY ./backend /app/backend WORKDIR /app/backend # 复制前端静态文件到 nginx COPY --from=frontend-builder /tmp/frontend/dist /usr/share/nginx/html # 配置 nginx RUN rm -rf /etc/nginx/conf.d/default.conf COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf # 创建 supervisor 配置 RUN mkdir -p /var/log/supervisor COPY <