250d4355b9
P5-prep Task 1(docs/plans/2026-09-21-P5-准备件.md): - docker/server.Dockerfile:单镜像 photo-live-server 多角色(api-cn/api-ov/ worker/sync/migrate-deploy/seed-admin,entrypoint.sh 分发;migrate-deploy 支持 cn|ov|all 区域参数)。三阶段:全量 install(锁文件冻结)→ prisma generate 双库 + 逐包构建;--prod 依赖层;runtime=node:20-alpine+openssl/curl + 全局 prisma@5.22.0(对齐锁文件)+ 双库 client 镜像内重建(db-cn 落 pnpm store .prisma、db-ov 落包内 generated/)。sharp 走 musl 预编译验证通过。 - docker/web.Dockerfile + infra/deploy/nginx.conf.template:photo-live-web (nginx:alpine + envsubst 模板)。viewer(/,history 回退) + admin(/admin/, hash 路由) + /v1 反代 API_UPSTREAM(含 /v1/realtime WS 升级)+ /assets/、/admin/assets/、/embed/v1/ immutable 长缓存(admin assets 的 alias 前缀剥除坑已实测修复)。VITE_* 为构建期参数(VIEWER_BASE/ EMBED_ORIGIN 随域名构建传入)。 - infra/deploy/docker-compose.cn.yml / -ov.yml:cn=api-cn+worker+sync+web, ov=api-ov+web-ov(核实架构:sync 仅 cn 侧,inbox/emergency 内嵌 api-ov, 无 ov 侧 sync 进程);健康检查 /v1/health、unless-stopped、json-file 10m×3、外部 1panel-network 复用 1Panel MySQL/Redis、SERVER_IMAGE/ WEB_IMAGE 环境变量化镜像 tag(回滚杠杆)。 - .env.production.example-cn/-ov:生产变量全量清单(cn 25 键/ov 24 键, DB/Redis/OSS/SYNC/AUTH/限速/域名分组注释,源自 services+packages process.env 全量审计);.gitignore 放行 example,真实 .env.production-* 永不入库。 - infra/deploy/README-1Panel.md:镜像导入双路径(save tar 导入 / 仓库 pull)、 MySQL 建库授权 SQL(utf8mb4_0900_bin,<8.0.30 回退 utf8mb4_bin——D12)、 Redis 连接、1Panel 编排、OpenResty 反代+证书、migrate-deploy 一次性容器、 首次部署顺序(DB→迁移→ov 栈→cn 栈→seed→冒烟)。 - 根 package.json pnpm.onlyBuiltDependencies 增补 sharp/prisma/@prisma/ engines/@prisma/client(镜像构建所需 install 脚本白名单)。 本地验证:两镜像构建成功(server 988MB / web 97.7MB);compose config 校验 通过;server 镜像内逐服务 require(sharp/argon2/双 Prisma client/bullmq/ ioredis)与双引擎 so.node、migrate-deploy 角色、无 .env 泄漏均实测;web 镜像 容器实测路由(viewer 回退/admin 子路径/assets 与 embed immutable/WS 代理路径 502 语义)全通过。未起真实栈(无真实 DB,符合准备件边界)。 Co-Authored-By: Claude Code <noreply@anthropic.com>
114 lines
6.3 KiB
Docker
114 lines
6.3 KiB
Docker
# syntax=docker/dockerfile:1
|
||
# docker/server.Dockerfile —— photo-live-server 单镜像多角色(P5-prep Task 1)。
|
||
# 决策(docs/plans/2026-09-21-P5-准备件.md Task 1):单镜像 photo-live-server,
|
||
# CMD 区分 api-cn / api-ov / worker / sync / migrate-deploy / seed-admin,
|
||
# 减少 1Panel 维护面(一个 tar 导入,多角色复用)。
|
||
#
|
||
# 构建:docker build -f docker/server.Dockerfile -t photo-live-server:<tag> .
|
||
# <tag> = git short sha + 日期(见 infra/deploy/README-1Panel.md 版本约定)。
|
||
#
|
||
# 阶段:
|
||
# build 全量 install(锁文件冻结)→ prisma generate 双库 → 逐包 tsc 构建
|
||
# (显式依赖序代替 turbo:镜像内无需 turbo 二进制,链路更短更确定)
|
||
# prod-deps 仅生产依赖的 workspace install(--prod,供 runtime 复用清单与结构)
|
||
# runtime node:20-alpine + openssl(prisma musl 引擎依赖)/curl(healthcheck)
|
||
# + 全局 prisma@5.22.0(migrate-deploy 角色;版本对齐 pnpm-lock.yaml)
|
||
# + prisma generate 双库(db-cn 生成到 pnpm store 内 .prisma,db-ov
|
||
# 生成到包内 generated/——运行时本阶段重建,避免拷贝易碎的 store 深路径)
|
||
#
|
||
# sharp 在 alpine(musl) 的预编译二进制随 optionalDependencies 分发(0.33+ 无需
|
||
# 编译);根 package.json pnpm.onlyBuiltDependencies 已放行其 install 脚本。若
|
||
# 未来 sharp 版本在 musl 失败,回退方案:两阶段 base 换 node:20-slim(debian,
|
||
# glibc 预编译),无需其它改动。
|
||
|
||
# ── 阶段 1:构建 ──
|
||
FROM node:20-alpine AS build
|
||
WORKDIR /app
|
||
ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0
|
||
RUN corepack enable
|
||
# 先拷全部 workspace 清单 → install 层缓存(源码变动不失效)。
|
||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||
COPY apps/admin/package.json apps/admin/
|
||
COPY apps/viewer/package.json apps/viewer/
|
||
COPY packages/contracts/package.json packages/contracts/
|
||
COPY packages/db-cn/package.json packages/db-cn/
|
||
COPY packages/db-ov/package.json packages/db-ov/
|
||
COPY packages/embed-loader/package.json packages/embed-loader/
|
||
COPY packages/storage/package.json packages/storage/
|
||
COPY services/api/package.json services/api/
|
||
COPY services/sync/package.json services/sync/
|
||
COPY services/worker/package.json services/worker/
|
||
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
|
||
pnpm install --frozen-lockfile
|
||
# 源码(.dockerignore 已剔除 node_modules/dist/.env/apps/mobile/docs)。
|
||
COPY packages packages
|
||
COPY services services
|
||
# prisma generate 双库:db-ov 的 src/index.ts 转出口 generated/client(gitignore
|
||
# 工件,必须先于 tsc);generate 不需要真实 DATABASE_URL_*,migrate deploy 才需要。
|
||
RUN pnpm --filter @photo/db-cn --filter @photo/db-ov exec prisma generate
|
||
# 逐包构建(依赖序显式;服务端不需要构建 apps/viewer、apps/admin——那是 web 镜像的事)。
|
||
RUN pnpm --filter @photo/contracts run build \
|
||
&& pnpm --filter @photo/db-cn run build \
|
||
&& pnpm --filter @photo/db-ov run build \
|
||
&& pnpm --filter @photo/storage run build \
|
||
&& pnpm --filter @photo/api-cn --filter @photo/worker --filter @photo/sync run build
|
||
|
||
# ── 阶段 2:生产依赖 ──
|
||
FROM node:20-alpine AS prod-deps
|
||
WORKDIR /app
|
||
ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0
|
||
RUN corepack enable
|
||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||
COPY apps/admin/package.json apps/admin/
|
||
COPY apps/viewer/package.json apps/viewer/
|
||
COPY packages/contracts/package.json packages/contracts/
|
||
COPY packages/db-cn/package.json packages/db-cn/
|
||
COPY packages/db-ov/package.json packages/db-ov/
|
||
COPY packages/embed-loader/package.json packages/embed-loader/
|
||
COPY packages/storage/package.json packages/storage/
|
||
COPY services/api/package.json services/api/
|
||
COPY services/sync/package.json services/sync/
|
||
COPY services/worker/package.json services/worker/
|
||
# --prod:剔除 jest/ts-node/playwright 等开发依赖;@prisma/client 走 optional
|
||
# 引擎依赖仍在(.prisma 生成产物由 runtime 阶段的 prisma generate 重建)。
|
||
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
|
||
pnpm install --frozen-lockfile --prod
|
||
|
||
# ── 阶段 3:运行时 ──
|
||
FROM node:20-alpine
|
||
# openssl:prisma 查询引擎 musl 构建链接 openssl3;curl:compose healthcheck;
|
||
# tini 未装——compose 侧统一 init: true 承担 PID 1 信号转发。
|
||
RUN apk add --no-cache openssl curl
|
||
# 全局 prisma CLI(migrate-deploy 角色)。版本必须与 pnpm-lock.yaml 的
|
||
# prisma@5.22.0 一致,避免 schema/engine 行为漂移。npm 显式重试参数:构建机到
|
||
# registry 偶发 ECONNRESET,npm 默认不重试会硬失败(pnpm 自带重试无此问题)。
|
||
RUN --mount=type=cache,target=/root/.npm \
|
||
npm install -g --fetch-retries=5 --fetch-retry-mintimeout=20000 \
|
||
--fetch-retry-maxtimeout=120000 prisma@5.22.0
|
||
ENV NODE_ENV=production
|
||
WORKDIR /app
|
||
# workspace 结构(清单 + 各包 node_modules 符号链接,pnpm 相对链接布局完整保留)。
|
||
COPY --from=prod-deps /app/node_modules ./node_modules
|
||
COPY --from=prod-deps /app/packages ./packages
|
||
COPY --from=prod-deps /app/services ./services
|
||
# 构建产物。
|
||
COPY --from=build /app/packages/contracts/dist ./packages/contracts/dist
|
||
COPY --from=build /app/packages/db-cn/dist ./packages/db-cn/dist
|
||
COPY --from=build /app/packages/db-ov/dist ./packages/db-ov/dist
|
||
COPY --from=build /app/packages/storage/dist ./packages/storage/dist
|
||
COPY --from=build /app/services/api/dist ./services/api/dist
|
||
COPY --from=build /app/services/worker/dist ./services/worker/dist
|
||
COPY --from=build /app/services/sync/dist ./services/sync/dist
|
||
# prisma schema + 迁移(migrate-deploy 角色与 generate 都在包内 prisma/ 目录)。
|
||
COPY packages/db-cn/prisma ./packages/db-cn/prisma
|
||
COPY packages/db-ov/prisma ./packages/db-ov/prisma
|
||
# 双库 client 生成:db-cn → pnpm store 内 .prisma/client;db-ov → 包内 generated/
|
||
# (运行时镜像内重建,产物即最终布局;docker build 网络可下载 musl 引擎)。
|
||
RUN prisma generate --schema=packages/db-cn/prisma/schema.prisma \
|
||
&& prisma generate --schema=packages/db-ov/prisma/schema.prisma
|
||
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||
# 缺省角色 api-cn;compose 用 command: 覆盖(api-ov/worker/sync/migrate-deploy)。
|
||
CMD ["api-cn"]
|