--- name: dokploy-gitea-deploy description: > 企业项目部署:默认走 company-deploy-mcp(飞书身份 + buxi_ Key → 推 Gitea → MCP 建库/多卷/PG·MySQL/域名/HTTPS → 轮询)。 旧路径为直连 Dokploy API(.env.deploy),仅运维/无 MCP 时使用。触发词:部署、上线、Dokploy、Gitea、 redeploy、MCP 部署、buxi_、company-deploy-mcp。Use when /dokploy-gitea-deploy。 metadata: short-description: "企业部署:优先 MCP,兼容 Dokploy 直连" --- # 安装(给用户 / Agent) ```bash # 内网一键(推荐) curl -fsSL https://company-deploy-mcp.loncode.site/install-skill.sh | bash # 或 skills CLI npx skills add http://git.loncode.site/Buxi/company-deploy-skills.git --skill dokploy-gitea-deploy -g -y ``` 技能仓:http://git.loncode.site/Buxi/company-deploy-skills 连接中心(飞书 + MCP Key):https://company-deploy-mcp.loncode.site/ Skill 只提供流程;真正部署还需配置 MCP `company-deploy`(`buxi_` Bearer)。 --- # 企业部署编排(Gitea + Dokploy + company-deploy-mcp) 业务同学不碰平台细节。Agent 负责:可构建工程 → 推代码 → 调控制面 → 交付 **HTTPS 链接**。 **默认路径:company-deploy-mcp(必须优先)。** 直连 Dokploy API 为 **legacy / 运维例外**。 **产品范围(收口):** 主路径是 **普通 Dockerfile 服务**(Python / Node / 静态站等)。 飞书 **妙搭 / `@lark-apaas/*` 模板不是主路径**——不承诺登录、权限、平台 API 与线上一致;控制面仅可能注入 **进程启动** 所需最小 env。详见 `references/stack-profiles.md` 支持矩阵。 参考: - `references/mcp-deploy.md` — **MCP 默认状态机**(工具参数、域名/卷/库) - `references/domain.md` — 域名与 HTTPS(Let’s Encrypt,无需通配符证书) - `references/sequence.md` — 时序 - `references/env-deploy.example` — 仅 legacy 直连用 - `references/stack-profiles.md` — Dockerfile 约定 + **支持矩阵** 线上连接中心:`https://company-deploy-mcp.loncode.site/` MCP endpoint:`https://company-deploy-mcp.loncode.site/mcp` --- ## 路径选择 | 条件 | 路径 | |------|------| | Agent 已配置 MCP `company-deploy`(`buxi_` Key) | **MCP 默认** | | 用户已飞书登录拿过 Key | **MCP 默认** | | 用户明确「不要 MCP / 运维直连 / 改 Dokploy 底层」 | legacy | | 无 MCP 且无 `.env.deploy` | **先引导连 MCP**,不要伪造部署 | **禁止**在可用 MCP 时仍让业务填写 `DOKPLOY_API_KEY` / Gitea Token。 --- ## 架构(默认) ```text 用户:「部署 / 上线」 → Agent:Dockerfile + 本地验证 → Agent:ensure_repository(MCP)→ 拿到 agentHint.pushUrl(机器人 Token) → Agent:git push (禁止用用户 SSH;禁止向用户要密钥) → Agent:create_deployment_plan + apply_deployment_plan MCP 内部:挂卷 → PG/MySQL(可选)→ domain(buxi+5位.根域 + LE HTTPS)→ deploy → Agent:get_deployment_status / list_projects 轮询 → 交付:https://buxi*****.loncode.site + 脱敏说明 ``` - **飞书**:身份;**buxi_ Key**:调用 MCP - **Gitea**:源码(**gitea-robot** 建仓+推送;业务用户**不需要** Gitea 账号或 `~/.ssh`) - **Dokploy**:构建运行(由 MCP 调用,不直暴露给业务) - **归属 / 配额 / 审计**:控制面 SQLite(`owner_open_id`、运行中数量) --- ## 前置条件 ### MCP 路径(默认) 1. 用户已在连接中心飞书登录,Agent 已配置: ```json { "mcpServers": { "company-deploy": { "url": "https://company-deploy-mcp.loncode.site/mcp", "headers": { "Authorization": "Bearer buxi_..." } } } } ``` 2. 项目有可构建 **Dockerfile**(进程监听 `spec.port`,状态写 `/data` 等挂载点) 3. 本机有 `git` 即可;**推送凭据来自 `ensure_repository` 的 `agentHint.pushUrl`**,**不要**配置用户 SSH、**不要**加 `id_ed25519.pub` 到 Gitea 4. 企业侧已配:`*.DOMAIN_ROOT` DNS → Dokploy;80/443 可达(Let’s Encrypt) 无 Key:引导打开连接中心登录,**不要**继续直连 Dokploy。 ### Legacy 路径(运维) 见文末;需 `.env.deploy` + `DEPLOY_AUTHORIZED=true`。 --- ## MCP 标准状态机(必须按序) 细节与 JSON 示例见 `references/mcp-deploy.md`。 ### 0. 身份 - 调用 `whoami`(可选):确认 `role` / `openId` - 调用 `get_my_quota`:看运行中数量是否达上限 ### 1. 工程 - 识别栈;保证 Dockerfile;`.gitignore` 排除密钥 - 有状态:默认 `/data`;多目录用 `persistence[]` - 需要库:`databases: [{ engine: "postgres"|"mysql", ... }]` - **若依赖 `@lark-apaas/*` / 妙搭模板:** - **先告知用户**:本平台不保证页面+接口可用;推荐 `lark-apps` 云端或业务去平台化 - **禁止**主动承诺「自托管后与妙搭一致」 - **禁止**在 skill 流程里大改登录/伪造网关/补 SPA 模板(那是业务仓责任,且非本 skill 范围) - 用户书面坚持后,仅按普通 Dockerfile 部署,交付时标注 **实验性** - **Node 多阶段硬规则**(详见 `stack-profiles.md`): - 禁止在 `npm ci`/`pnpm install` **之前** `ENV NODE_ENV=production`(否则 `nest`/`vite` not found) - 大前端 Vite:`NODE_OPTIONS=--max-old-space-size=3072` - runtime 用 `COPY --from=build` 串行,避免并行双 `npm ci` 把小机打爆 ### 2. 仓库与推送(权限红线) ```text ensure_repository({ repo: "owner/name" 或 "name" }) → 使用返回的 agentHint.pushUrl(含企业机器人 Token) → git add / commit → git push --set-upstream "" HEAD: → 记录 commitSha ``` **硬规则:** 1. **禁止**要求用户上传/配置 `~/.ssh/id_ed25519.pub` 或任何个人 SSH Key。 2. **禁止**让用户自己去 Gitea 开权限、建仓、加 Collaborator。 3. **禁止**用未认证的 `cloneUrl` 去 `git push`(会 403 / Permission denied)。 4. **必须**用 `agentHint.pushUrl` 做一次推送;**不要**把 `pushUrl` 全文贴进对用户的回复。 5. 若仍 403:重新 `ensure_repository` 取新 hint,检查本机网络能否访问 `git.loncode.site`——**不要**改去配用户 SSH。 ### 3. 计划与发布 ```text create_deployment_plan({ repo, commitSha, branch, # environment = 控制面「部署标签」,默认 default。禁止擅自 invent production/staging # 除非用户明确说「再部署一套并行环境」。与 status/redeploy 必须同一标签;不确定 list_projects environment: "default", spec: { buildType: "dockerfile", dockerfilePath: "Dockerfile", buildPath: "/", port: <容器端口>, healthcheckPath: "/", persistence: [ /* 可选多卷;缺省自动加 /data */ ], databases: [ /* 可选 postgres|mysql */ ], exposeWeb: true } }) → apply_deployment_plan({ planId }) → 使用返回的 url / domain / databases(密码已脱敏) ``` **环境概念(易混):** | 名称 | 是什么 | 谁决定 | |------|--------|--------| | Dokploy Environment | 应用建在平台哪个分组(如 preview) | 控制面 `DOKPLOY_ENVIRONMENT_ID`(全站统一) | | MCP `environment` | 部署标签,`repo+标签` 对应一套应用/域名 | Agent 参数,默认 `default`,全公司应统一 | 已有项目若当初用了非 default 标签,重部署/查状态必须继续传该标签,不要擅自改(否则会当成新项目)。 ### 部署标签硬规则(Agent) 1. **默认且优先**:省略 `environment` 或显式 `"default"`。 2. **禁止**仅因用户说「上线 / 生产 / 正式」就改成 `production`——那只是业务话术,不是部署标签。 3. **仅当**用户明确要求「第二套环境 / staging / 并行预发」时,才用非 default 标签。 4. 重部署前 `list_projects`,沿用已有 `environment` 字段。 ### 4. 轮询与交付 ```text get_deployment_status / list_projects Web:curl -skI "$url" 或健康路径(证书可能短暂签发中) ``` 对用户: - 给 **HTTPS 链接**(`apply` 的 `url`) - 不提 Gitea/Dokploy/Token - 配额满、无权:原文转述 MCP 错误 ### 5. 域名与 HTTPS(控制面完成,Agent 勿重复 domain.create) - 默认 host:`buxi` + 5 位随机 `[a-z0-9]` + `.` + `DOMAIN_ROOT` 例:`buxi3k9xa.loncode.site` - 首次分配后 **固定**(存在控制面 mapping) - HTTPS:Dokploy Traefik + **Let’s Encrypt 按子域签证书**(**不需要**通配符证书) - DNS:建议 `*.loncode.site` → 服务器(通配 **解析**,不是通配证书) - 证书失败:查 80/443、DNS;可暂 HTTP 仅当控制面 `DOMAIN_HTTPS=false` Agent **不要**在 MCP 路径下再调 Dokploy `domain.create`(避免双绑/冲突)。 ### 6. 卷与数据库 | 能力 | 行为 | |------|------| | 默认卷 | Docker named volume → `/data`(避免 bind 目录不存在导致 Swarm 0/1) | | bind 模式 | 可选;控制面 mkdir 宿主机路径,失败回退 volume | | 多卷 | `spec.persistence[]`;缺 `/data` 仍自动补 | | Postgres / MySQL | `spec.databases[]` → Dokploy 建库 + 注入 `DATABASE_URL` 等 | | 重部署 | 同 repo+env 不占新配额名额;域名与库记录复用 | 应用必须把状态写在挂载路径(如 SQLite → `/data/app.db`)。 --- ## 意图路由 | 用户说法 | 动作 | |----------|------| | 部署 / 上线 / 第一次发布 | MCP 全链路;交付 `url`(普通 Dockerfile) | | 重试 / 再构建 | 新 SHA → 新 plan → apply(已有 mapping) | | 查状态 / 我的项目 | `list_projects` / `get_deployment_status` | | 配额 | `get_my_quota` | | 只要链接 | `list_projects` 看 `url`;无则查 status | | 运维直连 Dokploy | 仅明确要求时走 legacy | | 妙搭应用 / `@lark-apaas` 上线 | **先边界说明**;优先 `lark-apps`;自托管仅实验、不承诺接口 | | 修妙搭白屏 / 平台 API / 登录伪造 | **非本 skill**;说明需业务去平台化或妙搭云端,勿在控制面堆适配 | --- ## 对用户话术 **成功:** - 已发布当前版本 - 访问:`https://buxi….loncode.site/`(以 MCP 返回为准) - 需要库时:说明已注入数据库连接(**不打印密码**) - 若为妙搭实验部署:明确 **「仅容器/入口可能可用,登录与平台接口不保证」** **失败:** - 配额满 / 未登录 Key / 构建失败 / 证书签发中 - 给可执行下一步,不暴露平台密钥 **拒绝加戏:** - 不要为了「页面像妙搭」去改 skill 流程、伪造网关、承诺 runtime API - 控制面 `SELF_HOST_*` 只是 boot 兜底,不是功能完整度保证 --- ## 安全红线 1. 永不 commit / 回显:`buxi_` Key、`MCP_AUTH_TOKEN`、Dokploy/Gitea Token、`pushUrl`、数据库密码全文 2. `apply` 返回的 `connectionUrl` 已脱敏则保持;未脱敏则遮罩 3. 普通用户不可查他人项目(控制面会 403) 4. 生产破坏性操作仍受控制面策略约束 5. **禁止**因 push 失败引导用户配置个人 SSH(那是错误路径) --- ## Agent 检查清单(MCP) - [ ] MCP 可用;`whoami` 正常 - [ ] Dockerfile + 数据写挂载点 - [ ] `ensure_repository` + push + `commitSha` - [ ] plan 含正确 `port`;需要时 `persistence` / `databases` - [ ] `apply` 拿到 `url` - [ ] 轮询至终态;探活 - [ ] 未向用户索要 Dokploy/Gitea 地址或 Token --- ## Legacy:直连 Dokploy(运维例外) **仅当**用户明确要求或 MCP 不可用且有 `.env.deploy`: 1. `set -a && source .env.deploy && set +a`,`DEPLOY_AUTHORIZED=true` 2. 按旧流程:Dockerfile → push → `application.*` / `mounts` / `domain.create` / deploy 3. 域名规则见 `references/domain.md` **Legacy** 段(与 MCP 的 `buxi+5` 规则不同,勿混用) 4. 模板:`references/env-deploy.example` 5. 仍禁止把密钥贴进聊天 **默认对话不要走这条。** 有 MCP 时禁止向业务索要 `DOKPLOY_API_KEY`。 --- ## 与其它 skill 边界 | 场景 | 用 | |------|-----| | 企业 Dockerfile 部署(默认) | **本 skill → MCP** | | 妙搭云端发布 / 平台能力迭代 | **`lark-apps`**(首选) | | 妙搭模板硬上自托管 | 非主路径;见 `stack-profiles`;**不**在本 skill 做深度适配 | | 无 MCP 的运维救火 | 本 skill → legacy | --- ## 故障速查(MCP) | 现象 | 处理 | |------|------| | 401 / 要 Feishu Key | 引导连接中心登录,配置 `buxi_` | | git push 权限 / Permission denied / 要配 SSH | **错误路径**。改用 `ensure_repository` → `agentHint.pushUrl` 推送;禁止给用户配 SSH | | `nest: not found` / `vite: not found` | build 阶段在装依赖前设了 `NODE_ENV=production`;先全量 `npm ci` 再设 production | | `JavaScript heap out of memory` | Dockerfile build 加 `NODE_OPTIONS=--max-old-space-size=3072`;避免并行 npm ci;机器内存过小则升配 | | `FORCE_AUTHN_INNERAPI_DOMAIN` / 平台模式需要基础域名 | 镜像仍带 PlatformModule 时缺 boot env;`apply` 会注入公网 URL;**不表示业务已可用** | | 妙搭项目:页面白屏 / `{{appId}}` / 接口 403·404 / JSON 解析 HTML | **预期内能力缺口**(非本 skill 必修)。引导去平台化或 `lark-apps`;勿在控制面加网关适配 | | 运行中项目达上限 | `get_my_quota`;停/删旧应用后再部署 | | Forbidden 看他人项目 | 非管理员;加 `ADMIN_OPEN_IDS` 或只查自己的 | | 有部署无 HTTPS | 等 LE;查 DNS/80;控制面证书配置 | | 重部署丢数据 | 确认写 `/data`;控制面默认挂载是否开启 | | Swarm 0/1 + bind path does not exist | 控制面已默认 volume + mkdir;旧应用可 `mkdir -p` 宿主机路径或删 bind 改 volume 后 redeploy | | 要 PG/MySQL | plan 里带 `databases`,勿手建后不注入 env |