已开启
新增提案:0006-沙箱动态挂载存储【WIP】 #9
刘艳松创建于 8月12日
新增提案:0006-沙箱动态挂载存储【WIP】 #9
已开启
刘艳松创建于 8月12日
共 1 个文件变更+367-0
@@ -0,0 +1,367 @@
1+# FluxSandbox 沙箱动态挂载存储
2+ 
3+## 概述
4+ 
5+本提案为 FluxSandbox 新增沙箱运行时动态存储挂载能力,兼容宿主机本地目录、K8s CSI PVC、沙箱快照、远端对象存储四类存储源;解决当前仅支持沙箱创建时静态一次性挂载、运行中无法增删存储卷的痛点,提升多租户数据隔离、大模型KV缓存、量化离线数据集场景资源弹性与业务连续性。
6+ 
7+## 动机
8+ 
9+### 背景
10+ 
11+当前 FluxSandbox 沙箱存储挂载仅支持创建阶段静态批量注入,所有挂载配置在 Agent 调用 containerd 创建容器时一次性写入 OCI Mount 配置,沙箱进入 Running 状态后无法新增 / 卸载存储,存在多重业务瓶颈:
12+- 多租户场景:用户独立持久 PVC 无法按需绑定,全局静态挂载存在跨租户文件越权风险;
13+- 快照预热能力无动态绑定入口,预加载数据集镜像无法挂载至已运行沙箱;
14+- 存储调度无拓扑感知,PVC 与沙箱跨节点挂载带来大量跨机网络 IO,推理延迟升高。
15+- 现有调度仅完成算力均衡,缺少存储维度亲和调度;同时存量静态挂载逻辑无法满足弹性存储诉求,亟需一套统一的静态 + 动态双模式存储编排能力。
16+ 
17+### 目标
18+ 
19+- 双模式挂载兼容:保留创建期静态批量挂载存量能力,新增运行时动态热挂载 / 卸载接口;
20+- 统一存储抽象:支持本地宿主机目录、K8s CSI PVC、沙箱快照镜像、远端 OSS 四类存储源;
21+- 联动拓扑亲和调度:动态挂载 PVC 时优先调度至存储同拓扑节点,降低跨节点 IO 损耗;
22+- 沙箱粒度隔离:单沙箱独立存储权限、读写控制、容量限制,满足多租户合规;
23+- 无侵入改造:不新增 CRD,扩展现有 Sandbox CR 字段,兼容存量 SandboxGroup 调度逻辑;
24+- 完整可观测:存储挂载 / 卸载事件、IO 资源占用、卷生命周期全链路日志与监控上报。
25+ 
26+### 非目标
27+ 
28+- 不实现沙箱内文件系统在线扩容,仅支持新增 / 卸载独立存储卷;
29+- Alpha 阶段不支持存储卷跨沙箱迁移;
30+- 不改造底层 containerd 运行时,复用原生 OCI Mount、UpdateContainer 标准能力;
31+- 暂不支持存储卷配额动态修改,容量限制创建 / 挂载时一次性指定。
32+ 
33+## 提案
34+ 
35+### 用户故事
36+ 
37+#### Story1 LLM PD 分离推理动态扩容 KV 缓存
38+集群已开启拓扑亲和调度,Node 打上unifiedbus.com/superpod拓扑标签,PVC 绑定对应超节点拓扑域。推理流量突增,Decode 沙箱显存 KV 缓存不足:
39+- 业务侧 OpenSandbox SDK 调用AddSandboxVolume动态挂载高速本地 PVC;
40+- FluxSandbox Controller 更新 Sandbox CR spec.dynamicVolumes;
41+- Scheduler 联动拓扑缓存,校验 PVC 与沙箱同超节点拓扑,下发挂载指令至对应 Agent;
42+- Agent 完成 PVC 在 Pod 层挂载后,调用 containerd 动态追加 mount 配置,沙箱无需重启即可使用 KV 存储;
43+- 流量回落时调用RemoveSandboxVolume卸载闲置存储,释放集群存储资源。
44+#### Story2:可用区容灾
45+ 
46+平台租户创建沙箱时静态挂载公共只读模型目录,运行中动态绑定个人专属 PVC 持久化代码与回测结果,不同租户 PVC 相互隔离,无跨目录访问权限。
47+ 
48+### 风险与缓解措施
49+ 
50+- **风险1**:containerd 动态更新容器 mount 失败,沙箱文件系统异常
51+ - **缓解**:Agent 增加挂载事务逻辑,追加失败自动回滚原有 mount 列表,日志输出完整错误堆栈;新增挂载前置校验(路径白名单、容量、权限),拦截非法挂载请求。
52+- **风险2**:PVC 跨拓扑节点挂载,产生大量跨节点网络 IO
53+ - **缓解**:动态挂载时读取 PVC 绑定拓扑标签,与沙箱所在拓扑域对比,不匹配时返回告警,提供强制挂载开关供业务兜底。
54+- **风险3**:沙箱销毁时动态存储卷残留未清理
55+ - **缓解**:Sandbox 控制器监听沙箱删除事件,自动下发批量卸载指令,Agent 兜底清理临时快照目录与 bind 挂载。
56+- **风险4**:频繁动态挂载引发 k8s PVC API 风暴
57+ - **缓解**:Agent 层缓存 PVC 挂载状态,同一 PVC 重复挂载请求去重,增加限流阈值。
58+ 
59+## 设计细节
60+ 
61+### 整体架构
62+ 
63+```mermaid
64+flowchart TD
65+ SDK["OpenSandbox SDK"] --> Server["OpenSandbox Server"]
66+ Server --> Ctrl["flux-sandbox-controller"]
67+ subgraph Scheduler Runtime
68+ SSGRuntime["SSGRuntime"]
69+ Registry["InMemoryRegistry"]
70+ VolMgr["VolumeManager 存储调度子模块"]
71+ end
72+ Ctrl --> SSGRuntime
73+ SSGRuntime --> Registry
74+ SSGRuntime --> TopoCache
75+ SSGRuntime --> VolMgr
76+ VolMgr --> Agent["flux-sandbox-agent"]
77+ Agent --> Containerd["containerd/nerdctl 运行时"]
78+ Agent --> CSI["K8s CSI PVC"]
79+ Agent --> Snapshot["快照预热模块"]
80+```
81+ 
82+### 核心概念
83+ 
84+- **静态卷 volumeMounts**:沙箱创建时一次性注入,生命周期与沙箱同步,存量兼容逻辑;
85+- **动态卷 dynamicVolumes**:沙箱 Running 状态下可通过 gRPC 增删,存储源独立生命周期;
86+- **存储源类型**:local (宿主机目录)、pvc (K8s 持久卷)、snapshot (数据集快照)、oss (远端对象存储);
87+- **拓扑存储亲和**:动态 PVC 挂载时,匹配 PVC 绑定 node 拓扑标签与沙箱所在调度域。
88+ 
89+### API 与 CRD 扩展设计
90+#### Sandbox CR 字段扩展(api/v1alpha1 SandboxSpec)
91+ 
92+不新增 CRD,扩展现有 spec 字段,完全向下兼容:
93+ 
94+```go
95+// SandboxSpec 扩展存储字段
96+type SandboxSpec struct {
97+ // 存量静态挂载,创建时一次性生效,兼容旧业务
98+ VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
99+ // 新增动态挂载列表,控制器监听字段变更实现热更新
100+ DynamicVolumes []DynamicVolume `json:"dynamicVolumes,omitempty"`
101+}
102+ 
103+// VolumeMount 静态挂载结构(存量复用)
104+type VolumeMount struct {
105+ Source string `json:"source"`
106+ Target string `json:"target"`
107+ Mode string `json:"mode"` // ro/rw
108+}
109+ 
110+// DynamicVolume 动态挂载独立结构
111+type DynamicVolume struct {
112+ VolumeType string `json:"volumeType"` // local/pvc/snapshot/oss
113+ Source string `json:"source"` // 路径/PVC名称/快照ID
114+ Target string `json:"target"` // 沙箱内挂载目录
115+ Mode string `json:"mode"` // ro/rw
116+ SizeLimit string `json:"sizeLimit"` // 容量上限,防磁盘打满
117+ TenantID string `json:"tenantId"` // 租户隔离标识
118+}
119+```
120+ 
121+CR YAML 示例:
122+ 
123+```yaml
124+apiVersion: sandbox.flux.io/v1alpha1
125+kind: Sandbox
126+spec:
127+ volumeMounts:
128+ - source: /agent/public/models
129+ target: /sandbox/public
130+ mode: ro
131+ dynamicVolumes:
132+ - volumeType: pvc
133+ source: user-001-data
134+ target: /sandbox/workspace
135+ mode: rw
136+ sizeLimit: 50Gi
137+ tenantId: t-10086
138+```
139+ 
140+#### Controller 新增动态存储 gRPC 接口
141+ 
142+```protobuf
143+// 新增沙箱动态存储服务
144+service SandboxVolumeService {
145+ // 运行时新增存储卷
146+ rpc AddSandVolume(AddSandVolumeRequest) returns (AddSandVolumeResponse);
147+ // 卸载指定存储卷
148+ rpc RemoveSandVolume(RemoveSandVolumeRequest) returns (RemoveSandVolumeResponse);
149+ // 查询沙箱全部静态+动态挂载列表
150+ rpc ListSandVolumes(ListSandVolumesRequest) returns (ListSandVolumesResponse);
151+}
152+```
153+### 核心组件改造
154+ 
155+#### SSGRuntime 新增 VolumeManager 存储子模块
156+ 
157+```go
158+type SSGRuntime struct {
159+ Key SubSandboxGroupKey
160+ Registry *InMemoryRegistry
161+ Engine *SandboxSchedulerEngine
162+ SchedulingWeights *SchedulingWeights
163+ SchedulingStrategy string
164+ TopologyCache *TopologyDomainCache // 复用0003拓扑缓存
165+ VolMgr *VolumeManager // 新增存储管理器
166+ Synced bool
167+ mu sync.RWMutex
168+}
169+```
170+VolumeManager 核心能力:
171+- 读取 Sandbox dynamicVolumes 变更事件;
172+- 结合 TopologyCache 校验 PVC 拓扑亲和匹配度;
173+- 下发挂载 / 卸载指令至对应 Agent;
174+- 统计各调度域存储占用,输出均衡日志。
175+#### flux-sandbox-agent 新增容器动态挂载能力
176+- 新增ContainerMountUpdater组件,封装 containerd UpdateContainer API:
177+- 前置校验:挂载路径白名单、租户匹配、容量校验、路径冲突检测;
178+- PVC 存储:先在 Agent Pod 完成 CSI 挂载,再 bind 透传至沙箱;
179+- 快照存储:调用快照模块拉取镜像生成临时目录;
180+- 事务保障:挂载失败回滚原有 mount 列表,输出完整错误日志;
181+- 沙箱销毁钩子:批量清理全部动态挂载目录。
182+#### 拓扑亲和联动逻辑
183+- 动态挂载 PVC 流程拓扑校验步骤:
184+- VolumeManager 读取 PVC 绑定的 node 拓扑标签;
185+- 通过 TopologyCache 获取沙箱当前所在调度域标识;
186+- 标签匹配则允许正常挂载;不匹配输出 WARN 日志,提供forceMount参数强制跨节点挂载兜底。
187+ 
188+### 关键流程
189+ 
190+#### 沙箱动态挂载完整流程
191+- OpenSandbox SDK 调用AddSandVolume gRPC 接口,传入沙箱 ID、动态卷参数;
192+- flux-sandbox-controller 更新对应 Sandbox CR spec.dynamicVolumes数组;
193+- SubSandboxGroupWatcher 感知 CR 变更,同步至对应 SSGRuntime;
194+- VolumeManager 读取动态卷配置,复用 TopologyCache 校验 PVC 拓扑亲和;
195+- 根据沙箱 ID 匹配所属 Agent Pod,下发动态挂载指令;
196+- Agent 执行前置校验,区分存储源完成 Pod 层资源挂载;
197+- 调用 containerd 动态追加 OCI Mount 配置,execd 刷新沙箱文件系统视图;
198+- 挂载完成后写入事件日志,上报存储监控指标。
199+#### Sandbox CR 静态挂载初始化流程(存量兼容)
200+沙箱首次分配时,Agent 合并volumeMounts静态列表与初始化动态卷列表,一次性组装 OCI 配置创建容器,原有逻辑无改动。
201+#### 配置变更与清理流程
202+- 动态卷删除:调用RemoveSandVolume,控制器清理 CR 内对应条目,Agent 卸载对应目录;
203+- 沙箱销毁:控制器触发批量卸载,Agent 清理快照临时目录、bind 挂载,防止存储残留。
204+ 
205+### DFX设计
206+ 
207+#### 可靠性设计
208+ 
209+- **缓存降级**:TopologyDomainCache 缓存失效时,跳过拓扑校验,允许强制挂载,不阻断业务;
210+- **Agent 重启恢复**:重启后扫描本地已存在动态挂载目录,重建内存映射;
211+- **事务回滚**:单次挂载操作原子化,部分步骤失败全部撤销变更;
212+- **兜底清理**:节点 DaemonSet sandbox-watcher 定时扫描孤儿临时快照目录,自动回收磁盘。
213+#### 性能设计
214+ 
215+- 调度热路径无额外 k8s API,拓扑信息复用 0003 内存缓存;
216+- Agent 层 PVC 挂载状态本地缓存,重复请求去重,减少 CSI 调用;
217+- 动态卷列表操作 O (n),单沙箱挂载卷数量上限可控,不影响调度耗时;
218+- 稳态无新增周期性轮询开销,仅 CR 变更触发存储同步。
219+#### 安全性设计
220+ 
221+- **路径白名单**:禁止挂载/、/etc、/proc等系统敏感目录;
222+- **租户隔离**:动态卷绑定 TenantID,跨租户无法操作对方存储卷;
223+- **容量限流**:每个动态卷配置 SizeLimit,防止单沙箱打满节点磁盘;
224+- **最小权限**:Scheduler 仅读取 PVC 基础信息,无修改存储资源权限。
225+#### 可维护性设计
226+ 
227+- **日志可追溯**:每条动态挂载 / 卸载日志携带沙箱 ID、租户、存储源、拓扑匹配结果;
228+- **监控指标**:新增sandbox_dynamic_volume_count、sandbox_pvc_cross_topology_mount指标;
229+- **灰度开关**:SandboxGroup 可单独关闭动态挂载能力,单集群灰度验证;
230+- **兼容降级**:删除dynamicVolumes字段自动回退为仅静态挂载模式。
231+### 测试计划
232+ 
233+[ ] 我/我们理解,相关组件的所有者可能会要求更新已有的测试,以便在提交实现该增强功能所需的更改之前,使代码达到足够稳固的质量标准。
234+ 
235+##### 单元测试
236+- VolumeManager 拓扑亲和匹配校验单元用例;
237+- ContainerMountUpdater 挂载事务回滚测试;
238+- DynamicVolume CR 字段序列化 / 反序列化兼容测试。
239+##### 集成测试
240+ 
241+- 单超节点集群,沙箱运行中动态挂载 PVC,验证读写正常;
242+- 跨拓扑 PVC 挂载,校验告警日志与强制挂载能力;
243+- 快照镜像动态挂载、卸载全流程验证。
244+ 
245+##### e2e 测试
246+ 
247+- PD 分离推理场景,动态扩容 Decode KV 存储,验证推理任务不中断;
248+- 批量创建沙箱 + 批量动态挂载,验证存储均衡分布;
249+- 沙箱销毁后检查动态卷目录自动清理。
250+ 
251+### 毕业标准
252+ 
253+#### Alpha 阶段
254+- 动态卷 gRPC 接口、Sandbox CR 字段扩展完成;
255+- 本地目录、PVC 两类存储源挂载逻辑实现;
256+- 单元测试、基础集成测试通过;
257+- FeatureGate 开关控制,默认关闭。
258+ 
259+#### Beta 阶段
260+- 快照、OSS 存储源支持完成;
261+- 拓扑亲和校验完整落地;
262+- 监控指标、完整日志告警补齐;
263+- 多租户隔离、容量限制安全机制完备。
264+ 
265+#### GA 阶段
266+- 完整故障演练(容器挂载失败、PVC 离线、Scheduler 重启)通过;
267+- 运维文档、SDK 使用示例完备。
268+ 
269+### 升级/降级策略
270+ 
271+- **升级**:新增`dynamicVolumes`可选字段,旧版本控制器自动忽略,存量静态挂载行为不变,无数据迁移;
272+- **降级**:回退旧版本后,CR 新增字段被忽略,动态挂载能力失效,已挂载存储持续生效至沙箱销毁,不中断业务;
273+- **配置兼容**:新增配置。
274+ 
275+### 版本倾斜策略
276+ 
277+- 控制器、Scheduler、Agent 渐进式灰度升级,新旧组件共存时动态挂载功能自动关闭,保证兼容性。
278+ 
279+## 生产可用性审查
280+ 
281+### 功能启用和回滚
282+ 
283+###### 如何在实时集群中启用/禁用此功能?
284+ 
285+- [x] **通过 SandboxGroup CR 特性开关控制:**
286+```yaml
287+spec:
288+ featureGates:
289+ dynamicVolumeMount: true
290+```
291+修改 CR 后无需重启组件,SSGRuntime 下一个同步周期生效,可单分组灰度。
292+ 
293+###### 启用该功能会改变任何默认行为吗?
294+ 
295+默认 `dynamicVolumeMount` 关闭,仅静态挂载生效,行为与现有版本完全一致;开启后新增动态热挂载能力,原有创建时静态挂载逻辑无任何变更。
296+ 
297+###### 该功能一旦启用,是否可以禁用?
298+ 
299+可以。将 `dynamicVolumeMount.Enabled` 设为 `false` 或删除 `dynamicVolumeMount` 字段即可回退到静态挂载存储,无需重启。
300+ 
301+###### 如果该功能之前已回滚,现在我们重新启用它会发生什么情况?
302+ 
303+可以,关闭后不再接收新的动态挂载请求,已存在的动态卷持续可用,沙箱销毁时正常清理。
304+ 
305+###### 是否有任何针对功能启用/禁用的测试?
306+ 
307+- 单元测试覆盖 `dynamicVolumeMount.Enabled=true` 和 `dynamicVolumeMount.Enabled=false` 两种场景
308+ 
309+### 监控要求
310+ 
311+###### 操作员如何确定该功能是否正在被工作负载使用?
312+ 
313+- 检查 SandboxGroup CR 的 `spec.schedulingPolicy.topologyAffinity.enabled` 字段
314+- Scheduler 日志中搜索 `topologyAffinity enabled` 关键字
315+ 
316+###### 使用此功能的人如何知道它适用于他们的实例?
317+ 
318+###### 增强的合理 SLO 是什么?
319+ 
320+###### 运维人员可以使用哪些服务级别指标来来判断服务的健康状况?
321+ 
322+### 依赖项
323+ 
324+###### 此功能是否依赖于集群中运行的任何特定服务?
325+ 
326+- K8S API:读取 PVC 信息、node 拓扑标签(复用 0003 缓存逻辑,无高频新增调用);
327+- containerd:依赖容器 Update 挂载原生 API;
328+- 快照预热模块:快照类型存储依赖配套提案能力。
329+ 
330+### 可扩展性
331+ 
332+###### 启用/使用此功能会导致任何新的 API 调用吗?
333+ 
334+- **API 调用类型**:`GET /api/v1/nodes/{nodeName}`(每个新发现的 node 一次)
335+- **预估调用频率(吞吐量)**:稳态下为 0(全量缓存)。新增 node 时每个 node 一次调用。160 个 node 的集群,首次同步 160 次 GET 请求。
336+- **调用发起组件**:FluxSandboxScheduler(FluxSandboxLoop)
337+ 
338+###### 启用/使用此功能是否会导致引入新的 API 类型?
339+ 
340+无新增 CRD,仅扩展 Sandbox CR 可选字段。
341+ 
342+###### 启用/使用此功能是否会导致现有 API 对象的大小或数量增加?
343+ 
344+- **API 类型**:`SandboxVolumeService`
345+- **预估对象体积增加量**:扩展 Sandbox CR 可选字段,单对象增量 < 200 字节
346+- **预估新增对象数量**:无新增对象
347+ 
348+###### 启用/使用此功能是否会导致任何组件的资源使用率不可忽略的增加?
349+ 
350+- `TopologyDomainCache` 内存占用:每个 node 映射约 100 字节,160 个 node 约 16KB,可忽略。
351+- 拓扑打分计算:O(域数量),通常不超过 100 个域,每次调度增加的计算量可忽略。
352+ 
353+## 实施历史
354+ 
355+- 2026-08-12:提案创建
356+ 
357+## 缺点
358+ 
359+- Alpha 阶段仅支持容器追加挂载,不支持运行中修改已有挂载读写权限;
360+- PVC 资源不均衡时无法自动迁移沙箱至同存储拓扑节点;
361+- 动态挂载失败仅回滚本次操作,不会自动重试,需要业务侧重试补偿。
362+ 
363+## 替代方案
364+ 
365+- 全量静态预挂载:提前挂载所有可能用到的 PVC,资源浪费严重,多租户隔离差;
366+- 销毁重建沙箱:中断推理 / 计算任务,业务连续性差;
367+- Agent Pod 全局共享存储:无沙箱粒度隔离,存在文件冲突、越权风险。