commit 7b56a16fbc2fe407c0fdd617ab300c23239427ac Author: deploy-bot Date: Fri Jul 31 09:47:16 2026 +0800 chore: init company-deploy-skills with dokploy-gitea-deploy diff --git a/README.md b/README.md new file mode 100644 index 0000000..ba70c6e --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# company-deploy-skills + +企业部署相关 **Agent Skills**(与 [company-deploy-mcp](https://company-deploy-mcp.loncode.site/) 配合使用)。 + +## 一键安装 + +```bash +# 推荐(skills CLI,支持多 Agent) +npx skills add http://git.loncode.site/Buxi/company-deploy-skills --skill dokploy-gitea-deploy -g -y + +# 内网兜底(git clone 到常见技能目录) +curl -fsSL https://company-deploy-mcp.loncode.site/install-skill.sh | bash +``` + +安装后仍需在连接中心登录飞书,配置 MCP(`buxi_` Key)。 + +## 包含的 Skills + +| Skill | 说明 | +|-------|------| +| `dokploy-gitea-deploy` | 企业部署:MCP 优先(Gitea + Dokploy),交付 HTTPS | + +## 目录约定 + +```text +company-deploy-skills/ + README.md + dokploy-gitea-deploy/ + SKILL.md + references/ + # 后续新 skill 平铺同级目录即可 +``` + +## 与 MCP 的关系 + +| 组件 | 职责 | +|------|------| +| **本仓库 Skill** | 教 Agent 流程与话术 | +| **company-deploy-mcp** | 飞书身份、配额、域名、真正调 Dokploy | + +连接中心:https://company-deploy-mcp.loncode.site/ diff --git a/dokploy-gitea-deploy/SKILL.md b/dokploy-gitea-deploy/SKILL.md new file mode 100644 index 0000000..f155351 --- /dev/null +++ b/dokploy-gitea-deploy/SKILL.md @@ -0,0 +1,277 @@ +--- +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 直连" +--- + +# 企业部署编排(Gitea + Dokploy + company-deploy-mcp) + +业务同学不碰平台细节。Agent 负责:可构建工程 → 推代码 → 调控制面 → 交付 **HTTPS 链接**。 + +**默认路径:company-deploy-mcp(必须优先)。** +直连 Dokploy API 为 **legacy / 运维例外**。 + +参考: + +- `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) + → Agent:git push(企业凭据,用户无感) + → 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**:源码;**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. Agent 本机可 `git push`(企业 Git 凭据,**不**向用户索要) +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", ... }]` + +### 2. 仓库 + +```text +ensure_repository({ repo: "owner/name" 或 "name" }) +→ git remote / commit / push +→ 记录 commitSha +``` + +### 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` | +| 重试 / 再构建 | 新 SHA → 新 plan → apply(已有 mapping) | +| 查状态 / 我的项目 | `list_projects` / `get_deployment_status` | +| 配额 | `get_my_quota` | +| 只要链接 | `list_projects` 看 `url`;无则查 status | +| 运维直连 Dokploy | 仅明确要求时走 legacy | + +--- + +## 对用户话术 + +**成功:** + +- 已发布当前版本 +- 访问:`https://buxi….loncode.site/`(以 MCP 返回为准) +- 需要库时:说明已注入数据库连接(**不打印密码**) + +**失败:** + +- 配额满 / 未登录 Key / 构建失败 / 证书签发中 +- 给可执行下一步,不暴露平台密钥 + +--- + +## 安全红线 + +1. 永不 commit / 回显:`buxi_` Key、`MCP_AUTH_TOKEN`、Dokploy/Gitea Token、数据库密码全文 +2. `apply` 返回的 `connectionUrl` 已脱敏则保持;未脱敏则遮罩 +3. 普通用户不可查他人项目(控制面会 403) +4. 生产破坏性操作仍受控制面策略约束 + +--- + +## 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` | +| 无 MCP 的运维救火 | 本 skill → legacy | + +--- + +## 故障速查(MCP) + +| 现象 | 处理 | +|------|------| +| 401 / 要 Feishu Key | 引导连接中心登录,配置 `buxi_` | +| 运行中项目达上限 | `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 | diff --git a/dokploy-gitea-deploy/references/domain.md b/dokploy-gitea-deploy/references/domain.md new file mode 100644 index 0000000..2a1edd2 --- /dev/null +++ b/dokploy-gitea-deploy/references/domain.md @@ -0,0 +1,142 @@ +# 域名与 HTTPS + +## 默认路径:company-deploy-mcp(优先) + +业务部署 **不要** 手写 Dokploy `domain.create`。 +控制面在 `apply_deployment_plan` 内自动绑定域名并启用 HTTPS。 + +### 主机名规则 + +| 项 | 值 | +|----|-----| +| 格式 | `{prefix}{random}.{DOMAIN_ROOT}` | +| 默认 prefix | `buxi` | +| 默认 random | 5 位 `[a-z0-9]` | +| 默认根域 | `loncode.site`(以控制面 `DOMAIN_ROOT` 为准) | +| 示例 | `buxi3k9xa.loncode.site` | + +- **首次** `apply` 且 `exposeWeb !== false` 时分配 +- 分配后写入项目 mapping,**同 repo+environment 永久复用** +- 可用 `spec.domainHost` 指定固定 host(需 DNS 已解析到 Dokploy;一般业务勿用) +- `exposeWeb: false`:不绑公网域(Worker / 长连接机器人) + +### HTTPS / 证书 + +| 项 | 说明 | +|----|------| +| 默认 | `DOMAIN_HTTPS=true`,`certificateType=letsencrypt` | +| 实现 | Dokploy Traefik 按**具体子域**申请 Let’s Encrypt | +| **不需要** | 通配符证书(`*.loncode.site` 的 cert) | +| **需要** | DNS 把子域指到 Dokploy;**80/443** 公网可达(HTTP-01) | + +推荐 DNS(一次配好,所有项目共用): + +```text +*.loncode.site → A/AAAA → Dokploy 服务器 IP +``` + +这是通配 **解析**,不是通配证书。每个 `buxi*****.loncode.site` 各自签 LE。 + +### 交付链接 + +| 来源 | 字段 | +|------|------| +| `apply_deployment_plan` | `url`、`domain.host`、`domain.url` | +| `list_projects` | 每项 `url` / `domainHost` | +| `get_deployment_status` | 结合应用状态与 mapping | + +格式:`https:///`(控制面 `DOMAIN_HTTPS=false` 时才是 `http://`)。 + +Agent 探活: + +```bash +curl -skI "https://buxiXXXXX.loncode.site/" +# 或健康路径 +curl -skI "https://buxiXXXXX.loncode.site/healthz" +``` + +首次可能短暂 404 / TLS 握手失败:等 1–3 分钟 LE;仍失败查 DNS 与 80/443。 + +### Agent 红线(MCP 路径) + +1. **不要**再调 Dokploy `domain.create`(双绑/冲突) +2. **不要**要求业务用户填 `DOKPLOY_DOMAIN` +3. **不要**把错误的宿主机端口(如别人的 `:8080`)当成产品链接 +4. 证书失败:查基础设施,不要改业务代码「硬编码域名」进 Git + +细节与 plan 参数见 `mcp-deploy.md`。 + +--- + +## Legacy 路径:直连 Dokploy(运维例外) + +仅当用户明确要求不走 MCP,且存在项目 `.env.deploy` 时使用。 + +### 配置写在哪? + +| 位置 | 用途 | +|------|------| +| **项目根 `.env.deploy`** | Agent 读取;必须 gitignore | +| `env-deploy.example` | 模板 | +| Dokploy 面板 Domains | 人工补绑 | +| 域名注册商 DNS | 用户/运维配置 | + +### 方式 A:写死完整域名 + +```bash +DOKPLOY_EXPOSE_WEB=true +DOKPLOY_DOMAIN=crm.loncode.site +DOKPLOY_DOMAIN_HTTPS=true +DOKPLOY_DNS_READY=true +DOKPLOY_PORT=3000 +``` + +### 方式 B:根域 + slug + +```bash +DOKPLOY_EXPOSE_WEB=true +DOKPLOY_DOMAIN_ROOT=loncode.site +DOKPLOY_DOMAIN_PREFIX= +# DOKPLOY_DOMAIN 留空 → {PREFIX}{slug}.{ROOT} +``` + +与控制面 `buxi+5` 规则**不同**(legacy 多为 app 名 slug)。 +企业统一对外仍推荐 **MCP 的 buxi+5**,避免与连接中心体验分裂。 + +### 方式 C:非 Web + +```bash +DOKPLOY_EXPOSE_WEB=false +``` + +### Legacy API 示例 + +```bash +curl -sS -X POST \ + -H "x-api-key: $DOKPLOY_API_KEY" \ + -H "Content-Type: application/json" \ + -d "{ + \"host\": \"${DOKPLOY_DOMAIN}\", + \"applicationId\": \"${DOKPLOY_APPLICATION_ID}\", + \"https\": true, + \"certificateType\": \"letsencrypt\", + \"port\": ${DOKPLOY_PORT}, + \"path\": \"/\", + \"domainType\": \"application\" + }" \ + "${DOKPLOY_URL}/api/domain.create" +``` + +`host` **不要**带协议。证书同样依赖 DNS + 80/443。 + +--- + +## 故障速查 + +| 现象 | 处理 | +|------|------| +| 有 host 无 HTTPS | 等 LE;查 80 是否被占用/防火墙 | +| DNS NXDOMAIN | 配 `*.DOMAIN_ROOT` 或单条 A 记录 | +| 证书反复失败 | 确认公网能访问该 host 的 80 | +| 打开了错误站点 | 是否绑到了别的 applicationId | +| MCP 与 legacy 双绑 | 停掉一侧;优先只走 MCP | diff --git a/dokploy-gitea-deploy/references/env-deploy.example b/dokploy-gitea-deploy/references/env-deploy.example new file mode 100644 index 0000000..9dcef01 --- /dev/null +++ b/dokploy-gitea-deploy/references/env-deploy.example @@ -0,0 +1,77 @@ +# ═══ LEGACY ONLY ═══ +# 默认部署请走 company-deploy-mcp(飞书 + buxi_ Key),不要业务项目填本文件。 +# 仅运维 / 明确直连 Dokploy 时使用。 +# +# 复制到目标项目根目录: +# cp ~/.grok/skills/dokploy-gitea-deploy/references/env-deploy.example .env.deploy +# 填好后:set -a && source .env.deploy && set +a +# 必须 gitignore:.env.deploy + +# ── 授权 ── +DEPLOY_AUTHORIZED=false +ALLOW_SYNC_APP_ENV_TO_DOKPLOY=true +DO_GIT_PUSH=true +DO_DOKPLOY_DEPLOY=true +DO_HEALTHCHECK=true +FIX_DOCKERFILE=true + +PROJECT_DIR=. +APP_ENV_FILE=.env + +# ── Gitea ── +GITEA_URL=https://git.example.com +GITEA_USER= +GITEA_ORG= +GITEA_REPO= +GITEA_REPO_VISIBILITY=private +GITEA_REPO_EXISTS=false +GITEA_TOKEN= +GIT_PUSH_METHOD=https +GIT_BRANCH=main +GITEA_CLONE_URL= + +# ── Dokploy ── +DOKPLOY_URL=https://dokploy.example.com +DOKPLOY_API_KEY= +DOKPLOY_PROJECT_NAME= +DOKPLOY_APP_NAME= +DOKPLOY_APPLICATION_ID= +DOKPLOY_BUILD_TYPE=dockerfile +DOKPLOY_DOCKERFILE_PATH=Dockerfile +DOKPLOY_PORT=8080 +DOKPLOY_REPLICAS=1 +DOKPLOY_VOLUME_MOUNT= +DOKPLOY_HEALTHCHECK_PATH=/healthz +DOKPLOY_GIT_AUTH_METHOD=gitea_provider +DOKPLOY_GITEA_LINKED=false +# 首次部署后勿默认 true,除非依赖变了或缓存损坏 +DOKPLOY_CLEAN_CACHE=false + +# ── 域名 / 可访问链接(Web 页面必看)── +# 是否对外提供网页链接:true=部署成功后必须绑 Domain 并交付 https URL +# false=Worker/飞书长连接等,域名可选 +DOKPLOY_EXPOSE_WEB=true + +# 方式 A:完整主机名(优先)。不要写 https:// +# DOKPLOY_DOMAIN=crm.loncode.site + +# 方式 B:根域自动生成子域(DOKPLOY_DOMAIN 留空时生效) +# 最终 host = {DOKPLOY_DOMAIN_PREFIX}{slug}.{DOKPLOY_DOMAIN_ROOT} +# slug 默认取 DOKPLOY_APP_NAME 或 GITEA_REPO(小写,非法字符变 -) +# 建议 DNS 配:*.loncode.site → Dokploy 服务器 IP +DOKPLOY_DOMAIN= +DOKPLOY_DOMAIN_ROOT= +DOKPLOY_DOMAIN_PREFIX= + +# HTTPS / 证书(公网建议 true + letsencrypt) +DOKPLOY_DOMAIN_HTTPS=true +DOKPLOY_CERTIFICATE_TYPE=letsencrypt + +# DNS 是否已指向 Dokploy(true 时 Agent 会强调证书应能签发并做探活) +DOKPLOY_DNS_READY=false + +# ── 包源(构建)── +# Python / uv +PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/ +# Node(可选,写入构建环境或 .npmrc) +# NPM_CONFIG_REGISTRY=https://registry.npmmirror.com diff --git a/dokploy-gitea-deploy/references/mcp-deploy.md b/dokploy-gitea-deploy/references/mcp-deploy.md new file mode 100644 index 0000000..eb809d4 --- /dev/null +++ b/dokploy-gitea-deploy/references/mcp-deploy.md @@ -0,0 +1,301 @@ +# company-deploy-mcp 默认部署路径 + +**连接中心(飞书登录 + 拿 Key):** +`https://company-deploy-mcp.loncode.site/` + +**MCP endpoint:** +`https://company-deploy-mcp.loncode.site/mcp` + +Agent 配置示例(用户从连接中心复制,**不要**写进业务仓库): + +```json +{ + "mcpServers": { + "company-deploy": { + "url": "https://company-deploy-mcp.loncode.site/mcp", + "headers": { + "Authorization": "Bearer buxi_..." + } + } + } +} +``` + +- Key 前缀:`buxi_`(旧 `cdp_` 若仍存在可兼容,新发一律 `buxi_`) +- 身份:飞书 `open_id` 绑定到 Key;管理员另见 `ADMIN_OPEN_IDS` / 平台 `MCP_AUTH_TOKEN` +- **禁止**在 MCP 可用时向业务用户索要 Dokploy / Gitea Token + +--- + +## 工具一览 + +| 工具 | 读写 | 作用 | +|------|------|------| +| `whoami` | 读 | 当前身份、`role`(user/admin)、`openId` | +| `get_my_quota` | 读 | 运行中项目数 / 上限 / 剩余 | +| `list_projects` | 读 | 用户仅自己的;admin 全部 + Dokploy 运行态 | +| `inspect_project` | 读 | 某 repo+env 映射与策略(含存储策略说明) | +| `ensure_repository` | 写 | Gitea 建库(缺省组织私有库) | +| `create_deployment_plan` | 写 | 针对**已 push** 的 commit SHA 建计划 | +| `apply_deployment_plan` | 写 | 挂卷 → PG/MySQL → 域名/HTTPS → deploy | +| `get_deployment_status` | 读 | 应用与部署摘要(脱敏) | +| `get_sanitized_logs` | 读 | 脱敏诊断摘要 | + +`repo` 格式: + +- `Owner/name` 完整路径 +- 或仅 `name` → 控制面补默认 `GITEA_ORG` + +--- + +## 标准调用顺序(必须) + +```text +0. whoami / get_my_quota # 可选但推荐;配额满先处理 +1. 本地:Dockerfile + 数据写 /data + .gitignore +2. ensure_repository({ repo }) +3. git remote add/set-url + commit + push # Agent 本机企业凭据 +4. create_deployment_plan({ repo, commitSha, branch, environment, spec }) +5. apply_deployment_plan({ planId }) +6. get_deployment_status / list_projects 轮询 +7. curl 探活 apply 返回的 url(证书可能短暂签发中) +``` + +**Push 必须在 Agent 侧做**:MCP 在服务器上读不到用户工作区未提交文件。 + +--- + +## create_deployment_plan 参数 + +| 字段 | 类型 | 默认 | 说明 | +|------|------|------|------| +| `repo` | string | 必填 | 见上 | +| `commitSha` | string | 必填 | 7–64 位 hex,**已在 Gitea 上** | +| `branch` | string | `main` | 分支名 | +| `environment` | string | 控制面 `DEFAULT_DEPLOY_ENVIRONMENT`(常为 `default`) | **部署标签**(非 Dokploy preview/production);与 repo 组成唯一映射。查状态/重部署必须与首次 apply 相同 | +| `spec` | object | 必填 | 见下 | + +### `spec` 字段 + +| 字段 | 类型 | 默认 | 说明 | +|------|------|------|------| +| `buildType` | `"dockerfile"` | 必填 | MVP 仅 Dockerfile | +| `dockerfilePath` | string | `Dockerfile` | 路径须以 `Dockerfile` 结尾 | +| `buildPath` | string | `/` | 构建上下文 | +| `port` | number | 必填 | **容器内**监听端口(Traefik 转到这里) | +| `healthcheckPath` | string | `/` | 以 `/` 开头 | +| `persistence` | array | `[]` | 多卷;**缺 `/data` 时控制面自动补** | +| `databases` | array | `[]` | 托管 PG/MySQL,可选 | +| `exposeWeb` | boolean | `true` | `false` 则不绑公网域名(Worker 等) | +| `domainHost` | string | 省略 | 可选固定 host;省略则 `buxi`+5 随机 | + +### `persistence[]` 项 + +```json +{ + "name": "data", + "mountPath": "/data", + "hostPath": "/optional/host/path" +} +``` + +- `name`:逻辑名(命名 volume / 主机子目录用) +- `mountPath`:容器内绝对路径 +- `hostPath`:可选;bind 模式下省略则控制面生成 + `{HOST_DATA_ROOT}/{appSlug}/{name}` + +**应用约定:** 有状态数据必须写在挂载路径(如 SQLite → `/data/app.db`)。 +重部署同 `repo`+`environment` **不重新占配额**,卷与域名复用。 + +### `databases[]` 项 + +```json +{ + "engine": "postgres", + "name": "main", + "databaseName": "app", + "databaseUser": "app", + "envVar": "DATABASE_URL" +} +``` + +| 字段 | 说明 | +|------|------| +| `engine` | `postgres` 或 `mysql` | +| `name` | 逻辑名(多库区分);默认 `main` | +| `databaseName` / `databaseUser` | 可选覆盖 | +| `envVar` | 注入应用的环境变量名,默认 `DATABASE_URL` | + +`apply` 时:Dokploy 建库服务 → deploy 库 → 把连接串写入应用 env → 再构建应用。 +**勿**在聊天中打印完整 `connectionUrl`(返回侧会尽量脱敏)。 + +--- + +## 最小示例:纯 Web(自动域名 + 默认 /data) + +```json +{ + "repo": "my-web-app", + "commitSha": "a1b2c3d4e5f6...", + "branch": "main", + "environment": "default", + "spec": { + "buildType": "dockerfile", + "dockerfilePath": "Dockerfile", + "buildPath": "/", + "port": 3000, + "healthcheckPath": "/", + "exposeWeb": true + } +} +``` + +`apply` 成功后典型字段: + +```json +{ + "planId": "...", + "applicationId": "...", + "isNewProject": true, + "url": "https://buxi3k9xa.loncode.site", + "domain": { + "host": "buxi3k9xa.loncode.site", + "url": "https://buxi3k9xa.loncode.site", + "https": true + }, + "mounts": [{ "name": "data", "mountPath": "/data" }], + "databases": [], + "dataPathHint": { + "container": "/data", + "note": "Write application state under mounted paths..." + } +} +``` + +对用户只说:**已发布,访问 `https://buxi….loncode.site/`**(以实际返回为准)。 + +--- + +## 示例:多卷 + Postgres + +**部署标签必须用默认 `default`(或省略),除非用户明确要求并行第二套环境。** +禁止因「上线/生产」等话术擅自改成 `production`(与 Dokploy 的 production 环境无关,且会导致查不到项目)。 + +```json +{ + "repo": "Buxi/order-api", + "commitSha": "deadbeefcafebabe...", + "branch": "main", + "environment": "default", + "spec": { + "buildType": "dockerfile", + "dockerfilePath": "Dockerfile", + "buildPath": "/", + "port": 8080, + "healthcheckPath": "/healthz", + "exposeWeb": true, + "persistence": [ + { "name": "data", "mountPath": "/data" }, + { "name": "uploads", "mountPath": "/var/uploads" } + ], + "databases": [ + { + "engine": "postgres", + "name": "main", + "envVar": "DATABASE_URL" + } + ] + } +} +``` + +应用启动时读 `process.env.DATABASE_URL`(或所选 `envVar`)。 +若还要 MySQL 第二实例,再 push 一条 `{ "engine": "mysql", "name": "legacy", "envVar": "MYSQL_URL" }`。 + +--- + +## 示例:Worker(不暴露 Web) + +```json +{ + "repo": "job-worker", + "commitSha": "...", + "branch": "main", + "environment": "default", + "spec": { + "buildType": "dockerfile", + "dockerfilePath": "Dockerfile", + "buildPath": "/", + "port": 8080, + "healthcheckPath": "/healthz", + "exposeWeb": false + } +} +``` + +`url` / `domain` 可能为 null;用 `get_deployment_status` 看 Dokploy 运行态即可。 + +--- + +## apply 内部顺序(Agent 勿重复) + +控制面在 `apply_deployment_plan` 内按序完成: + +1. **配额**:仅**新建** mapping 时检查运行中数量 +2. **ensure Application**(已有则复用) +3. **ensureMounts**:默认 `/data`(Docker volume,无需预建宿主机目录)+ `persistence[]` +4. **ensureDatabases**:postgres/mysql + 注入 env +5. **ensureDomain**:`buxi`+5 随机 + Let’s Encrypt(见 `domain.md`) +6. **deploy** 应用镜像 + +Agent **不要**再直连 Dokploy 做 `domain.create` / `mounts.create` / 手建 DB(会双绑冲突)。 + +--- + +## 配额与归属 + +| 概念 | 行为 | +|------|------| +| 归属 | 首次成功 `apply` 的 `owner_open_id` | +| 配额 | 该用户 **Dokploy 运行中** 应用数 ≤ `MAX_RUNNING_PROJECTS_PER_USER`(常见 5) | +| 重部署 | 同 repo+env **不占新名额** | +| 可见性 | 普通用户只能 list/status 自己的;admin 看全部 | + +配额满错误:引导用户停掉旧应用或找管理员,**不要**绕过 MCP 硬推。 + +--- + +## 轮询建议 + +```text +apply 返回后: + 每 15–30s:get_deployment_status(repo, environment) + 或 list_projects 看 applicationStatus / running / url + 终态:构建成功且容器 running/done + Web:curl -skI "$url" 或健康路径 + 证书:首次 LE 可能需 1–3 分钟;DNS/80 未通会失败 +``` + +`create` 的 plan **只能 apply 一次**;失败或新版本 → 新 SHA 再 `create_deployment_plan`。 + +--- + +## 对用户话术(摘要) + +| 场景 | 说法 | +|------|------| +| 成功 | 已发布当前版本;访问:`https://…` | +| 有数据库 | 已配置托管数据库连接(不打印密码) | +| 配额满 | 运行中项目已达上限,请先停用不用的服务 | +| 未登录 | 打开连接中心飞书登录,把配置贴到 Agent | +| 构建中 | 正在构建,稍后自动检查 | +| 证书中 | 链接已分配,HTTPS 证书签发中,稍后再开 | + +--- + +## 安全 + +1. 永不 commit / 回显:`buxi_`、平台 Token、DB 密码全文 +2. 日志只用 `get_sanitized_logs` +3. `.env` / 密钥进 `.gitignore` +4. 生产破坏操作受控制面策略约束;不要教用户绕过 diff --git a/dokploy-gitea-deploy/references/sequence.md b/dokploy-gitea-deploy/references/sequence.md new file mode 100644 index 0000000..1731f9f --- /dev/null +++ b/dokploy-gitea-deploy/references/sequence.md @@ -0,0 +1,104 @@ +# 时序 + +## 默认:MCP 全链路(业务部署) + +```text +用户 Agent company-deploy-mcp Gitea Dokploy + │ │ │ │ │ + │ 部署/上线 │ │ │ │ + │─────────────────►│ │ │ │ + │ │ whoami / get_my_quota │ │ │ + │ │────────────────────────►│ │ │ + │ │ Dockerfile + 本地校验 │ │ │ + │ │ ensure_repository │ │ │ + │ │────────────────────────►│──建库(可选)─────►│ │ + │ │◄────────────────────────│◄─────────────────│ │ + │ │ git push(企业凭据) │ │ │ + │ │───────────────────────────────────────────►│ │ + │ │ create_deployment_plan │ │ │ + │ │────────────────────────►│ │ │ + │ │ apply_deployment_plan │ │ │ + │ │────────────────────────►│ │ │ + │ │ │ ensure app │ │ + │ │ │ mounts (/data+) │ │ + │ │ │ postgres/mysql? │ │ + │ │ │ domain buxi+5+LE │ │ + │ │ │ deploy ──────────┼──────────────►│ + │ │ │ │ clone/build │ + │ │ get_deployment_status │ │ run │ + │ │────────────────────────►│──status──────────┼──────────────►│ + │ │ 探活 https://buxi…. │ │ │ + │ 交付 HTTPS 链接 │ │ │ │ + │◄─────────────────│ │ │ │ +``` + +要点: + +- **建库 / 挂卷 / PG·MySQL / 域名 / deploy** 全在 MCP `apply` 内 +- **push** 只在 Agent 本机 +- 业务用户不接触 Gitea / Dokploy / Token + +参数与示例:`mcp-deploy.md`。域名与证书:`domain.md`。 + +--- + +## 日常二次发布(MCP) + +```text +用户 → Agent → git push → create_deployment_plan(新 SHA) + → apply_deployment_plan + → 复用 mapping(域名、卷、库、配额名额) + → 轮询 + 探活 +``` + +- 同一 `repo` + `environment`:**不新建** Dokploy 应用名额 +- 域名 host **不变** +- 数据卷 **不变**(应用须写在挂载路径) +- plan 一次性;每次发布新建 plan + +--- + +## Legacy:直连 Dokploy(运维例外) + +```text +用户 Agent Gitea Dokploy + │ │ │ │ + │ 明确要求直连 │ │ │ + │───────────────────►│ source .env.deploy │ │ + │ │ Dockerfile │ │ + │ │ 建仓+git push │ │ + │ │────────────────────►│ │ + │ │ application.* │ │ + │ │ mounts / domain │ │ + │ │ application.deploy │ │ + │ │──────────────────────────────────────────►│ + │ │ 轮询 + 探活 │ │ + │◄───────────────────│ │ │ +``` + +仅当 MCP 不可用且有 `.env.deploy` + `DEPLOY_AUTHORIZED=true`。 +默认对话 **不要** 走这条。 + +--- + +## 责任边界 + +| 角色 | MCP 路径 | Legacy 路径 | +|------|----------|-------------| +| 用户 | 飞书登录拿 `buxi_`;说「部署」 | 提供/保管 `.env.deploy`(运维) | +| Agent | 工程 + push + 调 MCP 工具 + 交付 URL | 工程 + push + 直调 Dokploy API | +| company-deploy-mcp | 身份/配额/审计/Gitea 建库/Dokploy 编排 | — | +| Gitea | 源码 | 源码 | +| Dokploy | 构建运行/卷/库/Traefik+LE | 同左(Agent 直调) | + +--- + +## 异步语义 + +| 动作 | 含义 | +|------|------| +| `apply_deployment_plan` 返回 200 | 已受理编排与 deploy 请求 | +| `deploymentRequested: true` | 不等于用户已可稳定访问 | +| 上线完成 | Dokploy 部署终态成功 +(Web)HTTPS 探活通过 | + +构建失败:`get_deployment_status` / `get_sanitized_logs`,修代码或 Dockerfile 后新 SHA 再 plan+apply。 diff --git a/dokploy-gitea-deploy/references/stack-profiles.md b/dokploy-gitea-deploy/references/stack-profiles.md new file mode 100644 index 0000000..b571c10 --- /dev/null +++ b/dokploy-gitea-deploy/references/stack-profiles.md @@ -0,0 +1,183 @@ +# 技术栈构建约定(Agent 改 Dockerfile 时遵循) + +## 通用 + +1. 基础镜像:Docker Hub(`python:*` / `node:*` / `nginx:*`),避免默认 `ghcr.io`。 +2. 多阶段或「依赖层 → 代码层」拆分。 +3. BuildKit:`--mount=type=cache` 缓存包管理器目录。 +4. 生产 `CMD`/`ENTRYPOINT` 明确;进程监听 **`spec.port`**(与 plan 一致)。 +5. 健康检查:实现 `/healthz` 或约定路径,写入 `spec.healthcheckPath`。 +6. Dokploy **不要每次 cleanCache**。 +7. **有状态数据写挂载路径**(见下),不要只写容器可写层。 + +--- + +## 持久化与 `/data`(MCP 默认) + +控制面默认为每个应用挂载 **容器内 `/data`**(可配置,见 `inspect_project` → `policy.storage`)。 + +| 约定 | 说明 | +|------|------| +| SQLite / 本地文件 | 路径放在 `/data/...`,例如 `/data/app.db` | +| 上传目录 | 额外 `persistence`:`{ "name": "uploads", "mountPath": "/var/uploads" }` | +| 日志 | ephemeral 可写容器内;需保留则挂卷 | +| 多卷 | `spec.persistence[]`;若未包含 `/data`,控制面仍自动补默认卷 | + +示例环境变量(应用代码侧): + +```text +DATA_DIR=/data +DATABASE_PATH=/data/app.db +``` + +**禁止**假设宿主机路径;只认容器内 `mountPath`。 + +--- + +## 托管数据库(Postgres / MySQL) + +plan 中声明 `spec.databases[]` 后,控制面注入连接串环境变量(默认名 `DATABASE_URL`)。 + +应用应: + +1. 启动时读取 `process.env.DATABASE_URL`(或自定义 `envVar`) +2. **不要**在镜像里写死密码 +3. 迁移在启动脚本或独立 job 中执行(注意并发与锁) + +示例(Node): + +```js +const url = process.env.DATABASE_URL; +if (!url) throw new Error("DATABASE_URL is required"); +``` + +示例(Python): + +```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`。 + +推荐结构: + +```dockerfile +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`。 + +推荐结构(standalone / 需 `node` 运行): + +```dockerfile +FROM node:22-bookworm-slim AS deps +WORKDIR /app +RUN corepack enable +COPY package.json pnpm-lock.yaml ./ +# 可选:COPY .npmrc ./ +RUN --mount=type=cache,target=/root/.local/share/pnpm/store \ + pnpm install --frozen-lockfile + +FROM node:22-bookworm-slim AS build +WORKDIR /app +RUN corepack enable +COPY --from=deps /app/node_modules ./node_modules +COPY . . +RUN pnpm run build + +FROM node:22-bookworm-slim AS runner +WORKDIR /app +ENV NODE_ENV=production +ENV DATA_DIR=/data +COPY --from=build /app/dist ./dist +COPY --from=build /app/package.json ./ +COPY --from=deps /app/node_modules ./node_modules +EXPOSE 3000 +CMD ["node", "dist/index.js"] +``` + +静态前端(Vite 等)可用 `nginx:stable-alpine` 拷 `dist`;`spec.port` 多为 `80`。 + +Registry 加速示例 `.npmrc`(可提交或构建时注入): + +```ini +registry=https://registry.npmmirror.com +``` + +--- + +## 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