题干与适用场景
一个多租户机器学习平台使用 GPU、FPGA 和高速网卡。现有方案通过节点标签、扩展资源和设备插件分配整块设备,难以表达设备属性、共享容量和租户隔离。团队计划采用 Kubernetes 1.34 中已升级为稳定版的 Dynamic Resource Allocation(DRA)。
请设计从旧方案迁移到 DRA 的系统,并说明 ResourceClaim、DeviceClass、ResourceClaimTemplate、ResourceSlice、驱动和调度器之间的责任边界。假设集群需要渐进式迁移,不能一次性重启所有工作负载。
面试官考察点
面试官看重候选人是否把“声明设备需求”和“实际分配设备”分开,能否解释控制面 API、调度器、节点驱动与 kubelet 的数据流;是否知道 DRA 的 resource.k8s.io/v1 API 稳定并非意味着所有驱动能力都稳定。
强回答还会处理容量共享、跨命名空间引用、驱动不可用、Pod 重建、旧工作负载共存、权限最小化和回滚指标,而不是只罗列资源对象。
回答前需要澄清的问题
- 设备需求是整卡、可切分容量,还是按属性选择任意设备?
- 设备驱动是否支持 DRA,能否同时运行旧设备插件?
- ResourceClaim 的生命周期由工作负载创建,还是由平台模板生成?
- 租户是否允许跨命名空间复用 Claim,哪些对象由平台控制器写入?
- 迁移期间要保持 GPU 作业连续性、调度吞吐还是资源利用率?
30 秒回答框架
“我会先把设备需求建模成 Claim,再让驱动负责设备发现、分配和节点配置,调度器只依据 ResourceSlice 和 Claim 的声明做可行性判断。先以独立命名空间和少量设备类灰度,旧设备插件与 DRA 并存但不让同一设备被两套控制面管理。每个阶段都验证 Claim 状态、Pod 绑定、节点可见性、驱动错误、分配延迟和租户边界;发现分配错误就停止新 Claim、保留运行中作业并回退新工作负载到旧路径。”
分步骤深入解答
先画出 DRA 数据流
工作负载通过 Pod 的 resourceClaims 引用 Claim。Claim 可以由用户直接创建,也可以由 ResourceClaimTemplate 为 Job 或其他控制器生成。DeviceClass 描述可选择的设备类别,ResourceSlice 由驱动发布节点上的设备和属性。调度器结合 Pod、Claim、DeviceClass 和 ResourceSlice 选择节点;节点侧驱动随后完成具体分配和配置。
这条链路把“选择哪个设备”从应用 YAML 中抽离出来,避免平台把硬件拓扑编码成标签约定。
设计 Claim 模板与租户边界
模板只暴露租户需要的参数,例如显存档位、互联类型或网络带宽,不让租户直接写驱动内部标识。平台控制器为每个命名空间设置准入策略、配额和生命周期清理;跨命名空间 Claim 必须有明确的引用权限和审计事件。删除租户时先停止新 Claim,再等待 Pod 释放,最后回收设备状态。
处理整卡与可共享容量
整卡分配可以把一个 DeviceRequest 映射到一个设备。若要共享显存、带宽或时间片,需要驱动发布容量并开启对应的 DRA consumable capacity 能力;不能仅在调度器标签上模拟共享,否则调度成功后可能在节点上超卖。容量模型应定义单位、并发上限、回收时机和碎片化策略。
与旧设备插件并存
迁移阶段按设备类或节点池切分,不让旧插件和 DRA 同时声明同一硬件。旧工作负载继续使用扩展资源,新工作负载引用 DRA Claim;节点池标签只做迁移边界,不作为最终的设备属性来源。每个池都要有清晰的所有权和禁用开关,避免驱动重复初始化。
处理调度、抢占与失败
Claim 处于等待或分配失败时,Pod 应保持可解释的 Pending 原因。调度器选择节点不等于设备已经可用;驱动可能在节点配置阶段失败,因此控制器必须把失败状态传递给平台告警,并按可重试、不可重试和需人工清理分类。抢占策略要同时考虑 Pod 优先级、Claim 已占用容量和释放延迟,不能只按 CPU 或内存排序。
观测与容量规划
记录 Claim 创建到绑定、绑定到节点分配、分配到 Pod Ready 的分段时延;分别统计设备空闲、已分配、不可用、碎片化和驱动错误。把 ResourceSlice 发布的容量与节点实际可见性做周期性对账,发现漂移时禁止继续扩大灰度。对训练作业还要记录重试、检查点恢复和设备健康事件。
灰度、回滚与数据一致性
第一阶段只选一个驱动和一个节点池,先运行可重试作业;第二阶段扩大到多租户并启用模板;最后才迁移长时间、不可中断作业。回滚不是删除已绑定 Claim:应先停止新 Claim 创建,等待或迁移运行中 Pod,冻结驱动变更,再让新作业回到旧设备插件。保留 Claim、Pod 和驱动事件,避免回滚后失去事故证据。
验证 API 与安全边界
部署前用 resource.k8s.io/v1 API 做契约测试,验证 Claim、Template、DeviceClass 和 ResourceSlice 的版本、状态转换和删除顺序。用故障注入测试驱动重启、节点失联、重复分配、Claim 泄漏和跨命名空间访问;同时检查准入、RBAC、审计和节点代理权限。只有功能、隔离和恢复指标都通过,才扩大设备池。
高质量示范回答
“我会把迁移拆成资源模型、驱动、调度和运行时四层。工作负载只声明 Claim,Template 负责批量生成,DeviceClass 表达选择语义,驱动发布 ResourceSlice 并在节点完成分配,调度器只做可行性和节点选择。旧设备插件与 DRA 按节点池或设备类并存,禁止双重管理同一设备。对共享容量,我要求驱动提供容量模型和回收语义,不用标签模拟超卖。上线先从可重试作业开始,观测 Claim 到 Ready 的分段时延、分配失败、碎片化、驱动健康和租户越权;回滚时停止新 Claim、保留运行中作业和事件,再把新作业切回旧路径。”
常见错误
- 把 DRA 当成新的设备标签 → 调度成功但节点无法兑现 → 让驱动发布结构化设备与容量。
- 旧插件和 DRA 管同一设备 → 出现重复初始化或双重分配 → 按池或设备类隔离所有权。
- 只设计 Claim,不设计回收 → 设备和配额逐渐泄漏 → 定义释放、超时、删除和对账流程。
- 用标签模拟可共享容量 → 调度器看不到真实剩余容量 → 由驱动提供容量与并发约束。
- 把节点选中当成分配成功 → 驱动失败导致长时间 Pending → 拆分调度、节点分配和 Ready 指标。
- 回滚时删除所有 Claim → 运行中作业和事故证据丢失 → 先冻结新分配,保留状态并迁移可恢复任务。
追问及应对
追问一:为什么不直接把 GPU 继续注册成扩展资源?
扩展资源适合简单的数量请求,但难以表达设备属性、可选方案、共享容量和复杂配置。若需求确实只有整卡计数且驱动成熟,旧方案可以继续使用;引入 DRA 应由设备选择和生命周期复杂度驱动。
追问二:一个 Claim 被多个 Pod 引用时如何防止超卖?
Claim 的复用语义必须由驱动和平台策略明确,不能只依赖 YAML 约定。对可共享容量,驱动需要记录已分配容量、并发上限和回收状态;准入层限制不符合租户策略的引用。
追问三:驱动在节点配置阶段失败,调度器应该重试吗?
先区分暂时性节点故障、设备健康问题和 Claim 参数错误。暂时性故障可重试并退避;参数错误应标记不可重试并提示修正;设备健康问题要隔离节点,避免调度器不断把作业送回同一故障域。
追问四:如何验证迁移没有降低资源利用率?
用同一设备池和相近工作负载比较分配成功率、等待时延、碎片化、有效计算时间和作业重试率。把 DRA 与旧插件按设备类分组,不能只看整个集群平均 GPU 使用率。