| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 |
Runtime Capabilities
runtime_capabilities 是基于 openjiuwen_runtime.service 构建的可部署应用,用于通过一组明确的
REST API 验证运行时框架的数据库、Redis、Envelope 解析和 Kubernetes Pod 管理能力。
它位于 applications/,属于可独立安装、启动和部署的应用;service/examples/ 中的框架示例仍然
保持原样。应用复用 service 提供的 App、SystemContext、请求上下文、数据库抽象、Redis
原语和 Kubernetes 抽象,不在应用目录中重复实现这些通用能力。
1. 功能范围
应用启动后提供 /docs、/openapi.json、/health,以及以下 8 个业务接口:
| 分组 | 方法与路径 | 作用 |
|---|---|---|
| Database | POST /api/db/write |
创建或更新一条记录 |
| Database | POST /api/db/read |
按 ID 查询记录 |
| Redis | POST /api/redis/write |
写入带 TTL 的字符串值 |
| Redis | POST /api/redis/read |
查询字符串值 |
| Envelope | POST /api/envelope/inspect |
解析并返回 Envelope、Metadata 和请求上下文 |
| Kubernetes | POST /api/k8s/pod/create |
按受限模板创建一个 Pod |
| Kubernetes | POST /api/k8s/pod/read |
查询应用管理的 Pod |
| Kubernetes | POST /api/k8s/pod/delete |
删除应用管理的 Pod |
所有业务接口都接收完整的 OpenJiuwen Envelope。REST 路径和请求体中的 type 是同一个处理器
标识的两种表达:例如 /api/db/write 只接受 type: "db/write"。路径与 type 不一致时会被
FastAPI/OpenAPI 请求模型拒绝,未知路径返回 HTTP 404。
2. 运行模式
启动时必须显式指定一个模式:
| 模式 | 数据库 | Redis | Kubernetes | 适用场景 |
|---|---|---|---|---|
local |
SQLite 文件 | FakeRedis | 内存中的 Fake Kubernetes | 本地开发、接口联调、自动化测试 |
server |
真实 MySQL | 真实 Redis | 真实 Kubernetes API | 服务器和集群能力验证 |
模式由命令行 --mode 或部署脚本的第一个参数选择。应用会把它同步到
RUNTIME_CAPABILITIES_MODE。一个进程内不会混用真假资源:local 始终使用全部本地资源,
server 始终要求真实 MySQL、Redis 和 Kubernetes。
local 模式中的 FakeRedis 和 Fake Kubernetes 数据仅在当前进程生命周期内存在;SQLite 数据
保存在 RUNTIME_CAPABILITIES_SQLITE_PATH 指向的文件中。server 模式启动时会校验数据库类型
必须为 mysql,并校验 Redis URL 已配置且合法,防止误以为正在验证真实资源而实际落到本地
替代实现。
3. 目录结构
applications/runtime_capabilities/
├── README.md
├── pyproject.toml
├── runtime_capabilities.local.env.example
├── runtime_capabilities.server.env.example
├── scripts/
│ └── deploy.sh
├── src/runtime_capabilities/
│ ├── __init__.py
│ ├── __main__.py
│ ├── application.py
│ └── cli.py
└── tests/
└── test_application.py
application.py:配置策略、请求/响应模型、8 个 Handler 和应用工厂。cli.py:统一命令行入口,负责加载 dotenv、选择模式并启动 Uvicorn。scripts/deploy.sh:面向开发者的安装与启动辅助脚本。- 两个
*.env.example:可提交的配置模板;实际.env.*.local文件不会进入 Git。 tests/:配置单元测试和经 ASGI 发起真实 HTTP 请求的系统测试。
4. 本地启动
要求 Python >=3.11.4,并已安装 uv。在仓库根目录执行:
cp applications/runtime_capabilities/runtime_capabilities.local.env.example \
applications/runtime_capabilities/.env.development.local
./applications/runtime_capabilities/scripts/deploy.sh local
首次执行时,即使不手动复制模板,脚本也会创建默认的
applications/runtime_capabilities/.env.development.local。随后脚本会:
- 通过
uv sync --extra local同步应用及本仓foundation、service依赖; - 加载本地配置文件;
- 以单 worker 启动应用。
默认访问地址:
- Swagger UI:
http://127.0.0.1:8090/docs - OpenAPI:
http://127.0.0.1:8090/openapi.json - 健康检查:
http://127.0.0.1:8090/health
也可以绕过脚本直接启动:
cd applications/runtime_capabilities
uv sync --extra local
uv run runtime-capabilities \
--mode local \
--env-file .env.development.local
5. 服务器模式
先复制服务器模板,并按目标环境填写真实资源:
cp applications/runtime_capabilities/runtime_capabilities.server.env.example \
applications/runtime_capabilities/.env.production.local
至少需要确认以下配置:
RUNTIME_CAPABILITIES_MODE=server
RUNTIME_CAPABILITIES_KUBERNETES_NAMESPACE=runtime-capabilities
RUNTIME_CAPABILITIES_KUBERNETES_POD_IMAGE=redis:7-alpine
RUNTIME_CAPABILITIES_KUBERNETES_POD_RUN_AS_USER=999
RUNTIME_CAPABILITIES_KUBERNETES_POD_RUN_AS_GROUP=1000
OPENJIUWEN_SERVICE_DB_TYPE=mysql
OPENJIUWEN_SERVICE_DB_HOST=mysql.example.internal
OPENJIUWEN_SERVICE_DB_PORT=3306
OPENJIUWEN_SERVICE_DB_NAME=runtime_capabilities
OPENJIUWEN_SERVICE_DB_USER=runtime_capabilities
OPENJIUWEN_SERVICE_DB_PASSWORD=change-me
OPENJIUWEN_SERVICE_REDIS_URL=redis://redis.example.internal:6379/0
OPENJIUWEN_SERVICE_REDIS_KEY_PREFIX=runtime-capabilities
然后在仓库根目录执行:
./applications/runtime_capabilities/scripts/deploy.sh server
辅助脚本只同步依赖、加载配置并启动应用,不会创建 MySQL、Redis、Kubernetes namespace、 ServiceAccount 或 RBAC。外部基础设施应由环境管理员预先准备。
5.1 MySQL 要求
配置的 MySQL 账户需要具备目标数据库的连接权限,以及应用表的建表和 CRUD 权限。框架启动时会
确保数据库及 runtime_capability_records 表存在;若目标环境禁止应用创建数据库,应由管理员
预先创建 OPENJIUWEN_SERVICE_DB_NAME 指定的数据库,并授予必要的表级权限。
5.2 Kubernetes 连接与权限
应用只操作 RUNTIME_CAPABILITIES_KUBERNETES_NAMESPACE 指定 namespace 中、带有本应用管理标签
的 Pod。
- 应用运行在 Kubernetes 集群内时,客户端优先使用 Pod 的 ServiceAccount。
- 应用作为服务器本地进程运行时,通过
KUBECONFIG指向可访问目标集群的 kubeconfig;未显式 设置时,Kubernetes 客户端使用默认 kubeconfig 查找规则。 - 身份至少需要目标 namespace 中 Pod 的
get、list、create、delete权限。
生产或共享测试环境中应按 namespace 最小授权,不要授予集群管理员权限。一个最小 Role 的规则 部分如下,具体 ServiceAccount 和 RoleBinding 名称由部署环境决定:
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "create", "delete"]
Pod 模板固定启用 runAsNonRoot、禁止提权并丢弃 Linux capabilities。如果所选镜像的镜像元数据
没有声明非 root 用户,可以同时配置:
RUNTIME_CAPABILITIES_KUBERNETES_POD_RUN_AS_USER=<镜像内有效的非 root UID>
RUNTIME_CAPABILITIES_KUBERNETES_POD_RUN_AS_GROUP=<镜像内有效的非 root GID>
UID 和 GID 必须成对配置,且应从所选镜像本身确认,不能把一个镜像的数值直接套用到另一个镜像。
5.3 对外访问
服务器模板默认监听 0.0.0.0:8090,方便通过受控网络、反向代理或端口转发访问。当前应用用于
能力验证,没有内置业务身份认证;共享环境应通过防火墙、内网策略、反向代理认证等方式限制
访问,尤其是 Kubernetes 写接口。
6. 在 Swagger UI 中验证接口
打开 /docs,展开接口,点击 Try it out,粘贴对应请求体并点击 Execute。以下请求均为
完整、可直接执行的 Envelope 示例。
6.1 写数据库:POST /api/db/write
{
"type": "db/write",
"metadata": {
"request_id": "db-write-1"
},
"rawdata": {
"id": "record-1",
"value": "hello database"
},
"version": "1"
}
首次写入返回 operation: "created";用相同 id 再次写入会更新记录并返回
operation: "updated"。
6.2 读数据库:POST /api/db/read
{
"type": "db/read",
"metadata": {
"request_id": "db-read-1"
},
"rawdata": {
"id": "record-1"
},
"version": "1"
}
存在时返回 id、value、updated_at;记录不存在时返回 HTTP 404 和统一错误信封。
6.3 写 Redis:POST /api/redis/write
{
"type": "redis/write",
"metadata": {
"request_id": "redis-write-1"
},
"rawdata": {
"key": "message-1",
"value": "hello redis",
"ttl_seconds": 300
},
"version": "1"
}
ttl_seconds 可省略;省略时使用
RUNTIME_CAPABILITIES_REDIS_DEFAULT_TTL_SECONDS。返回中的 backend_mode 可用于确认当前访问的
是 fake 还是真实 real 后端。
6.4 读 Redis:POST /api/redis/read
{
"type": "redis/read",
"metadata": {
"request_id": "redis-read-1"
},
"rawdata": {
"key": "message-1"
},
"version": "1"
}
存在时返回 found: true 和 value;不存在时仍返回 HTTP 200,但 found 为 false、value
为 null。
6.5 解析 Envelope:POST /api/envelope/inspect
{
"type": "envelope/inspect",
"metadata": {
"request_id": "inspect-1",
"user_id": "user-001",
"chat_id": "chat-001",
"session_id": "session-001",
"bot_id": "bot-001",
"channel": "swagger",
"trace_id": "trace-001",
"instance_id": "instance-001",
"extra": {
"tenant": "example-tenant",
"source": "manual-test"
}
},
"rawdata": {
"message": "inspect this envelope",
"attributes": {
"environment": "server"
}
},
"version": "1"
}
响应分为三部分:
envelope:框架解析后的完整 Envelope;context:框架从 Metadata 建立的请求上下文字段,以及当前副本replica_id;service:应用模式和 Redis/Kubernetes 后端模式。
6.6 创建 Pod:POST /api/k8s/pod/create
{
"type": "k8s/pod/create",
"metadata": {
"request_id": "pod-create-1"
},
"rawdata": {
"name": "capability-pod-1"
},
"version": "1"
}
镜像、namespace 和安全上下文由服务端配置决定,调用方只能指定符合 DNS-1123 的 Pod 名称。 同名且由本应用管理的 Pod 已存在时返回 HTTP 409。
6.7 查询 Pod:POST /api/k8s/pod/read
{
"type": "k8s/pod/read",
"metadata": {
"request_id": "pod-read-1"
},
"rawdata": {
"name": "capability-pod-1"
},
"version": "1"
}
返回 name、namespace、phase、ready 和 image。真实集群中,创建接口刚返回时 Pod
可能处于 Pending,镜像拉取并通过就绪检查后再查询会看到 Running 和 ready: true。
6.8 删除 Pod:POST /api/k8s/pod/delete
{
"type": "k8s/pod/delete",
"metadata": {
"request_id": "pod-delete-1"
},
"rawdata": {
"name": "capability-pod-1"
},
"version": "1"
}
state 可能为:
delete_requested:已向 Kubernetes 提交删除;deletion_in_progress:Pod 已处于终止过程;already_absent:Pod 已不存在。
7. 自动化测试
在仓库根目录执行:
uv sync --project applications/runtime_capabilities --all-extras
uv run --project applications/runtime_capabilities pytest -q \
applications/runtime_capabilities/tests
只运行配置等单元测试:
uv run --project applications/runtime_capabilities pytest -q -m unit \
applications/runtime_capabilities/tests
只运行通过 ASGI/HTTP 验证全部接口、错误码和 OpenAPI 的系统测试:
uv run --project applications/runtime_capabilities pytest -q -m system \
applications/runtime_capabilities/tests
自动化测试不会连接真实 MySQL、Redis 或 Kubernetes。真实资源验证应使用 server 模式,并在
受控 namespace 和专用测试数据范围内按第 6 节顺序执行。
8. 配置参考
应用配置
| 变量 | 默认值 | 说明 |
|---|---|---|
RUNTIME_CAPABILITIES_MODE |
local |
local 或 server;脚本会按启动参数设置 |
RUNTIME_CAPABILITIES_SERVICE_LABEL |
runtime-capabilities |
Envelope 检查响应中的服务标识 |
RUNTIME_CAPABILITIES_REDIS_DEFAULT_TTL_SECONDS |
300 |
Redis 写接口的默认 TTL,必须为正整数 |
RUNTIME_CAPABILITIES_KUBERNETES_NAMESPACE |
runtime-capabilities |
允许管理 Pod 的 namespace |
RUNTIME_CAPABILITIES_KUBERNETES_POD_IMAGE |
见模板 | 创建 Pod 使用的固定镜像 |
RUNTIME_CAPABILITIES_KUBERNETES_POD_RUN_AS_USER |
未设置 | 可选非 root UID,必须与 GID 成对配置 |
RUNTIME_CAPABILITIES_KUBERNETES_POD_RUN_AS_GROUP |
未设置 | 可选非 root GID,必须与 UID 成对配置 |
RUNTIME_CAPABILITIES_SQLITE_PATH |
./runtime_capabilities.db |
仅本地模式使用的 SQLite 文件 |
框架配置
网络、数据库、Redis、锁和缓存使用 OPENJIUWEN_SERVICE_* 配置。完整定义以
service/openjiuwen_runtime/service/config.py 为准;本应用最常用的配置已列在两个环境模板中。
实际密码、token、证书和 kubeconfig 不应写入 README、模板或 Git,应只保存在受控的本地环境 文件或部署平台 Secret 中。