# syntax=docker/dockerfile:1 # 与 .node-version 对齐;可用 build-arg 覆盖 ARG NODE_VERSION=26.7.0 FROM node:${NODE_VERSION}-alpine AS base WORKDIR /app ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0 \ TURBO_TELEMETRY_DISABLED=1 \ DO_NOT_TRACK=1 # Node 25+ 官方镜像不再内置 corepack,需显式安装以使用 yarn@4 RUN npm install -g corepack && corepack enable # ---- 依赖层:只拷清单,最大化 yarn 缓存 ---- FROM base AS deps COPY package.json yarn.lock .yarnrc.yml ./ COPY app/web/package.json app/web/package.json # workspaces: app/* + packages/* — 清单缺一不可,否则 yarn 解析 workspace:* 失败或漏链 COPY app/docs/package.json app/docs/package.json COPY packages/adsense/package.json packages/adsense/package.json COPY packages/dao/package.json packages/dao/package.json COPY packages/db/package.json packages/db/package.json COPY packages/design-tokens/package.json packages/design-tokens/package.json COPY packages/i18n/package.json packages/i18n/package.json COPY packages/models/package.json packages/models/package.json COPY packages/seo-geo/package.json packages/seo-geo/package.json COPY packages/trpc/package.json packages/trpc/package.json COPY packages/types/package.json packages/types/package.json COPY packages/ui/package.json packages/ui/package.json RUN --mount=type=cache,target=/root/.yarn/berry/cache \ yarn install --immutable # ---- 构建层:只 build web 依赖闭包 + 裁剪生产依赖 ---- FROM deps AS build COPY . . # Astro 构建期内联 PUBLIC_*;空串会导致 canonical/sitemap 抛 Invalid URL, # 因此给 localhost 默认值,生产用 --build-arg PUBLIC_SITE_URL=https://example.com 覆盖 ARG PUBLIC_SITE_URL=http://localhost:4321 ENV PUBLIC_SITE_URL=${PUBLIC_SITE_URL} \ ASTRO_TELEMETRY_DISABLED=1 \ TURBO_TELEMETRY_DISABLED=1 # --filter=@app/web...:web + 其上游依赖;跳过 adsense 等无关包 # --cache-dir 指到 /tmp:与 .turbo 分离,rm -rf .turbo 不会清掉 BuildKit 缓存挂载 # 缓存挂载需 BuildKit(DOCKER_BUILDKIT=1) RUN --mount=type=cache,id=turbo-cache,target=/tmp/turbo-cache \ yarn turbo run build --filter=@app/web... --cache-dir=/tmp/turbo-cache \ && yarn workspaces focus --production @app/web \ && rm -rf .git .turbo output \ && rm -rf packages/*/src packages/*/*.tsbuildinfo \ && rm -rf app/web/src app/web/node_modules/.vite # ---- 运行层:仅产物 + 生产 node_modules ---- FROM node:${NODE_VERSION}-alpine AS runner WORKDIR /app ENV NODE_ENV=production \ HOST=0.0.0.0 \ HOSTNAME=0.0.0.0 \ PORT=4321 \ # file: 库与 session 的可写位置(/app 属主为 root,node 用户不可写) TMPDIR=/tmp \ # 默认本地 sqlite;生产可 -e TURSO_DATABASE_URL=libsql://... 覆盖 TURSO_DATABASE_URL=file:/app/data/local.db \ # 挂载凭据加密(64 hex):运行时必须 -e MEDIA_SECRET_KEY=... MEDIA_SECRET_KEY= \ # 可选:开放弹幕 AppId/Secret、Bangumi/Open API 地址见 .env.example OPEN_DANMAKU_APP_ID= \ OPEN_DANMAKU_APP_SECRET= COPY --from=build --chown=node:node /app/package.json /app/yarn.lock /app/.yarnrc.yml ./ COPY --from=build --chown=node:node /app/app/web/package.json app/web/package.json COPY --from=build --chown=node:node /app/app/web/dist app/web/dist COPY --from=build --chown=node:node /app/packages packages COPY --from=build --chown=node:node /app/node_modules node_modules # 工作区内可能存在的局部 node_modules(会话缓存写在其 .astro 下) COPY --from=build --chown=node:node /app/app/web/node_modules app/web/node_modules RUN mkdir -p /app/data && chown node:node /app/data USER node EXPOSE 4321 HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \ CMD wget -q -O /dev/null "http://127.0.0.1:4321/" || exit 1 CMD ["node", "app/web/dist/server/entry.mjs"]