独立控制面运行时
代码仓库包含独立的 cheesewaf-control 控制面进程。它会打开控制面 PostgreSQL 适配器和 native-raft 运行时,再提供本地状态服务。它不处理 WAF 请求,不托管 Web 控制台,也不替代主 cheesewaf serve 进程。
本文说明当前源码和运行时契约,不是高可用部署手册。主 cheesewaf serve 路径仍使用 storage.profile: temporary 和内置 SQLite;生产管理存储仍会以 ErrProductionStorageUnavailable 拒绝启动。独立进程不提供空集群初始化、远程 join 流程、插件安装、OTA 或 CWEDP 执行。
命令边界
进程只接受命令行参数,不接受位置参数。
| 参数 | 默认值 | 规则 |
|---|---|---|
--profile | production | 只接受 production 配置。 |
--cluster-id | 空 | 必填。不能包含空白、控制字符或不可见格式字符。 |
--node-id | 自动生成 | 可选。不填写时,native-raft 会在 --data-dir 下生成并保存节点身份。 |
--data-dir | 空 | 必填。请使用持久且权限受限的目录保存 native-raft 状态和快照。 |
--listen | 127.0.0.1:9450 | 本地管理 HTTP 地址,必须是回环 host:port。 |
--raft-listen | 127.0.0.1:9451 | native-raft 地址,必须是不同的回环 host:port。 |
--mode | join | 只能是 bootstrap 或 join;默认值不会初始化集群。 |
--ca-file | 空 | 必填的控制面和 native-raft TLS 信任 CA PEM 文件,必须是权限受限的普通文件。 |
--cert-file | 空 | 必填的节点证书 PEM;设置 --node-id 时,证书身份必须匹配。 |
--key-file | 空 | 必填的节点私钥 PEM,建议权限为 0600,不得写入日志或源码仓库。 |
--postgres-dsn | 空 | 必填的管理 PostgreSQL DSN,不会写入状态 JSON。 |
--timeout | 15s | 必须为正数。超时会停止启动。 |
两个监听地址都会校验为回环地址。当前命令不提供远程管理监听。若要远程部署,需要单独设计 TLS、mTLS、ACL、审计和回滚控制。
--postgres-dsn 是独立的管理状态连接,不能与 storage.postgresql.dsn 混淆。后者仍是 cheesewaf 使用的可选异步访问日志 Sink。回环地址和 Unix Socket 的 PostgreSQL 连接可以使用;远程 PostgreSQL 主机必须启用并校验证书的 TLS。这个进程不会打开 Redis 连接。
CA、节点证书和私钥必须由受保护的配置流程提前生成并放置。没有真实 PostgreSQL、Raft TLS 和一致快照时,这个示例仍会 fail-closed;它不是可以直接成功创建 HA 集群的安装步骤。
启动顺序与 fail-closed 行为
只有完整的生产启动流程成功后,cheesewaf-control 才会绑定 HTTP 监听器:
- 打开管理 PostgreSQL 适配器。
- 执行 PostgreSQL 控制面表迁移并检查健康状态。
- 读取 PostgreSQL 控制状态快照。
- 打开、准备并检查 native-raft。
- 读取 native-raft 快照。
- 比较两份快照,包括 cluster、leader、term、epoch、revision、期望版本、摘要、载荷、冻结状态和 nonce ledger。
- 校验快照,确认它没有覆盖本机已经保存的 last-known-good 状态。
- 建立 fencing token,并确认它绑定同一个 cluster、leader、epoch、revision、摘要和 nonce。
- 再次读取 native-raft。fencing 后如果 leader、term、epoch、revision 或摘要发生变化,启动失败。
- 安装一致的快照,恢复控制面写入,并报告
ready。
迁移、健康检查、快照比较、校验或 fencing 任一步失败,命令都会返回错误。命令输出 control-plane startup failed closed,并在启动状态服务前退出。未验证的快照不会进入 ready 状态,系统也不会接受 proposal。若上层 supervisor 特意使用运行时提供的冻结诊断模式,可以暴露存活状态和冻结原因;这种模式不会报告 ready,也不会恢复写入。
当 PostgreSQL 没有状态行、native-raft 也没有状态时,两边都会得到空的冻结状态。要进入 ready,仍必须有已提交的 desired state revision、非零 term 和 epoch、已建立的 leader,以及匹配的 fencing nonce。因此,仅设置 --mode bootstrap 不能初始化空的生产集群,也不能凭空生成第一份期望状态。
本地状态接口
状态服务供本机 supervisor 和探针使用。它监听 --listen,该地址会被校验为仅限回环。
| 方法 | 路径 | 响应 |
|---|---|---|
GET | /healthz | 始终返回 200 和当前状态文档。若 supervisor 特意暴露冻结诊断,冻结状态也可以报告存活。 |
GET | /readyz | 只有 ready 和 write_ready 都为 true 时返回 200,否则返回 503。 |
GET | /status | 返回 200,内容包括阶段、ready 状态、集群/节点身份、leader、term、epoch、revision、更新时间和有长度限制的冻结原因。 |
POST | /proposals | 未进入写入 ready 前返回 503;进入写入 ready 后,当前二进制因 proposal transport 尚未挂载而返回 501。其他方法返回 405。 |
状态响应不会包含凭据、PostgreSQL DSN、文件路径或后端原始错误。这个接口只用于本地诊断,不是集群 API。
Bootstrap 与 join 模式
bootstrap 和 join 是 native-raft 的启动模式,不是完整的集群管理流程。
bootstrap只有在数据目录没有既有 Raft 状态时,才会调用 native-raft 的一次性BootstrapCluster。进程仍然需要一致的 PostgreSQL 与 native-raft 快照,以及有效的已提交 fencing,才能进入 ready。join不会调用BootstrapCluster。全新的 join 节点不会自行成为 leader,也不能把空状态变成集群。当前 CLI 没有 controller 地址、join token 或远程注册参数。- native-raft 包提供 leader 侧的
Join操作,用于添加 voter。这个操作是内部运行时 API,不是 HTTP 接口,也不是cheesewaf-control子命令。在完整、经过测试的 follower 注册流程发布前,应把join视为只读注册模式。
因此,当前独立命令不能创建空集群、自动加入对等节点,也不能宣称已经提供生产级多节点 HA。仓库中的 native-raft 和 PostgreSQL 代码定义了一致性边界,但不会让现有 cheesewaf serve 自动切换到 PostgreSQL 或 native-raft 存储路径。
与主服务的关系
cheesewaf serve 仍是主 WAF 入口。它负责数据平面监听和现有管理平面;当前可运行的管理存储配置仍是 storage.profile: temporary。在主服务中添加管理 PostgreSQL DSN,或设置 storage.profile: production,都不会把它迁移到这个独立进程。主服务仍会等待完整的 PostgreSQL、Coordinator、native-raft、审批、审计和数据面接线完成后,才可能解除 fail-closed。
更大的目标架构见商业化平台架构。本文说明独立命令的可执行边界,应与仓库中的控制面启动契约一起阅读。