题干与适用场景
一个多租户集群有 GPU 显存、虚拟网卡带宽等不能简单按“整块设备”分配的资源。平台希望多个 Pod 共享同一设备,但每个请求必须有最小值、步长、上限和可追踪的分配身份。请基于 Kubernetes DRA consumable capacity 设计资源模型和端到端流程。
题目假设 Kubernetes 1.34 已启用相关能力,设备驱动能执行容量限制,调度器需要避免超卖。Kubernetes 1.34 让 DRA 核心 API GA,同时将 consumable capacity 作为 alpha 能力提供更细粒度的设备共享;因此回答必须明确哪些结论属于稳定核心,哪些仍受 feature gate 和驱动实现限制。
面试官考察点
强回答会把 DeviceClass、ResourceSlice、ResourceClaim、DeviceRequest 和驱动分工讲清楚,并写出“总已分配容量不超过设备容量”的不变量。它会区分预定义分片与动态容量,说明 allowMultipleAllocations、RequestPolicy、ShareID 和 DistinctAttribute 如何影响调度与隔离。
面试官还会检查候选人是否把调度成功误当成应用限速成功。真正的系统需要驱动执行带宽或显存限制、状态回报、跨命名空间授权、节点故障恢复和可回滚的灰度策略。
需要澄清的问题
资源是可切片还是可超卖
确认设备容量是否可被硬件或驱动强制隔离。不能强制隔离的资源只能做软配额或整设备分配,不能把 DRA API 当成实际 QoS 保证。
共享边界与授权
确认不同命名空间能否共享同一设备、是否允许管理员模式,以及租户是否能读取设备属性和容量。答案会改变 DeviceClass 选择器、Admission 控制与审计范围。
失败时要保持什么
确认调度失败、驱动分配失败、节点失联和 Pod 重建时,是释放容量、保留租约还是重新排队。短暂重试与不可恢复的硬件故障必须有不同状态。
30 秒回答框架
“我先定义容量不变量和租户隔离,再用 DeviceClass 描述可选设备,用 ResourceSlice 发布容量与请求策略,用 ResourceClaim 表达 Pod 的需求。调度器只负责选择满足容量和 selector 的设备,驱动通过 ShareID 为每个分配执行实际限制并回报状态。跨命名空间共享必须由授权和审计保护,所有释放操作要幂等。上线前先在单一设备类灰度,比较已分配容量、驱动实际限额、调度延迟、拒绝率和故障恢复时间。”
分步骤深入解答
第一步:写出资源模型
DeviceClass 表达设备类型和 CEL selector;ResourceSlice 发布具体设备、属性、容量和是否允许多次分配;ResourceClaim 通过 DeviceRequest 声明设备类与容量请求。把“设备总容量”和“本次请求容量”分开,避免把数量为一的设备请求误解成容量为一。
第二步:定义容量不变量
对每个设备维护已分配容量总和、容量单位和请求策略。若设备容量是 40 GiB,策略最小 5 GiB、步长 5 GiB,则每个请求必须满足边界和步长,且所有活跃 ShareID 的总和不超过 40 GiB。释放和重试都按分配版本幂等,不能因重复回调扣减两次。
第三步:描述调度与驱动数据流
调度器读取 ResourceSlice,过滤 DeviceClass selector、容量范围和 allowMultipleAllocations,预留候选后绑定 ResourceClaim。驱动收到分配结果,以 ShareID 建立独立限额,向设备施加显存或带宽约束,并把动态信息写入 ResourceClaim status。调度成功但驱动拒绝时,控制器必须把错误暴露为可重试或不可重试状态,而不是让 Pod 假装 Ready。
第四步:处理跨命名空间和重复设备
ResourceClaim 的命名空间边界不能被“共享设备”绕过。Admission 需要限制可用 DeviceClass、管理员访问和驱动配置;DistinctAttribute 用于同一个 claim 内要求不同底层设备,例如跨子网的两张网卡。审计记录租户、claim、ShareID、容量和策略版本,避免只记录最终设备名。
第五步:设计故障与回收
驱动重启时先从持久化状态恢复 ShareID 与实际限制;节点失联时由控制器标记分配未知,禁止立即把容量重新发给另一 Pod,直到租约、设备 fencing 或驱动确认完成。Pod 删除、claim 失效和调度回滚都必须能重复执行。若容量策略变化,已完成分配按旧快照解释,新 claim 使用新策略。
第六步:灰度、SLO 与容量估算
假设集群有 100 个设备、每个设备 40 GiB,目标平均利用率 70%,则可供调度的逻辑容量约为 2800 GiB;这不是可承诺的业务吞吐,还要扣除驱动保留、碎片和故障余量。为调度 p99、驱动配置 p99、容量拒绝率和状态收敛时间设 SLO,并按设备类逐步开启 feature gate。对照整设备分配测量吞吐、尾延迟、碎片和恢复时间。
第七步:比较替代方案
如果硬件只支持固定切片,MIG 或预切分的 DeviceClass 更简单,容量不变量也更容易证明;代价是碎片和弹性较差。若驱动不能执行细粒度限额,应退回整设备或节点扩展,不能用 API 中的 capacity 字段伪造隔离。
高质量示范回答
我会先确认设备是否能强制执行容量隔离。如果不能,方案只提供声明式选择,不承诺 QoS。能隔离时,DeviceClass 描述可选设备,ResourceSlice 发布容量和请求策略,ResourceClaim 表达租户请求。调度器只在容量总和不超卖且 selector 满足时绑定;驱动再用 ShareID 建立独立限额并回报 status。
我会把容量总和、版本和释放幂等写成不变量。跨命名空间共享需要 Admission、管理员授权和审计;DistinctAttribute 解决同一 claim 不能重复选同一底层设备。驱动或节点故障时先保留未知分配,完成 fencing 或确认后再回收。上线从单一设备类灰度,比较调度 p99、驱动配置 p99、拒绝率、实际限额与恢复时间;硬件只支持固定切片时选择预切分方案。
常见错误
- 错误表现 → 只在 ResourceClaim 中写容量 → 失败原因 → 驱动可能没有实际限额能力 → 修正方法 → 证明驱动执行和状态回报链路。
- 错误表现 → 用设备数量代替容量总和 → 失败原因 → 多个请求会隐式超卖或浪费碎片 → 修正方法 → 维护按设备和版本计算的已分配容量。
- 错误表现 → 共享设备等于跨租户无条件共享 → 失败原因 → 命名空间和授权边界被绕过 → 修正方法 → 加 Admission、管理员访问控制与审计。
- 错误表现 → 节点失联后立即释放全部容量 → 失败原因 → 旧驱动可能仍在施加限制,出现双重分配 → 修正方法 → 先 fencing、租约确认或显式未知状态。
- 错误表现 → 把 alpha feature gate 当成稳定 SLO → 失败原因 → API、驱动和升级行为仍有实现差异 → 修正方法 → 标出版本边界并灰度验证。
追问及应对
追问一:两个命名空间同时请求最后 10 GiB,如何避免竞态?
调度器需要以 ResourceSlice 版本或等价的乐观并发检查预留容量,绑定失败后重新观察最新状态。驱动回调不能自行突破调度器的不变量,最终分配仍须由控制面确认。
追问二:驱动报告 ShareID 已分配,但 Pod 没有启动怎么办?
把分配状态与 Pod 启动状态分开。控制器在超时后执行幂等释放或进入人工介入状态,并保留 ShareID、claim 版本和错误原因。不能因为 Pod 未 Running 就直接丢弃审计和容量记录。
追问三:容量策略从最小 5 GiB 改成最小 10 GiB,会影响已有 claim 吗?
已完成分配应按当时的策略快照保持语义,新请求使用新策略。若业务要求重新平衡,应创建显式迁移流程,先评估驱动是否支持缩放,再按可回滚步骤释放和重新分配。
追问四:如何证明共享带宽真的被限制?
在固定流量、相同节点和相同驱动版本下,运行单租户基线与多 ShareID 并发压测,比较每个租户的吞吐、p99、丢包和限额上界。只看 ResourceClaim status 不足以证明硬件 QoS 已生效。