# BASE_REGISTRY 默认 docker.io;国内拉不到可换镜像源: # docker build --build-arg BASE_REGISTRY=docker.m.daocloud.io -f Dockerfile.complete . ARG BASE_REGISTRY=docker.io # === 阶段1:构建 Backend === FROM ${BASE_REGISTRY}/library/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。 ARG BASE_REGISTRY=docker.io FROM ${BASE_REGISTRY}/library/node:20-alpine AS frontend-builder # 可由发布 workflow 从 git tag 注入,用于前端 About 页展示版本;未传时由 Vite 回退读取 tauri.conf.json。 ARG VITE_APP_VERSION= ENV VITE_APP_VERSION=${VITE_APP_VERSION} # 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:完整应用镜像 === ARG BASE_REGISTRY=docker.io FROM ${BASE_REGISTRY}/library/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 配置 # 关键点:supervisord 默认 *不* 把自己的环境变量传给子进程。 # 在 [supervisord] 块用 environment= 设兜底默认值;在 [program:backend] 用 # %(ENV_*)s 显式引用,等价于「把 host 通过 docker run -e 或 env_file 传进来的 # 变量再透传给 python main.py」。漏掉这一步就是用户「改 .env 没反应」的根因。 # /app/backend/data 用于持久化数据库与笔记(见下方 DATABASE_URL / NOTE_OUTPUT_DIR), # 预建好目录,避免不挂卷启动时 sqlite 因父目录不存在而创建库失败。 RUN mkdir -p /var/log/supervisor /app/backend/data COPY <