58 lines
3.1 KiB
Markdown
58 lines
3.1 KiB
Markdown
# OpenSandbox VM runner
|
||
|
||
Gitea 的 `workflow_job` webhook 只负责发现带 `self-hosted,pod` 或
|
||
`self-hosted,vm` label 的 queued job。controller 不再把请求写入 NATS,而是携带由
|
||
OpenSandbox 只承载 `self-hosted,vm` workload。`self-hosted,pod` 由 homelab 原生
|
||
Kubernetes worker 创建,不经过 OpenSandbox。homelab ExternalSecret 挂载的 API key
|
||
供 VM consumer 调用 OpenSandbox Lifecycle API:
|
||
|
||
```text
|
||
http://10.60.0.13:8080/v1/sandboxes
|
||
```
|
||
|
||
请求通过 `extensions.poolRef` 选择 `ci-pod` 或 `ci-vm`。地址是 VyOS HAProxy 的
|
||
内网 TCP frontend,backend 为 sandbox 两个节点上的固定 NodePort;不通过公网或
|
||
Cloudflare Tunnel。OpenSandbox key 只从 OpenBao `kv/k8s/opensandbox-api.api_key`
|
||
进入 homelab Secret,进程通过 `OPENSANDBOX_API_KEY_FILE` 读取。
|
||
|
||
## 身份顺序
|
||
|
||
Lifecycle 请求把稳定的 repository/task SPIFFE ID 放入 task environment。sandbox
|
||
集群内的 `opensandbox-identity` controller 读取 BatchSandbox allocation 得到实际
|
||
Pod UID,然后创建:
|
||
|
||
- parent:`spiffe://ddupan.top/spire/agent/k8s_psat/sandbox-kata/pod/<pod-uid>`;
|
||
- workload:`spiffe://ddupan.top/ci/<owner>/<repository>/<task>`;
|
||
- selector:`unix:uid:2000`。
|
||
|
||
job ID 只进入诊断 label,不进入业务身份。Pool 内 runner 进程固定使用 UID 2000,
|
||
Pod 设置 `shareProcessNamespace: true`;guest-local SPIRE Agent 使用 Pod-bound PSAT,
|
||
通过内存 emptyDir 暴露 Workload API。`gitea-opensandbox-runner` 等待精确 SVID,随后
|
||
通过一次性 nonce URL 领取 Gitea registration token。token 不进入 Lifecycle 请求、
|
||
BatchSandbox、镜像或 sandbox Secret。
|
||
|
||
identity controller 只能读取 opensandbox namespace 的 BatchSandbox/Pod,并维护带
|
||
自身 label 的 ClusterStaticEntry。它不持有 OpenSandbox API key、Gitea token 或 Bao
|
||
凭据。BatchSandbox 消失后,对应 entry 在下一次 reconcile 删除;Pod 删除后,按 Pod
|
||
UID attestation 的临时 Agent 失去父级。
|
||
|
||
## Pool 契约
|
||
|
||
`ci-vm` 使用 `kata-clh-runtime-rs`;`ci-pod` 使用默认 runc。两者都要求:
|
||
|
||
- runner 镜像包含 Gitea Runner、Node.js action userspace、SPIRE CLI、Docker 工具和
|
||
identity gate;Pod 与 VM backend 使用同一个镜像;
|
||
- runner UID 2000;SPIRE Agent 独立运行;job-started hook 在第一步 workflow 之前
|
||
启动 job-local Docker daemon,业务 workflow 不负责 runner 基础设施初始化;
|
||
- Kata VM 中 Docker 数据使用 guest 内的 loop-backed ext4,并随 sandbox 一起删除;
|
||
- `self-hosted` 必须是所有 runner labels 的前缀;
|
||
- ephemeral/once runner 完成一项任务后退出。
|
||
|
||
## 清理与恢复
|
||
|
||
Gitea 接受 runner 终态后,facade 先通过 Lifecycle API 将
|
||
`ci.ddupan.top/terminal=true` 持久化到 sandbox metadata,再向 runner 返回成功。VM
|
||
lifecycle reconciler 按该 metadata 查询并调用 DELETE;controller 在标记与删除之间重启
|
||
也能恢复清理。API delete、identity entry delete 均接受对象已不存在,OpenSandbox
|
||
timeout 仍是最终兜底回收边界;生命周期状态不写入消息队列或新的数据库。
|