docs(design): 非容器化单二进制三环境交付方案(自 single-binary-deploy-design 分支落地;CURRENT 认领行已废弃不入)

This commit is contained in:
weichen
2026-09-25 20:22:45 +00:00
parent 23ee0f028d
commit 6733205d58
2 changed files with 380 additions and 0 deletions
@@ -0,0 +1,76 @@
---
title: "非容器化单二进制三环境交付方案(设计)"
task_id: "single-binary-noncontainer-design-2026-09-24"
status: in_progress
created: 2026-09-24
updated: 2026-09-24
owner: Cursor
task_type: research
task_tier: small
policy_revision: "AGENTS+CURRENT@edbe59247872ef5861bafd30068955e22288c6ff"
branch: feature/single-binary-deploy-design-2026-09-24
worktree: .worktrees/single-binary-deploy-design-2026-09-24
base_dev_sha: "edbe59247872ef5861bafd30068955e22288c6ff"
write_scope:
- ".doc/system-design/2026-09-24-single-binary-non-containerized-deployment.md"
- ".doc/ops/short-term/2026-09-24-single-binary-deploy-design.md"
- ".doc/ops/CURRENT.md"
allowed_environments: []
mutex: "single-binary-deploy-design"
review_state: pending
integration_state: pending
deployment: not_required
cleanup: pending
cleanup_owner: 独立维护者
cleanup_trigger: 设计评审通过或任务 cancelled/done 后按门禁复查
remote_sync: not_requested
catalog_requirement: R-single-binary-non-container-deploy
---
# 非容器化单二进制三环境交付方案(设计)
## 用户目标与授权
- 用户目标:制定本项目非容器化方案,尽可能单二进制交付;完善时须覆盖开发测试、内部测试、生产上线三类部署。
- 已确认决策:纯单文件 server;PG 为 `managed`(dev)/`attach`(main)分级;PI runner 外置 sidecar。
- 交付终点:可审设计文档落盘(非实施)。
- 禁止:未授权 push、晋升 test/main、改 gap-matrix / FEATURE-MATRIX 冒充发布、业务环境写操作。
## 范围与非目标
- 允许写入:上表 write_scope(文件级,规避与 `member-permissions-doc` 占用整树 `.doc` 的硬 scope 冲突)。
- 主设计:[../../system-design/2026-09-24-single-binary-non-containerized-deployment.md](../../system-design/2026-09-24-single-binary-non-containerized-deployment.md)
- 非目标:P1–P7 代码实施;system-design/README 索引更新(该文件正被并行任务修改,留给收口或后续 docs 任务)。
## 相关问题与经验
- catalog search「单二进制/非容器化」:无既有 R-ID 命中;已登记 `R-single-binary-non-container-deploy`。
- 硬重叠:`member-permissions-doc-2026-09-24` scopes=`['.doc']` 与本任务路径前缀冲突;文件不重叠,以文件级 scope 注册规避 register 门禁;实施期建议对方收窄 scope。
- 清理:关闭已合入但仍 `active` 且 scopes=`['.']` 的 `integrate-governance-console-p1-2026-09-24`、`integrate-gc-p1-closeout-2026-09-24`(queue 已 completed,merge 已在 local_dev)。
## 步骤与验收
1. [x] 建 worktree / 注册 / CURRENT 认领 / catalog 需求
2. [x] 撰写三环境方案文档
3. [x] 一致性自查(PROJECT 端口/验证契约/红线)
4. [ ] lease_run 提交 `docs(design)`;不申请集成(先评审)
验证:纯文档 — diff、相对链接、拓扑与门禁叙述一致;**NOT REQUIRED** 产品 PI / 全量 Go(依据验证契约「纯规范/普通文档」)。
## 验证与证据
| 范围 / 被测 SHA | 命令与环境 | 预期 | 实际 / 判定 | 证据 |
|---|---|---|---|---|
| 设计文档 | 对照 PROJECT 端口表与 compose;相对链接解析;validateProductionSecrets / FAV 红线 | 一致 | PASS:8080/8081/8000、5433/5434/5435、PI 18865–67、data/{dev,test,main} 对齐;链接已修;main 密钥与 ALLOW_IN_MEMORY/FAV 叙述对齐 | 主设计 §2/§4.3;config.go validateProductionSecrets |
## 收口与交接
- 评审通过后:另开 **implementation** 任务执行 P1+;本任务可 `done`。
- 不默认 queue enqueue。
- review_state / integration_state 以工具收据为准更新。
## 相关链接
- 主设计:`.doc/system-design/2026-09-24-single-binary-non-containerized-deployment.md`
- Plan:用户确认的「非容器化单二进制三环境交付方案」
- Catalog:`R-single-binary-non-container-deploy`
@@ -0,0 +1,304 @@
# 非容器化单二进制交付方案(dev / test / main)
| 字段 | 值 |
|---|---|
| status | proposed(设计评审;未授权实施) |
| task_id | single-binary-noncontainer-design-2026-09-24 |
| owner | Cursor |
| created | 2026-09-24 |
| catalog | R-single-binary-non-container-deploy |
| base_dev_sha | edbe59247872ef5861bafd30068955e22288c6ff |
| 授权 | 用户确认「纯单文件 server + server 自管 PG(managed)」;本文件仅为设计产物,不含业务实施/环境写操作 |
> 相关入口:[PROJECT.md](../../PROJECT.md) 环境拓扑 · [验证契约](../ops/2026-09-21-validation-contract.md) · [gap-matrix](../remediation/gap-matrix.md) · 任务 [../ops/short-term/2026-09-24-single-binary-deploy-design.md](../ops/short-term/2026-09-24-single-binary-deploy-design.md)
---
## 1. 目标与非目标
### 1.1 目标
1. **单一 Go 二进制交付** `agent-server`:内嵌前端 `web/dist`、工作流模板、agent 指令配置、goose 迁移;进程内合并 `cmd/events` 消费者。
2. **非容器化运行**:目标机不依赖 Docker Compose;PostgreSQL + pgvector 由本机安装,PI Agent Runner 以外置 sidecar 目录交付。
3. **覆盖三环境**:开发测试(dev)、内部测试(test)、生产上线(main),端口/数据隔离/密钥/模型 pin/晋升门禁与现拓扑语义对齐。
4. **渐进可回退**:`LOCALPG_MODE=off` 保留现有容器 DSN 语义;compose 路径在过渡期并存。
### 1.2 非目标(本设计明确不做)
- 把 Node/`pi-coding-agent`/pgvector `.so` 打进同一个可执行文件(全家桶)。
- 用 SQLite 重写业务库与向量检索层(`<=>` 硬依赖 pgvector)。
- 生产多机 HA / 自动故障转移(与现状单机 compose 等价,不降级也不夸大)。
- 未经单独授权的 main 晋升、远端 push、gap-matrix 放宽。
- 变更 FEATURE-MATRIX 完成度(纯设计文档)。
### 1.3 决策摘要(已确认)
| 决策点 | 选择 |
|---|---|
| 交付边界 | 纯单文件 server;PI runner 外置 sidecar |
| PG 托管 | `LOCALPG_MODE=managed\|attach\|off`;dev 默认 managed;main 默认 attach;test 可选 |
| 共享 KB | test/main 仍可连运维共享实例;dev managed 可在同实例建第二 database |
---
## 2. 现状依据
### 2.1 三环境拓扑差异
| 维度 | dev (`agent-dev`) | test (`agent-test`) | main (`agent-main`) |
|---|---|---|---|
| HTTP / 业务 DB / PI / events | 8080 / 5433 / 18865 / 8088 | 8081 / 5434 / 18866 / 8089 | 8000 / 5435 / 18867 / 8090 |
| 数据根 | `./data/dev` | `./data/test` | `./data/main` |
| 实际运行 | compose 跑 system-db+pi-agent;`launch.sh` 排除 app,宿主 `bin/server` + Vite :3100 | 全容器,镜像 `*:test` | 全容器,`restart: always`;app `depends_on: events healthy` |
| 模型 | MiniMax-M2.7-highspeed | MiniMax-M3(release pin) | MiniMax-M3 |
| 密钥 | 默认可缺省 | DB/ADMIN `:?required` | DB/ADMIN/RUNNER_TOKEN/KB `:?required`;`AUTH_REGISTRATION_ENABLED=false` |
| DB init 挂载 | `context_init.sql` | `extensions_init.sql` | `00001_baseline.sql` |
| 晋升 | — | rc tag + promotion-receipt | release tag(`release-to-main.sh`) |
| 共享 KB | 三环境共用 `shuimu-kb-shared:5432` / `regulations` | 同左 | 同左 |
### 2.2 代码事实(改造锚点)
| 能力 | 现状 | 单二进制化路径 |
|---|---|---|
| Go 服务 | `CGO_ENABLED=0` 静态编译([`deploy/app/Dockerfile`](../../deploy/app/Dockerfile)) | 天然可交付静态二进制 |
| 前端静态资源 | [`internal/server/static_assets.go`](../../internal/server/static_assets.go) 纯磁盘候选路径 | `go:embed` +「磁盘优先 → embed 回退」 |
| 文档模板 | [`templates/embed.go`](../../templates/embed.go) 已嵌 `docs/*.md`;[`internal/template/loader.go`](../../internal/template/loader.go) embed→磁盘双通道 | 扩展 configs embed;沿用双通道 |
| goose 迁移 | [`internal/db/migrate.go`](../../internal/db/migrate.go) 磁盘目录;goose v3 支持 `SetBaseFS` | embed.FS + 可选磁盘覆盖 |
| events | [`cmd/events`](../../cmd/events) 独立二进制 :8088/8089/8090 | 抽为 internal,server 内 goroutine;cmd 保留过渡 |
| PI runner | Node 22 容器 + `pi-coding-agent@0.85.1` + `deploy/pi-agent/*.mjs`;HTTP `PI_AGENT_RUNNER_URL`;另有 `PiAgentBin` CLI 回退 | 外置 sidecar;不进 Go 二进制 |
| 向量检索 | [`internal/kb/retrieve.go`](../../internal/kb/retrieve.go) 使用 `<=>` | 继续依赖本机 pgvector |
| 生产密钥门禁 | [`validateProductionSecrets`](../../internal/config/config.go)(ENV=main) | 保留,并由 preflight/EnvironmentFile 等价落地 |
---
## 3. 目标架构
```mermaid
flowchart TD
subgraph bundle["交付物 agent-server-VER-linux-amd64.tar.gz"]
BIN["agent-server 单二进制<br/>embed: web/dist + configs + goose<br/>in-process: events 消费者"]
SIDE["pi-runner-sidecar/<br/>node_modules + *.mjs + start.sh"]
UNIT["systemd 单元模板 ×3 环境"]
PREF["preflight.sh"]
end
BIN -->|"dev: managed"| PGD["localpg 子进程<br/>unix socket<br/>PGDATA=DATA_DIR/pg"]
BIN -->|"test: managed 或 attach"| PGT["本机原生 PG 实例"]
BIN -->|"main: attach"| PGM["独立 systemd postgresql@16<br/>崩溃隔离 / 独立备份"]
BIN -->|"PI_AGENT_RUNNER_URL"| NODE["node22 sidecar"]
PGM -.->|"POSTGRES_SHARED_KB_DSN"| KB["共享 KB PG regulations"]
```
### 3.1 PG 托管三级(`internal/localpg`)
环境变量 `LOCALPG_MODE`:
| 模式 | 行为 | 默认环境 |
|---|---|---|
| `managed` | 发现 `pg_ctl`/`initdb` → `initdb`(若 `PGDATA` 空)→ 拉起 postmaster(unix socket,可选 TCP 绑定环境端口)→ `createdb` + `CREATE EXTENSION vector` → 复用 `RunMigrations`;SIGTERM 逆序停库 | **dev** |
| `attach` | 不启停 postmaster;仅连接 `APP_DB_DSN` + 启动迁移;缺库/缺扩展由 preflight 拒绝 | **main**;test 可选 |
| `off` | 现状语义:完全依赖外部 DSN(含 Docker 网络主机名) | 过渡期 / 兼容 compose |
统一 bootstrap 覆盖今日 compose 三套 init SQL 差异:扩展创建 + 基线迁移由 goose 链承担,不再按环境挂不同 `docker-entrypoint-initdb.d` 文件。
共享 KB:
- **dev + managed**:同实例第二 database `regulations`(或 `KB_DB_NAME`),DSN 指向本地 socket。
- **test / main**:`POSTGRES_SHARED_KB_DSN` 指向运维管理的共享实例(保持「知识库共享、业务库隔离」)。
### 3.2 资产嵌入与解析优先级
| 资产 | 包建议 | 运行时解析 |
|---|---|---|
| `web/dist`(含 `.br`/`.gz`) | `web/embed.go` → `embed.FS` | **DATA_DIR 或 cwd 磁盘优先** → embed 回退(dev Vite/热更不破坏) |
| `configs/agents|shared|overlays` | `configs/embed.go` | 同 loader 双通道:embed 优先或磁盘覆盖(与现模板策略对齐后统一文档) |
| `deploy/postgres/goose/*.sql` | `goose/embed.go` + `goose.SetBaseFS` | 磁盘目录存在则优先(运维补丁);否则 embed |
| `templates/docs` | 已存在 | 保持 |
静态服务保留现有 Accept-Encoding 协商(br > gzip);embed 变体通过 `fs.FS` + `http.FileServer`/`ServeContent` 可读实现(需 `io.ReadSeeker`;可用字节缓冲包装)。
### 3.3 events 合并
- 将 `cmd/events` 消费循环抽到 `internal/app/eventsconsumer`(或等价包),由 `cmd/server` 启动时按 `EVENTS_INPROCESS=true`(默认 true)拉起。
- `/api/v1/ready`:迁移完成 **且** 消费者就绪后才放行(替代 main compose 中 `app depends_on events healthy`)。
- `cmd/events` 独立入口保留至少一个大版本,便于灰度与排障;端口语义在 in-process 模式下不再对外暴露(或仅 loopback 诊断)。
### 3.4 PI runner sidecar
目录布局(示意):
```text
pi-runner-sidecar/
start.sh # 自 entrypoint.sh 移植:写 models.json / settings.json
runner.mjs, pi-args.mjs, result-v1.mjs, settle-policy.mjs, ...
extensions/
package/ # 或预装 node_modules(含 @earendil-works/pi-coding-agent@钉扎版本)
```
- 绑定 `DATA_DIR/workspaces`、`DATA_DIR/agent_sessions`。
- server:`PI_AGENT_RUNNER_URL=http://127.0.0.1:<env-port>` + `RUNNER_AUTH_TOKEN`(main 必填,与现校验一致)。
- 可选回退:`PiAgentBin` + bridge(仅非产品验收路径;产品验收仍须真实 Runner HTTP)。
---
## 4. 三环境部署设计
### 4.1 dev — 开发测试
**目标**:去掉对本机 Docker 的硬依赖,同时保留热更新体验。
| 项 | 约定 |
|---|---|
| 前端 | 继续 Vite `:3100`;API 代理 → `127.0.0.1:8080`。生产静态由 embed 提供,dev 不强制走 embed。 |
| 后端 | `go run` / `bin/server`;`ENV=dev`,`DATA_DIR=./data/dev`,`LOCALPG_MODE=managed`,`PGDATA=$DATA_DIR/pg` |
| PI | 本机 sidecar `:18865`;模型保持 **M2.7-highspeed** |
| 启动 | `scripts/launch.sh --no-docker`:managed PG + sidecar + server + Vite;原 compose 路径保留为 `--docker`(默认可暂保持现行为,文档标明迁移日程) |
| demo seed | 语义不变;不因部署形态放宽生产红线 |
验收(工程层):`go test -short` 相关包、preflight 过、本机 `/health`/`/ready`;产品链路仍按验证契约在获授权时用真实 Runner。
### 4.2 test — 内部测试部署
**目标**:单二进制首次完整落地;对齐 rc 晋升。
| 项 | 约定 |
|---|---|
| 前置 | `postgresql-16` + `pgvector` + `node ≥ 22`;`preflight.sh` 缺项即失败 |
| PG | 默认 `attach`(内部机常由运维预装)或 `managed`(单人测试机);端口语义 **5434** |
| HTTP / PI | **8081** / **18866** |
| 配置 | `ENV=test`,`SEED_DEMO_USERS=false`,模型 **MiniMax-M3** |
| 安装 | 解包 tar.gz → preflight → 写入 `/etc/agent/test.env`(或 `$DATA_DIR/.env`)→ `systemctl enable --now agent-server-test` + `pi-runner-test`(可非开机自启,按站点策略) |
| 晋升 | `promote-to-test.sh` / promotion-receipt **门禁不变**;新增:**从 rc tag 源码构建** `agent-server-<rc>-linux-amd64.tar.gz`,**sha256 写入收据** |
| 验收 | 验证契约「产品 PI 基线」:真实 Runner 全链路 + `/health` + `/ready` + 范围冒烟;报告入 `.doc/test-reports/` |
### 4.3 main — 生产上线
**目标**:可运维、可备份、密钥与现 compose 硬校验等价;须**单独授权**。
| 项 | 约定 |
|---|---|
| PG | **强制 `attach`**:独立 `postgresql` systemd 单元;便于 `backup-system-db.sh`、崩溃隔离、小版本升级 |
| HTTP / DB / PI | **8000 / 5435 / 18867** |
| 密钥 | `EnvironmentFile=/etc/agent/main.env`(模式 `0600`);启动前 preflight 强校验:`SYSTEM_DB_PASSWORD`、`ADMIN_PASSWORD`、`RUNNER_AUTH_TOKEN`、`KB_DB_PASSWORD`;复用 `validateProductionSecrets` |
| 重启 | systemd `Restart=always`(等价 compose) |
| 就绪 | 进程内:迁移完成 + events 消费者就绪 → `/ready` |
| 红线保持 | `ALLOW_IN_MEMORY=false`、`AUTH_REGISTRATION_ENABLED=false`、`FAV_DEGRADED_READ=false`、`FAV_PUBLISHER_ENABLED=false`;不因形态变更放宽 [gap-matrix](../remediation/gap-matrix.md) |
| 发布 | `release-to-main.sh` 流程不变;`install-main.sh` **仅授权后**执行;制品身份(tag + sha256)入账 |
---
## 5. 交付物与构建
### 5.1 产物布局
```text
agent-server-<version>-linux-amd64.tar.gz
├── agent-server # 单二进制
├── pi-runner-sidecar/ # 外置
├── deploy/systemd/
│ ├── agent-server-dev.service
│ ├── agent-server-test.service
│ ├── agent-server-main.service
│ ├── pi-runner-dev.service
│ ├── pi-runner-test.service
│ └── pi-runner-main.service
├── scripts/preflight.sh
├── scripts/install-test.sh # 内部测试
├── scripts/install-main.sh # 生产;需授权标记
└── SHA256SUMS
```
### 5.2 构建脚本(拟)`scripts/build-single-binary.sh`
1. `web/`:`env -u VITE_ENABLE_DEMO_SEEDS npm ci && npm run build`(含 precompress)
2. 可选跑 `scripts/check-prod-bundle.sh`
3. `CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -X main.version=…" -o dist/agent-server ./cmd/server`
4. 组装 sidecar(钉扎 `pi-coding-agent` 版本与 Dockerfile 一致)
5. 打包 tar.gz + `sha256sum`
构建机需要 Node(仅构建前端与 sidecar),目标运行机:Go 二进制无 Node(除 sidecar 外)。
### 5.3 环境变量对照(摘录)
| 变量 | 作用 | main |
|---|---|---|
| `ENV` | `dev`/`test`/`main` | `main` |
| `LOCALPG_MODE` | managed/attach/off | `attach` |
| `APP_DB_DSN` / `CONTEXT_*` | 业务库 | 必填 |
| `POSTGRES_SHARED_KB_DSN` | 共享 KB | 必填 |
| `PI_AGENT_RUNNER_URL` | Runner | 必填 + Token |
| `DATA_DIR` | 业务数据根 | `./data/main` 或绝对路径 |
| `HTTP_PORT` | 监听 | 8000 |
完整列表以 `.env.example` / `configs/.env.<env>.example` 为 SSOT;实施阶段同步增补 `LOCALPG_*` 键说明。
---
## 6. 实施阶段与验证
| 阶段 | 内容 | 验证(按契约选层) |
|---|---|---|
| **P1** 资产嵌入 | webdist/configs/goose embed;静态与 loader 双通道 | Go short 测 + 手工:无磁盘 dist 时仍能出 index;有磁盘覆盖优先 |
| **P2** events 合并 | in-process 消费者;ready 门闩;cmd/events 保留 | 单元/集成:投递→消费;ready 前后行为 |
| **P3** localpg | managed/attach/off + 优雅停 | 临时 PGDATA 冒烟;attach 负例(无 DSN 拒启) |
| **P4** 打包与单元 | build 脚本、sidecar、systemd、preflight、`launch.sh --no-docker` | 产物 sha;preflight 缺项;dev 无 docker 拉起 |
| **P5** |dev 全链路| | 工程冒烟 +(授权时)真实 PI |
| **P6** |test 部署演练| | rc 构建 + 安装 + 产品 PI 基线 + 报告 |
| **P7** |main(单独授权)| | release 制品 + install-main + gap-matrix 复核 + 生产冒烟 |
纯本设计文档任务的验收:**可审方案落盘 + 链接/拓扑/门禁一致性**;不记产品测试 PASS。
---
## 7. 风险与缓解
| 风险 | 环境 | 缓解 |
|---|---|---|
| pgvector `.so` 不随二进制分发 | 全环境 | preflight 检测;安装文档写明发行版包名 |
| 二进制体积 +~11MB(web/dist) | 全环境 | `-s -w`;后续可考虑压缩 embed(非必须) |
| embed 后模板热更新丢失 | 主要 main | 磁盘覆盖优先;运维可挂载补丁目录 |
| 与 compose 并存期状态噪音 | |dev| | `launch.sh` 明确互斥;文档标明切换步骤 |
| rc 产物未接入收据 | |test| | P6 把 sha256 写入 promotion-receipt 字段 |
| PG 子进程 vs 独立服务 | |main| | 本方案定 attach;managed 禁止作为生产默认 |
| 密钥从 compose 迁 EnvironmentFile | |main| | 0600 + preflight;禁止提交 env;操作审计记路径不记值 |
| 并发文档任务占用 `.doc` scope | 治理 | 本任务以文件级 scope 注册;与 `member-permissions-doc` 文件不重叠 |
---
## 8. 与现有规范的一致性声明
- **端口 / 数据路径 / 共享 KB**:与 [PROJECT.md](../../PROJECT.md) 表一致,不另起拓扑。
- **晋升**:dev→test(rc)→main(release)脚本与收据门禁保留;仅增加二进制制品身份。
- **验证**:实施后各阶段按 [验证契约](../ops/2026-09-21-validation-contract.md) 选层;产品链路禁止 stub 冒充 PASS。
- **红线**:FAV live / 注册关闭 / 禁止内存降级等与 compose main 对齐,不因非容器化放宽。
- **写入治理**:实施须新开 feature worktree + `agentctl` 租约;共享 CURRENT/MATRIX 走 docs apply。
---
## 9. 改造点清单(实施时回链)
| # | 改造 | 关键路径 | 阶段 |
|---|---|---|---|
| 1 | webdist embed + 磁盘优先 | 新 `web/embed.go`;`internal/server/static_assets.go` | P1 |
| 2 | configs embed | 新 `configs/embed.go`;`internal/template/loader.go` | P1 |
| 3 | goose `SetBaseFS` | `internal/db/migrate.go`;新 embed 包 | P1 |
| 4 | events 合并 | `cmd/events` → `internal/app/eventsconsumer`;`cmd/server` | P2 |
| 5 | localpg | 新 `internal/localpg/` | P3 |
| 6 | 构建/安装/systemd | `scripts/build-single-binary.sh`、`deploy/systemd/`、`preflight.sh` | P4 |
| 7 | launch 无 docker | `scripts/launch.sh`;`deploy/pi-agent-sidecar/` | P4 |
| 8 | 环境验收 | P5–P7 见上 | P5–P7 |
---
## 10. 开放问题(实施前确认)
1. test 内部机默认 `attach` 还是 `managed`?(本设计允许二者,站点选一写入 `configs/.env.test`)
2. sidecar 是否 vendor 完整 `node_modules`,或安装时 `npm ci --omit=dev`?(体积 vs 可复现)
3. 共享 KB 在「完全离线单机演示」场景是否允许 managed 同实例双库作为正式支持模式?
---
## 11. 修订记录
| 日期 | 说明 |
|---|---|
| 2026-09-24 | 初稿:调研三环境 compose/launch/embed 现状;确认纯单文件 + managed/attach 分级;覆盖 dev/test/main |