mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
163 lines
8.6 KiB
Markdown
163 lines
8.6 KiB
Markdown
# QingLong 3.0 Cluster Automation Management
|
||
|
||
该 operation 是 Cluster Task/Trigger 的人类管理入口,不适用于 Edge/Standalone。路由器继续使用
|
||
短生命周期 `ql3-task` 与 `ql3-trigger`,不会因此增加 HTTPS listener、证书或 PostgreSQL Pool。
|
||
|
||
## 部署前置
|
||
|
||
1. 完成 PostgreSQL capability v53、54 条 control-core migration 与 readiness;
|
||
2. 从 `deploy/kubernetes/ql3-cluster/operations/automation-management/config.example.yaml`
|
||
创建私有 TLS、客户端 CA/CRL 与 public identity keyset Secret;
|
||
3. 把 Pod template 的 CA/CRL digest sentinel 换成精确 bundle SHA-256;
|
||
4. 在私有 overlay 中把 Admin image 的全零 digest 换成已验证 release digest;
|
||
5. CloudNativePG 已创建 `ql3-postgres-automation-manager-auth` 与 `ql3-postgres-ca`。
|
||
|
||
```bash
|
||
kubectl kustomize \
|
||
deploy/kubernetes/ql3-cluster/operations/automation-management/cloudnative-pg \
|
||
>/dev/null
|
||
kubectl apply -k \
|
||
deploy/kubernetes/ql3-cluster/operations/automation-management/cloudnative-pg
|
||
kubectl -n qinglong3-system rollout status \
|
||
deployment/ql3-automation-management
|
||
```
|
||
|
||
基础清单不会被 `operations/kustomization.yaml` 自动引用。服务仅在 ClusterIP 8445 提供
|
||
`POST /api/v3/automations/management`,只接受同 namespace 且带
|
||
`qinglong.io/automation-management-client=true` label 的客户端 Pod。base 只有 DNS egress,
|
||
CloudNativePG overlay 只增加 PostgreSQL 5432。
|
||
|
||
## 身份与请求
|
||
|
||
客户端必须同时提供受信 mTLS 证书与短期 OIDC 断言。断言固定:
|
||
|
||
- audience:`qinglong3-automation-management`
|
||
- JWT type:`ql3-automation-management+jwt`
|
||
- purpose claim:`automation-management`
|
||
- subject:User
|
||
- assurance:`multi_factor` 或 `hardware`
|
||
|
||
业务 body 只接受 schema v1 的六个操作:
|
||
|
||
- mutation:`task.publish`、`trigger.publish`;
|
||
- inspection:`task.inspect`、`trigger.inspect`;
|
||
- bounded list:`task.list`、`trigger.list`。
|
||
|
||
mutation 调用方必须复用同一 `requestId`、`mutationId` 和 command 重试无响应请求;收到明确 HTTP/业务
|
||
拒绝后不得自动换 ID 重试。inspect/list 每次请求必须提供新的 UUID v4 `auditEventId`,分别要求
|
||
`task.read` 或 `trigger.read`。读取已经产生 append-only allowed audit,因此响应丢失后应使用新的
|
||
`requestId`/`auditEventId` 重新读取,不能把重复 audit identity 当作幂等读取。
|
||
|
||
inspect/list 与 mutation 使用相同的审计耐久性约束。HA 以 `synchronous_commit=remote_apply` 运行时,
|
||
主库提升后若同步备库尚未恢复,读取会因 allowed audit 无法获得同步确认而超时并失败关闭。这不是只读
|
||
服务故障,也不能临时降低 `synchronous_commit`;等待旧主 `pg_rewind` 并以同步只读备库重入后,再用
|
||
新的 request/audit identity 重试。已经返回成功的读取,其 audit 已同步应用到备库。
|
||
|
||
```json
|
||
{
|
||
"schemaVersion": 1,
|
||
"operation": "task.inspect",
|
||
"request": {
|
||
"requestId": "operator-request-20260804-1",
|
||
"auditEventId": "123e4567-e89b-42d3-a456-426614174010",
|
||
"projectId": "default",
|
||
"taskId": "daily-backup"
|
||
}
|
||
}
|
||
```
|
||
|
||
```json
|
||
{
|
||
"schemaVersion": 1,
|
||
"operation": "trigger.list",
|
||
"request": {
|
||
"requestId": "operator-request-20260804-2",
|
||
"auditEventId": "123e4567-e89b-42d3-a456-426614174011",
|
||
"projectId": "default",
|
||
"limit": 64,
|
||
"after": { "triggerId": "hourly-cleanup" }
|
||
}
|
||
}
|
||
```
|
||
|
||
list 只接受 1–256 的 limit 与稳定 keyset cursor,不支持 offset。inspect 不存在时返回 `absent`;响应只
|
||
返回 Task/Trigger current-head 低敏摘要和分页状态,不回显 name、description、labels、spec、command、
|
||
cron expression、mutation、Principal、credential、assertion 或 audit identity。
|
||
|
||
仓库提供两个产品调用面:
|
||
|
||
- `ql3-automation-client`:从三个 owner-private `0600` 绝对路径读取 client config、command 和
|
||
assertion,执行一次 TLS 1.3+mTLS 请求;
|
||
- `operations/automation-management-client`:caller 创建的一次性 Kubernetes Job,不含 RBAC 或
|
||
ServiceAccount token,`backoffLimit=0`,只访问 DNS 和 exact manager Pod 的 8445 端口。
|
||
|
||
本地/CI 的真实 PostgreSQL + HTTPS 产品门可通过以下标准入口运行;未同时提供两个 URL 时测试只做
|
||
条件 skip,不会尝试隐式启动数据库:
|
||
|
||
```bash
|
||
QL3_TEST_POSTGRES_URL='postgresql://ql3_migration:...@127.0.0.1:5432/ql3_contract' \
|
||
QL3_TEST_POSTGRES_AUTOMATION_MANAGER_URL='postgresql://ql3_automation_manager:...@127.0.0.1:5432/ql3_contract' \
|
||
pnpm test:automation-postgres-integration:ql3
|
||
```
|
||
|
||
该门会启动两个独立 manager 验证同请求并发,再模拟第三实例已 COMMIT 但响应丢失并从另一实例精确
|
||
重放;测试 identity adapter 只用于隔离验证 transport/repository,不构成生产 OIDC ceremony 证据。
|
||
|
||
### 三节点 Kubernetes + PostgreSQL HA live gate
|
||
|
||
完整 Cluster 纵切面是显式 opt-in,必须提供已下载并审查、且与 operator lock 一致的 CloudNativePG
|
||
1.30.0 release manifest。它会创建随机命名的一个 K3s server、两个 agent 和独立 Docker network,
|
||
拒绝复用同名资源,并在 `finally` 中只清理由本次 fixture 记录的容器、网络、临时目录与两张测试镜像:
|
||
|
||
```bash
|
||
QL3_AUTOMATION_MANAGEMENT_KUBERNETES_LIVE=1 \
|
||
QL3_CNPG_OPERATOR_MANIFEST_FILE=/owner-private/cloudnative-pg-1.30.0.yaml \
|
||
pnpm test:automation-management-kubernetes-live:ql3
|
||
```
|
||
|
||
该门使用锁定的 `rancher/k3s:v1.34.3-k3s1`、CloudNativePG 1.30.0 与 PostgreSQL 18.4,真实执行
|
||
三实例引导、54 条 migration/capability v53、十三角色、双 manager、TLS 1.3/mTLS、identity/CRL
|
||
轮换、primary deletion/promotion、数据库失联与 fresh-Pod 恢复、CNI ingress/egress 和 RBAC 拒绝。
|
||
K3s 默认 Flannel 是分发内嵌组件,不存在可假定的三副本 `kube-flannel` DaemonSet;证据由锁定的 K3s
|
||
分发、三个现场 Ready+唯一 PodCIDR 节点、server 的 Flannel VXLAN/subnet-manager annotation,以及
|
||
真实跨节点正负网络探针共同构成。最终 stdout 只输出 exact-schema 低敏报告,任何 assertion、证书、
|
||
私钥、DSN、kubeconfig 或 Secret 都会被审计器拒绝。
|
||
|
||
这是单 Docker host 上的应用/数据库故障门,不是生产基础设施 STONITH、Kubernetes control-plane HA、
|
||
CSI/节点断电或真实外部 IdP 证据。路由器/低配设备不运行此门,也不因此新增常驻进程、workspace package
|
||
或依赖闭包;夹具与 PKI helper 留在 `scripts/lib`,只在维护工作站或 CI 的 opt-in lifecycle 中加载。
|
||
|
||
Task source、command、environment recipe 等可能含敏感信息,因此 Kubernetes operation 的
|
||
`ql3-automation-management-request` 必须是 immutable Secret,不能照搬 Worker client 使用 ConfigMap。
|
||
从 `deploy/kubernetes/ql3-cluster/operations/automation-management-client/config.example.yaml`
|
||
复制四个输入对象到私有 per-command overlay,替换 assertion、客户端证书、CA、Task/Trigger command
|
||
以及全零 Admin image digest,然后执行:
|
||
|
||
```bash
|
||
kubectl create -k \
|
||
deploy/kubernetes/ql3-cluster/operations/automation-management-client
|
||
kubectl -n qinglong3-system wait \
|
||
--for=condition=Complete job/ql3-automation-management-client \
|
||
--timeout=2m
|
||
kubectl -n qinglong3-system logs job/ql3-automation-management-client
|
||
```
|
||
|
||
Job 名称固定;再次执行前等待 TTL 清理或只删除该精确 Job 和对应 per-command immutable inputs。
|
||
init container 只重试 `/readyz`,不会发送业务命令;main container 只执行一次。若客户端在收到响应前
|
||
断线,mutation operator 必须先以完全相同的 `requestId`、`mutationId` 和 command 查询/重放,不得生成
|
||
新 mutation 身份;inspect/list 则使用新的 request/audit identity 再执行一次有审计读取。
|
||
|
||
## 资源档位
|
||
|
||
生产 HA base 是 2 Pod,每 Pod PostgreSQL Pool 2、最多 32 个 TLS connection 与 16 个并发请求,
|
||
Pod requests 为 100m CPU/128Mi。单节点开发 overlay 可以显式降为 1 Pod、Pool 1 并移除 PDB/required
|
||
anti-affinity,但不属于生产支持矩阵。更大集群扩容前必须同时评审数据库角色 `connectionLimit`、全局
|
||
限流、故障域和身份 ledger 竞争;禁止只增加 replica。
|
||
|
||
## 轮换与恢复
|
||
|
||
public keyset generation 只能递增。新旧 key 先 overlap,再把旧 `kid` 追加到 `revokedKids`;不能删除
|
||
或复用已吊销 ID。CA/CRL 改动必须更新 Pod annotation 并完成零不可用 rollout。服务端 TLS 材料只在
|
||
进程启动时加载,因此证书替换也需要滚动 Pod。任何数据库错误会撤销 readiness;恢复应由新 Pod
|
||
重新完成 schema、identity ledger 和 TLS 校验,不能通过跳过 readiness 强行开放业务路由。
|