7.3 KiB
7.3 KiB
技术栈构建约定(Agent 改 Dockerfile 时遵循)
通用
- 基础镜像:Docker Hub(
python:*/node:*/nginx:*),避免默认ghcr.io。 - 多阶段或「依赖层 → 代码层」拆分。
- BuildKit:
--mount=type=cache缓存包管理器目录。 - 生产
CMD/ENTRYPOINT明确;进程监听spec.port(与 plan 一致)。 - 健康检查:实现
/healthz或约定路径,写入spec.healthcheckPath。 - Dokploy 不要每次 cleanCache。
- 有状态数据写挂载路径(见下),不要只写容器可写层。
持久化与 /data(MCP 默认)
控制面默认为每个应用挂载 容器内 /data(可配置,见 inspect_project → policy.storage)。
| 约定 | 说明 |
|---|---|
| SQLite / 本地文件 | 路径放在 /data/...,例如 /data/app.db |
| 上传目录 | 额外 persistence:{ "name": "uploads", "mountPath": "/var/uploads" } |
| 日志 | ephemeral 可写容器内;需保留则挂卷 |
| 多卷 | spec.persistence[];若未包含 /data,控制面仍自动补默认卷 |
示例环境变量(应用代码侧):
DATA_DIR=/data
DATABASE_PATH=/data/app.db
禁止假设宿主机路径;只认容器内 mountPath。
托管数据库(Postgres / MySQL)
plan 中声明 spec.databases[] 后,控制面注入连接串环境变量(默认名 DATABASE_URL)。
应用应:
- 启动时读取
process.env.DATABASE_URL(或自定义envVar) - 不要在镜像里写死密码
- 迁移在启动脚本或独立 job 中执行(注意并发与锁)
示例(Node):
const url = process.env.DATABASE_URL;
if (!url) throw new Error("DATABASE_URL is required");
示例(Python):
import os
url = os.environ.get("DATABASE_URL")
if not url:
raise RuntimeError("DATABASE_URL is required")
Docker 内网 host 由 Dokploy 管理;应用只消费完整 URL。
Python(uv 优先)
检测:pyproject.toml + uv.lock,或 requirements.txt。
推荐结构:
FROM python:3.12-slim-bookworm
WORKDIR /app
ENV UV_LINK_MODE=copy \
UV_CONCURRENT_DOWNLOADS=16 \
UV_HTTP_TIMEOUT=120 \
PYTHONUNBUFFERED=1
ARG PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
ENV UV_DEFAULT_INDEX=${PIP_INDEX_URL} \
UV_INDEX_URL=${PIP_INDEX_URL} \
PIP_INDEX_URL=${PIP_INDEX_URL}
RUN --mount=type=cache,target=/root/.cache/pip \
pip install --no-cache-dir "uv>=0.6.0"
COPY pyproject.toml uv.lock README.md ./
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-dev --no-install-project
COPY src ./src
# …其它源码…
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-dev
# 监听 0.0.0.0,端口与 plan.spec.port 一致
ENV DATA_DIR=/data
EXPOSE 8000
CMD ["uv", "run", "your-entrypoint"]
说明:
- 慢点通常是 PyPI 下包,不是
pip install uv本身。 - 主机
~/.pip/pip.conf不会自动进容器;必须 Dockerfile/build-arg。 - 飞书长连接类:
replicas=1+ 状态进/data;exposeWeb: false若无需公网页。
Node(pnpm / npm)
检测:package.json,优先 pnpm-lock.yaml → package-lock.json → yarn.lock。
Dockerfile 硬规则(踩过的坑,Agent 必守)
| 错误 | 现象 | 正确做法 |
|---|---|---|
在 build 阶段 npm ci 之前 ENV NODE_ENV=production |
nest: not found / vite: not found;日志里 packages 只有几百个(缺 devDependencies) |
先 npm ci(装全量含 dev)→ 再 ENV NODE_ENV=production → npm run build |
| 不设 Node 堆、大前端 Vite 打包 | FATAL ERROR: JavaScript heap out of memory |
build 阶段:ENV NODE_OPTIONS=--max-old-space-size=3072(小机 3~4G 可试 2560) |
| multi-stage 里 build 与 runtime 无依赖 | Docker 并行 两个 npm ci,小机内存翻倍易 OOM |
runtime 至少 COPY --from=build … 一件产物,让 build 先完成 |
| 用用户 SSH 推 Gitea | Permission denied | 用 ensure_repository 的 pushUrl,见 SKILL |
推荐:Nest + Vite 全栈模板
FROM node:22-bookworm-slim AS build
WORKDIR /app
# ① 提高堆;② 此时不要 NODE_ENV=production
ENV NODE_OPTIONS=--max-old-space-size=3072
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts
COPY . ./
# ③ 仅编译时 production
ENV NODE_ENV=production
RUN npm run build:prod && npm cache clean --force
FROM node:22-bookworm-slim AS runtime
WORKDIR /app
ENV NODE_ENV=production \
SERVER_HOST=0.0.0.0 \
SERVER_PORT=3000 \
DATA_DIR=/data
COPY package.json package-lock.json ./
# ④ 依赖 build,避免与 vite 并行 npm ci
COPY --from=build /app/package.json /tmp/.build-done
RUN npm ci --omit=dev --ignore-scripts && npm cache clean --force
COPY --from=build /app/dist ./
EXPOSE 3000
CMD ["node", "server/main.js"]
推荐:较轻的 Node API(pnpm)
FROM node:22-bookworm-slim AS build
WORKDIR /app
ENV NODE_OPTIONS=--max-old-space-size=2048
RUN corepack enable
COPY package.json pnpm-lock.yaml ./
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile
COPY . .
ENV NODE_ENV=production
RUN pnpm run build
FROM node:22-bookworm-slim AS runner
WORKDIR /app
ENV NODE_ENV=production DATA_DIR=/data
COPY --from=build /app/dist ./dist
COPY --from=build /app/package.json ./
COPY --from=build /app/node_modules ./node_modules
# 若 node_modules 含 dev,可改为 runner 单独 pnpm install --prod
EXPOSE 3000
CMD ["node", "dist/index.js"]
静态前端(Vite 等)可用 nginx:stable-alpine 拷 dist;spec.port 多为 80。
纯静态站构建同样需要 devDependencies(vite)在 build 阶段装全。
Registry 加速示例 .npmrc:
registry=https://registry.npmmirror.com
部署前 Agent 自检(Node)
- Dockerfile 没有在安装依赖前设置
NODE_ENV=production nest/vite/tsc等 CLI 在 devDependencies 且 build 阶段能装到- 大前端:
NODE_OPTIONS=--max-old-space-size=3072(或更高,视机器) - multi-stage:runtime 依赖 build,避免并行双
npm ci - 运行
CMD只跑编译产物,不在 runtime 再nest build
Docker Compose
- 当前 MCP MVP 仅
buildType: dockerfile单应用。 - 多服务 Compose:legacy / 运维在 Dokploy 选 Compose 类型,或拆成多个 MCP 应用 + 托管 DB。
- 生产注意:DB 密码走
databases[]注入;卷走persistence[]。
构建耗时预期(经验)
| 场景 | 预期 |
|---|---|
| 首次全量(弱网 + 下包) | 10–40 分钟可能 |
| 依赖层已缓存,只改代码 | 数分钟内 |
| 仅拉预构建业务镜像 | 通常更短 |
若日志出现 Prepared N packages in 30m:换源 + 分层缓存 + 禁止 cleanCache;长期用私有镜像仓库。
与 plan.spec 对齐检查
部署前 Agent 自检:
- 容器监听
0.0.0.0:$PORT,且spec.port一致 - 有状态路径落在
/data或其它persistence.mountPath - 需要 PG/MySQL 时 plan 带
databases,代码读对应 env - Web 服务
exposeWeb: true(默认);Worker 显式false .gitignore排除.env、密钥、本地 db