Make deployment truth and remaining graduation gates explicit
Some checks failed
verify / verify (push) Has been cancelled
Some checks failed
verify / verify (push) Has been cancelled
Document the runnable Docker workflow, expected one-shot container exits, server-controlled Bailian namespace switch, current earned progress, and the security and evaluation work that still blocks private-data or graduation release claims. Constraint: Current local Bailian credentials are rejected by the configured workspace Rejected: Mark the project complete from synthetic metrics | would overstate provider, OCR, authorization, and blind-evaluation readiness Confidence: high Scope-risk: narrow Directive: Keep progress evidence task-based and distinguish synthetic engineering validation from real geological efficacy Tested: make verify-design; Markdown links; secret scan; diff checks Not-tested: Final thesis review and live provider authorization
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
| 项目 | 设计值 |
|
||||
|---|---|
|
||||
| 部署方式 | Docker Compose 单机 |
|
||||
| 长期服务 | 当前 `web`、`gateway`、`api`、`model-gateway`、`db`;后续加入 `worker` |
|
||||
| 一次性服务 | `migrate` |
|
||||
| 长期服务 | `web`、`gateway`、`api`、`model-gateway`、`worker-local`、`worker-model`、`db` |
|
||||
| 一次性服务 | `migrate`、`upload-init`;成功后正常 `Exited (0)` |
|
||||
| 对外端口 | 仅 Nginx/Web |
|
||||
| 密钥 | Docker Secret / Secret Manager |
|
||||
| 数据库 | PostgreSQL 17 + pgvector 0.8.x(实现时固定 digest) |
|
||||
@@ -17,7 +17,10 @@
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
这条命令当前完成数据库健康等待、一次性迁移、`model-gateway`、API、入口 Gateway 和 Web 启动;Worker 落地后也遵循同一依赖链。它不等于“所有数据和模型凭证自动生成”,首次部署仍必须完成密钥轮换、Secret 创建和三模型能力探测。
|
||||
这条命令当前完成数据库健康等待、一次性迁移、上传卷初始化、两个最小权限 Worker、
|
||||
`model-gateway`、API、入口 Gateway 和 Web 启动。`migrate` 与 `upload-init` 成功后显示
|
||||
`Exited (0)` 是预期终态,不是服务暂停。它不等于“所有数据和模型凭证自动生成”,首次部署
|
||||
仍必须创建本地 Secret;真实模式还必须完成密钥轮换和三模型能力探测。
|
||||
|
||||
架构定位是适合毕设、演示和单机内部使用的生产式单节点,不宣称跨主机高可用。互联网生产环境应替换托管数据库、对象存储和集中密钥管理。
|
||||
|
||||
@@ -29,10 +32,12 @@ docker compose up -d --build
|
||||
|---|---|---|---|
|
||||
| `db` | 固定版本 pgvector 镜像 | 元数据、向量、任务、会话、评测 | 仅内部网络 |
|
||||
| `migrate` | 与后端同镜像 | 运行 Alembic,一次成功退出 | 无 |
|
||||
| `upload-init` | 与后端同镜像 | 无网络初始化上传卷属主,一次成功退出 | 无网络 |
|
||||
| `api` | `backend/Dockerfile` | FastAPI、检索、问答、管理 API | 仅 internal data/model 网络 |
|
||||
| `gateway` | 与后端同镜像 | 固定上游、请求边界、脱敏错误和流式转发 | 仅 internal ingress/data 网络 |
|
||||
| `model-gateway` | 与后端同镜像 | 唯一读取百炼 Key,代理 Embedding/Rerank/Chat | 仅 internal model + egress 网络,无宿主机端口 |
|
||||
| `worker` | 同一后端镜像 | 解析、向量化、评测后台任务 | 无 |
|
||||
| `worker-local` | 同一后端镜像 | 本地文件验证、解析、切分;有上传卷,无模型网络/Token | 仅 internal data 网络 |
|
||||
| `worker-model` | 同一后端镜像 | 只处理已审批文本的向量化;无上传卷 | 仅 internal data/model 网络 |
|
||||
| `web` | `frontend/Dockerfile` | React 静态资源、Nginx 同源入口和 SSE 代理 | `127.0.0.1:8000`;生产部署 HTTPS |
|
||||
| `ocr-worker` | 可选 profile | PaddleOCR 重型任务 | 无 |
|
||||
| `prometheus/grafana` | 可选 profile | 本地观测 | 默认不对公网 |
|
||||
@@ -121,6 +126,20 @@ services:
|
||||
networks: [data]
|
||||
restart: "no"
|
||||
|
||||
upload-init:
|
||||
build: ./backend
|
||||
command: ["python", "-m", "app.tools.init_upload_storage"]
|
||||
environment:
|
||||
UPLOAD_ROOT: /data/uploads
|
||||
user: "0:0"
|
||||
network_mode: none
|
||||
volumes:
|
||||
- uploads_data:/data/uploads
|
||||
read_only: true
|
||||
cap_drop: [ALL]
|
||||
cap_add: [CHOWN, FOWNER, DAC_OVERRIDE]
|
||||
restart: "no"
|
||||
|
||||
model-gateway:
|
||||
build: ./backend
|
||||
command: ["uvicorn", "app.model_gateway:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
@@ -143,6 +162,8 @@ services:
|
||||
depends_on:
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
upload-init:
|
||||
condition: service_completed_successfully
|
||||
model-gateway:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
@@ -151,7 +172,7 @@ services:
|
||||
- postgres_app_password
|
||||
- model_gateway_api_token
|
||||
volumes:
|
||||
- uploads:/data/uploads
|
||||
- uploads_data:/data/uploads
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health/ready', timeout=2)"]
|
||||
interval: 10s
|
||||
@@ -170,22 +191,40 @@ services:
|
||||
networks: [ingress, data]
|
||||
restart: unless-stopped
|
||||
|
||||
worker:
|
||||
worker-local:
|
||||
build: ./backend
|
||||
command: ["python", "-m", "app.workers.main"]
|
||||
command: ["python", "-m", "app.worker"]
|
||||
depends_on:
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
upload-init:
|
||||
condition: service_completed_successfully
|
||||
environment:
|
||||
<<: *runtime-config
|
||||
WORKER_CAPABILITIES: document_parse
|
||||
secrets:
|
||||
- postgres_app_password
|
||||
volumes:
|
||||
- uploads_data:/data/uploads
|
||||
networks: [data]
|
||||
restart: unless-stopped
|
||||
|
||||
worker-model:
|
||||
build: ./backend
|
||||
command: ["python", "-m", "app.worker"]
|
||||
depends_on:
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
model-gateway:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
<<: [*runtime-config, *model-client-config]
|
||||
MODEL_GATEWAY_TOKEN_FILE: /run/secrets/model_gateway_worker_token
|
||||
MODEL_GATEWAY_CALLER: worker
|
||||
WORKER_CAPABILITIES: ${WORKER_CAPABILITIES:-document_parse,embedding,rerank,evaluation}
|
||||
WORKER_CAPABILITIES: embedding
|
||||
secrets:
|
||||
- postgres_app_password
|
||||
- model_gateway_worker_token
|
||||
volumes:
|
||||
- uploads:/data/uploads
|
||||
networks: [data, model]
|
||||
restart: unless-stopped
|
||||
|
||||
@@ -231,7 +270,7 @@ services:
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
uploads:
|
||||
uploads_data:
|
||||
|
||||
networks:
|
||||
edge:
|
||||
@@ -265,7 +304,17 @@ secrets:
|
||||
|
||||
实际实现固定数据库镜像 digest。`migrate` 只有一个实例执行;成功应用到 head 后退出码为 0,随后在 `docker compose ps -a` 显示 `Exited (0)` 是一次性任务的正常终态,不是服务暂停。API 和 Worker 不在启动时并发自动迁移。首次初始化脚本只在 `db` 容器内使用 bootstrap 凭据创建 `vector` 扩展、无超级用户权限的 migrator/app 登录角色和专属 schema;migrator 拥有 schema/DDL,app 仅获运行期所需的 DML/sequence 权限及默认权限,API/Worker 永远不挂载 bootstrap 或 migrator Secret。最后一个初始化脚本只有在全部 SQL 事务和授权成功后,才在 `PGDATA` 内用同文件系统 rename 原子写入 `.rag-bootstrap-complete`;healthcheck 同时检查 `pg_isready` 与该哨兵,防止临时初始化 server 提前放行迁移。Compose 的 `.env` 仅做变量插值,不会自动注入容器;后端从 `*_FILE` 读取 Secret,不把明文密码放进 `.env` 或 `DATABASE_URL`。
|
||||
|
||||
网络分为五层:`web` 位于普通 `edge` 和 internal `ingress`;入口 `gateway` 位于 `ingress + data`;API 位于 internal `data + model`;数据库/迁移位于 internal `data`;只有 `model-gateway` 位于 internal `model + egress`。`provider-smoke` 只持 API 内部 token,真实 `seed-demo` 只持数据库 Secret 和 Worker 内部 token;二者都不挂载百炼 Key、不加入 `egress`。未来 Worker 沿用相同边界。`model-gateway` 不连接数据库、不挂载上传卷、不发布端口。入口隔离见 [ADR-0004](adr/0004-secretless-web-ingress.md),模型出口隔离见 [ADR-0005](adr/0005-isolate-model-egress.md)。必须注意:普通 `edge` bridge 为 Web 提供宿主机端口发布时,也给 Web 留有技术上的默认公网出口;生产仍需主机防火墙或出口代理只允许 `model-gateway` 到百炼域名。
|
||||
网络分为五类:`web` 位于普通 `edge` 和 internal `ingress`;入口 `gateway` 位于
|
||||
`ingress + data`;API 位于 internal `data + model`;数据库、迁移和 `worker-local` 位于
|
||||
internal `data`;`worker-model` 位于 internal `data + model`;只有 `model-gateway` 位于
|
||||
internal `model + egress`。`worker-local` 挂载上传卷但没有模型 Token/网络,`worker-model` 持
|
||||
内部 Worker Token 但不挂载上传卷;两者的信任边界见
|
||||
[ADR-0007](adr/0007-split-local-and-model-workers.md)。`provider-smoke` 和真实 `seed-demo` 都不
|
||||
挂载百炼 Key、不加入 `egress`。`model-gateway` 不连接数据库、不挂载上传卷、不发布端口。
|
||||
入口隔离见 [ADR-0004](adr/0004-secretless-web-ingress.md),模型出口隔离见
|
||||
[ADR-0005](adr/0005-isolate-model-egress.md)。必须注意:普通 `edge` bridge 为 Web 提供宿主机
|
||||
端口发布时,也给 Web 留有技术上的默认公网出口;生产仍需主机防火墙或出口代理只允许
|
||||
`model-gateway` 到百炼域名。
|
||||
|
||||
### 2.3 后台任务为何不用 Redis
|
||||
|
||||
@@ -331,7 +380,11 @@ def read_secret(file_env: str, value_env: str) -> str:
|
||||
|
||||
生产只允许文件/Secret Manager;本地值环境变量仅作为临时兼容。`bailian_api_key` 只挂载到 `model-gateway`。API 与 Worker 分别挂载 `model_gateway_api_token`、`model_gateway_worker_token`;调用同时使用 Bearer token 和 `X-RAG-Caller`,服务端以常量时间比较并拒绝 token/身份不匹配。应用启动后不打印 Settings 的 Secret 字段,异常对象不得包含请求头。
|
||||
|
||||
Secret 或模型端点配置在运行中发生变化时,`model-gateway` 会原子清空旧 provider 与内部 token,并进入 `restart_required`;旧、新 token 都不能在旧进程继续调用。Docker 的 `restart: unless-stopped` 不会仅因 unhealthy 自动重启,因此轮换操作必须协调执行 `docker compose restart model-gateway api`(Worker 落地后同时重启 Worker),待 readiness 恢复后再运行 provider smoke。禁止只替换文件而让旧进程长期携带旧凭据。
|
||||
Secret 或模型端点配置在运行中发生变化时,`model-gateway` 会原子清空旧 provider 与内部
|
||||
token,并进入 `restart_required`;旧、新 token 都不能在旧进程继续调用。Docker 的
|
||||
`restart: unless-stopped` 不会仅因 unhealthy 自动重启,因此轮换操作必须协调执行
|
||||
`docker compose restart model-gateway api worker-model`,待 readiness 恢复后再运行 provider
|
||||
smoke。禁止只替换文件而让旧进程长期携带旧凭据。
|
||||
|
||||
### 3.3 Git 防泄漏
|
||||
|
||||
|
||||
Reference in New Issue
Block a user