existing k3s control plane
├─ ci-controller
├─ OpenSandbox BatchSandbox operator(单套)
├─ OpenSandbox API: pod profile ─► runc RuntimeClass ─► 普通 worker
└─ OpenSandbox API: vm profile ─► Kata RuntimeClass ─► sandbox-pve1 / sandbox-pve2
pve1/sandbox-node-1 LXC: k3s agent + containerd + Kata + /dev/kvm
pve2/sandbox-node-2 LXC: k3s agent + containerd + Kata + /dev/kvm
为什么需要两个 API profile
OpenSandbox 当前 [secure_runtime] 是 server 实例级配置,官方文档明确说明启用后该 server 创建的 ALL sandboxes 都使用指定 runtime;batchsandbox_template_file 也是单个 server 的全局模板。因此同一 API 实例目前不能按每次请求在 runc 与 Kata 间切换。
首期部署两个无状态 OpenSandbox server Deployment,指向同一 Kubernetes backend/operator:
opensandbox-pod:不配置 secure runtime,模板用 node affinity/资源策略调度普通 Pod
opensandbox-vm:配置 secure_runtime.type = kata 与 k8s_runtime_class = kata-*,模板带 Kata worker selector/toleration
CI controller 根据 runs-on: [self-hosted, pod|vm] 选择对应 API service。两者仍属于同一 OpenSandbox/Kubernetes 集群控制面,不是每节点部署一套 provider。
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
背景
当前 PoC 已验证 webhook → NATS → Pod/microVM 的完整生命周期,但实现仍带有明显的纵向耦合:
controller.py同时负责 Gitea webhook 协议、任务筛选和内部消息发布NATS 已经提供了正确的解耦边界。项目应重构为可独立演进的 source adapter、scheduler 和 executor 微服务,让 Gitea 与 GitHub 控制协议共享执行后端。
关联:
目标架构
source adapter
scheduler
executor
内部协议
至少定义并版本化:
JobIntent:source、外部任务引用、repository、job name、labels、约束ExecutionAssignment:内部 execution ID、provider、资源规格、短期 capability referenceLifecycleEvent:accepted、provisioning、ready、running、completed、failed、cancelled、timed_out外部系统的 registration token、JIT config、task lease 或长期 credential 不直接放入 JetStream payload。
JetStream 边界
ack_wait、max_deliver、DLQ/advisory 与过期清理策略增量迁移顺序
gitea-webhook-adapter,保持线上行为不变验收标准
非目标
技术栈决策:移除 shell 编排层
microVM 路径不应长期保留 Python 调用多段 shell 的结构。当前脚本已经承担磁盘生命周期、cloud-init、TAP/MAC、bridge/NAT/DHCP、进程监督、超时、日志归档和清理,实际上是一个缺少类型与测试边界的隐式状态机。
重构目标:
microvm-executor使用 Go 实现,与 scheduler 和公共 NATS runtime 共享类型与库ip/iptables输出qemu-img可以继续作为受控子进程调用;“不使用 shell 编排”不等于重写成熟的虚拟化工具microvm-runner-launch、microvm-runner-network和gitea-microvm-guest-runner应作为迁移完成条件,而非继续增加 shell 功能允许迁移期间保留现有脚本作为经过 smoke test 的兼容实现,但新生命周期逻辑不再加入 shell。Python webhook adapter 可以独立保留,直到被 source adapter 替换;不要求整个仓库在同一提交中统一技术栈。
更正:不要自行实现 hypervisor 管理层
上一条评论提出把 TAP、bridge、NAT、磁盘和 VM lifecycle 全部迁入 Go,这个方向不正确:它只是把现有 shell PoC 改写成自制的 hypervisor 管理工具,会扩大项目职责,也会重复实现成熟基础设施已有的资源管理、恢复与清理能力。
现有 shell launcher 的定位应明确为验证 Cloud Hypervisor + LXC/KVM + kind 可行性的 PoC,而不是未来 executor 的实现蓝本。
修正后的原则:
因此撤回“使用 Go netlink/nftables 自行管理 TAP、bridge、NAT”和“在 Go 中实现完整 instance lifecycle”的建议。下一步应先做 provider 选型,再决定 adapter 技术栈。
架构转向:以 OpenSandbox 作为 execution control plane
在调研 #21 后,backend 不应继续沿“自建 Pod worker + microVM worker + 公共 worker runtime”的方向重构。OpenSandbox 已经提供了我们准备实现的大部分 execution lifecycle:版本化 OpenAPI、异步创建、状态查询、TTL、删除重试、重启恢复、runtime provider、资源限制、诊断和 sandbox 内 exec endpoint。
新的职责边界:
本项目保留
交给 OpenSandbox
删除或降级
pod_worker.py与worker.py不再作为长期架构中的独立 backend servicemicrovm-runner-launch、network、guest shell 只保留为现有 PoC,迁移后删除仍需自行解决的 CI 特有问题
OpenSandbox 不理解 Gitea/GitHub job,因此不会替代 CI orchestrator:
/var/lib/docker新的首个设计产物
在继续写 backend 代码前,先定义一个最小
OpenSandboxProvidercontract:Ensure(execution):以幂等 metadata 创建或找到 sandboxGet(executionID):映射 OpenSandbox 状态为内部 lifecycleCancel(executionID):幂等删除 sandboxReconcile():发现并处理 orphan/missing/expired sandbox它应只是 OpenSandbox API adapter,不抽象或重写 hypervisor 细节。PoC 通过后再决定直接依赖 OpenSandbox API,还是采用其 lifecycle OpenAPI 作为可替换 provider contract。
首期部署拓扑
OpenSandbox Docker backend 应与 Docker/containerd、Kata runtime 和
/dev/kvm共置,不能把远程 Docker socket 当作 provider API,也不应为了运行它将主 k3s 节点改造成特权 sandbox host。建议首期部署:
为什么放在 pve2 runner LXC
/dev/kvm、privileged LXC、cgroup 与 AppArmor 路径已经通过 Cloud Hypervisor PoC 验证sandbox-node-1,而不是某个 CI runner 本身服务部署
控制面位置
ci-controller留在主 k3s:它需要稳定维护 Gitea/GitHub 会话、持有 source credential,并在 compute LXC 重启期间继续做退避和 reconciliation。OpenSandbox LXC 只持有 sandbox provider 所需凭据,不持有完整 Gitea/GitHub 控制面凭据。扩展路径
首期只注册一个 OpenSandbox endpoint。未来增加节点时,controller 维护 provider endpoint 列表与每节点容量/健康状态;每台 compute node 运行独立 OpenSandbox server。不要在 OpenSandbox 单 Docker backend 之上提前实现集群一致性。资源足够并决定采用 Kubernetes backend 后,再由 OpenSandbox 自身接管多节点调度。
故障语义
更正部署拓扑:使用 OpenSandbox Kubernetes 集群 backend
上一条“每台 LXC 一个 OpenSandbox Docker endpoint”的设计没有覆盖现有
podprofile,也放弃了 OpenSandbox Kubernetes backend 已有的多节点调度、Pool 与 BatchSandbox 生命周期,应撤回。正确方向是将 pve1/pve2 的 sandbox LXC 加入现有 k3s 集群作为专用 worker,而不是运行独立 Docker backend:
为什么需要两个 API profile
OpenSandbox 当前
[secure_runtime]是 server 实例级配置,官方文档明确说明启用后该 server 创建的 ALL sandboxes 都使用指定 runtime;batchsandbox_template_file也是单个 server 的全局模板。因此同一 API 实例目前不能按每次请求在 runc 与 Kata 间切换。首期部署两个无状态 OpenSandbox server Deployment,指向同一 Kubernetes backend/operator:
opensandbox-pod:不配置 secure runtime,模板用 node affinity/资源策略调度普通 Podopensandbox-vm:配置secure_runtime.type = kata与k8s_runtime_class = kata-*,模板带 Kata worker selector/tolerationCI controller 根据
runs-on: [self-hosted, pod|vm]选择对应 API service。两者仍属于同一 OpenSandbox/Kubernetes 集群控制面,不是每节点部署一套 provider。节点设计
sandbox.ddupan.top/kata=truelabel 与sandbox.ddupan.top/dedicated=ci:NoScheduletaint/dev/kvmpodjob 可继续使用现有 runc node pool;vmjob 只进入 Kata node pool收益
仍需 PoC 验证:pve1/pve2 LXC 作为 k3s worker 时 Kata runtime、CNI、block-backed
/var/lib/docker与 kind 是否正常。再次修正:独立 OpenSandbox k3s 集群 + 外部 SQL datastore
把 OpenSandbox/Kata/BatchSandbox 加入现有 homelab 集群虽然可行,但会把 CI sandbox 的 CRD、operator、RuntimeClass、特权节点、网络与故障域带入现有工作负载集群。这里应优先选择隔离复杂度,而不是追求少一个集群名字。
K3s 的三节点建议主要来自 embedded etcd quorum;它原生支持 PostgreSQL/MySQL/MariaDB 外部 datastore。官方 HA external DB 架构只要求两个或更多 server node,不要求三个 etcd member。因此建议拓扑改为:
控制面
k3s server,并使用同一个外部 PostgreSQL datastore;server 本身同时可调度 workload如果外部数据库首期尚未准备好,也可以先用单 server + embedded SQLite 完成 PoC,但 SQLite 不能支持多个 server,不能把它误当最终双节点形态。
workload profiles
pod:runc RuntimeClass,可在 pve1/pve2 两个 LXC 上运行vm:Kata RuntimeClass,同样跨两个节点调度并透传/dev/kvmsecure_runtime当前为 server 实例级配置隔离收益
这会撤回上一条“加入现有 k3s”的建议。保留 main k3s 中的 ci-controller 只是为了让 source 会话独立于 sandbox cluster 故障;若后续认为这点也不值得,controller 也可部署到独立 sandbox cluster,但需要接受集群不可用时无法维护 Gitea/GitHub 会话。