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>
67 lines
3.3 KiB
Docker
67 lines
3.3 KiB
Docker
# syntax=docker/dockerfile:1
|
||
# docker/web.Dockerfile —— photo-live-web 前端网关镜像(P5-prep Task 1)。
|
||
# nginx:alpine 承载 viewer(/,history 路由)+ admin(/admin/,hash 路由)
|
||
# + /v1 反代 API(API_UPSTREAM env,含 /v1/realtime WS 升级)
|
||
# + /embed/v1/ 与 /assets/ 内容寻址长缓存(见 infra/deploy/nginx.conf.template)。
|
||
#
|
||
# 构建(VITE_* 为构建期变量——viewer/admin 的 API 基址在产物内固化):
|
||
# docker build -f docker/web.Dockerfile \
|
||
# --build-arg VITE_VIEWER_BASE=https://viewer.example.com \
|
||
# --build-arg VITE_EMBED_ORIGIN=https://viewer.example.com \
|
||
# -t photo-live-web:<tag> .
|
||
# VITE_API_BASE 缺省空串(同源 /v1,经本镜像 nginx 反代)——cn/ov 两地域共用
|
||
# 同一构建参数集,API 差异全部由运行时 API_UPSTREAM 承担。
|
||
|
||
# ── 阶段 1:构建 ──
|
||
FROM node:20-alpine AS build
|
||
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/
|
||
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
|
||
pnpm install --frozen-lockfile
|
||
COPY packages packages
|
||
COPY apps apps
|
||
# 构建期 VITE 变量(进程 env 优先级高于 apps/*/.env* 文件):
|
||
# VITE_API_BASE viewer API 基址;空串=同源相对路径(生产网关形态,缺省)。
|
||
# VITE_BASE_URL admin 资源前缀=/admin/(nginx 子路径挂载;hash 路由)。
|
||
# VITE_VIEWER_BASE / VITE_EMBED_ORIGIN admin「分享卡/嵌入代码」拼 URL 用,
|
||
# 随真实域名构建时传入(缺省 dev 兜底仅作占位)。
|
||
ARG VITE_API_BASE=""
|
||
ARG VITE_BASE_URL=/admin/
|
||
ARG VITE_VERSION=0.1.0
|
||
ARG VITE_VIEWER_BASE=http://127.0.0.1:5175
|
||
ARG VITE_EMBED_ORIGIN=http://127.0.0.1:5175
|
||
ENV VITE_API_BASE=${VITE_API_BASE} \
|
||
VITE_BASE_URL=${VITE_BASE_URL} \
|
||
VITE_VERSION=${VITE_VERSION} \
|
||
VITE_VIEWER_BASE=${VITE_VIEWER_BASE} \
|
||
VITE_EMBED_ORIGIN=${VITE_EMBED_ORIGIN}
|
||
# embed-loader 先构建并同步进 viewer publicDir(loader.js 内容寻址路径 /embed/v1/),
|
||
# 随后 viewer / admin 构建(contracts 是两者的类型/运行时依赖,先出 dist)。
|
||
RUN pnpm --filter @photo/contracts run build \
|
||
&& pnpm --filter @photo/embed-loader run build \
|
||
&& pnpm --filter @photo/embed-loader run sync \
|
||
&& pnpm --filter @photo/viewer run build \
|
||
&& pnpm --filter @photo/admin run build
|
||
|
||
# ── 阶段 2:nginx ──
|
||
FROM nginx:alpine
|
||
# 官方镜像启动时 envsubst 渲染 /etc/nginx/templates/*.template → conf.d;
|
||
# API_UPSTREAM 由 compose environment 注入(缺省指向 cn API 容器名)。
|
||
ENV API_UPSTREAM=http://api-cn:8080
|
||
COPY infra/deploy/nginx.conf.template /etc/nginx/templates/default.conf.template
|
||
COPY --from=build /app/apps/viewer/dist /usr/share/nginx/html/viewer
|
||
COPY --from=build /app/apps/admin/dist /usr/share/nginx/html/admin
|
||
EXPOSE 80
|