Kueue 核心概念解析:ResourceFlavor、ClusterQueue 与 LocalQueue 的协同设计
Kueue 是 Kubernetes 原生的批调度队列系统,专为管理批量工作负载的资源分配而设计。它通过三个核心概念——ResourceFlavor、ClusterQueue 和 LocalQueue——构建了一个多层次、灵活的资源管理体系。本文将深入解析这三个组件的功能、关联关系以及它们如何协同工作。
一、ResourceFlavor:资源类型的抽象定义
1.1 基本概念
ResourceFlavor 是 Kueue 中资源类型的抽象描述,它定义了计算节点的特性和约束条件,相当于为集群中的资源打上分类标签。
apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
name: gpu-a100
spec:
nodeLabels:
gpu-type: a100 # 匹配节点标签
nodeTaints:
- key: gpu # 定义节点污点
value: "true"
effect: NoSchedule
tolerations: # 自动添加的容忍度
- key: gpu
operator: Equal
value: "true"
effect: NoSchedule
1.2 关键功能
- 节点选择:通过
nodeLabels
关联特定节点 - 访问控制:通过
nodeTaints
限制资源使用 - 自动注入:将定义的容忍度注入到匹配的工作负载
1.3 工作原理
- 当工作负载使用带有 ResourceFlavor 的 ClusterQueue 时
- Kueue 会比较工作负载的节点亲和性和 ResourceFlavor 的约束
- 不匹配的工作负载会被拒绝调度
- 匹配的工作负载会自动获得 ResourceFlavor 中定义的容忍度
版本注意:使用节点标签匹配需要 Kubernetes 1.23+
二、ClusterQueue:资源池的核心逻辑
2.1 基本架构
ClusterQueue 是 Kueue 的核心资源池概念,它定义了:
- 可用的资源类型(通过 ResourceFlavor)
- 资源配额分配规则
- 资源竞争和调度策略
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: ai-training
spec:
namespaceSelector: # 命名空间选择器
matchLabels:
team: ai
resourceGroups:
- coveredResources: ["cpu", "memory", "nvidia.com/gpu"]
flavors:
- name: "gpu-a100" # 引用 ResourceFlavor
resources:
- name: "nvidia.com/gpu"
nominalQuota: 8 # 基准配额
borrowingLimit: 4 # 最大可借用量
queueingStrategy: BestEffortFIFO
cohort: ai-cluster # 队列集团
2.2 关键配置解析
资源配额管理
字段 | 说明 |
---|---|
nominalQuota | 基准配额,保障性资源量 |
borrowingLimit | 可借用其他队列的资源上限 |
lendingLimit | 可借出给其他队列的资源量 |
队列策略
-
queueingStrategy:
StrictFIFO
:严格先进先出,可能阻塞BestEffortFIFO
:尽力而为,提高利用率
-
cohort:
- 资源借用的逻辑分组
- 同一 cohort 内的队列可相互借用资源
抢占机制
spec:
preemption:
reclaimWithinCohort: LowerPriority
borrowWithinCohort:
policy: LowerPriority
maxPriorityThreshold: 100
withinClusterQueue: LowerOrNewerEqualPriority
ClusterQueue
必须绑定 ResourceFlavor
才能正常工作
- 在 Kueue 中,
ClusterQueue
必须绑定ResourceFlavor
才能正常工作,不能完全独立使用。这是由 Kueue 的资源管理模型决定的,但具体约束的严格程度取决于配置方式。以下是详细说明:
1. 为什么必须绑定 ResourceFlavor?
ClusterQueue
的核心功能是 管理资源配额,而配额必须关联到具体的资源类型(即 ResourceFlavor
)。这是因为:
- 资源异构性:集群中可能存在多种资源类型(如 CPU、GPU、高内存节点等),需要明确分配哪种资源。
- 配额细分:不同
ResourceFlavor
的配额是分开管理的(例如:队列可以同时有cpu-flavor
和gpu-flavor
的独立配额)。
2. 绑定方式与灵活性
虽然必须绑定 ResourceFlavor
,但可以通过以下方式灵活配置:
(1) 默认 ResourceFlavor
如果集群只有一种通用资源类型,可以创建一个空的 ResourceFlavor
(如你提供的示例),作为默认资源池:
# 空 ResourceFlavor(逻辑分组)
apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
name: default-flavor
spec: {} # 无特殊属性
然后在 ClusterQueue
中引用它:
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: default-queue
spec:
resourceGroups:
- coveredResources: ["cpu", "memory"] # 管理的资源类型
flavors:
- name: "default-flavor" # 绑定空 ResourceFlavor
resources:
- name: "cpu"
nominalQuota: 100
- name: "memory"
nominalQuota: 100Gi
(2) 多 ResourceFlavor 绑定
对于复杂场景,可以绑定多个 ResourceFlavor
:
spec:
resourceGroups:
- coveredResources: ["cpu", "nvidia.com/gpu"]
flavors:
- name: "gpu-flavor" # 高优先级 GPU 资源
resources:
- name: "nvidia.com/gpu"
nominalQuota: 8
- name: "default-flavor" # 普通 CPU
resources:
- name: "cpu"
nominalQuota: 50
3. 如果不绑定 ResourceFlavor 会怎样?
- 创建
ClusterQueue
时会报错:Kueue 的校验逻辑会要求spec.resourceGroups.flavors
至少包含一个有效的ResourceFlavor
。 - 工作负载无法被调度:即使
ClusterQueue
创建成功,没有关联的ResourceFlavor
会导致工作负载找不到可用资源。
4. 特殊情况:隐式默认 ResourceFlavor
某些 Kueue 实现可能允许:
- 自动绑定集群全局默认
ResourceFlavor
(如果未显式指定)。 - 动态生成
ResourceFlavor
(例如通过控制器自动发现节点标签)。
但这类行为依赖具体实现,并非标准特性。
5. 最佳实践建议
- 始终显式绑定
ResourceFlavor
:即使只有一种资源类型,也明确声明。 - 空
ResourceFlavor
作为兜底:如你的示例所示,可用于简单场景。 - 利用标签选择器:通过
ResourceFlavor
的spec.nodeSelector
精确控制资源匹配。
总结
问题 | 答案 |
---|---|
ClusterQueue 能否单独使用? | 不能,必须至少绑定一个 ResourceFlavor (即使是空的逻辑分组)。 |
为什么需要绑定? | 资源配额必须关联到具体的资源类型(ResourceFlavor )。 |
如何简化配置? | 使用空的 ResourceFlavor 作为默认资源池。 |
这种设计确保了资源分配的明确性和可审计性,避免了模糊的全局默认值导致的调度冲突。
三、LocalQueue:命名空间级接入点
3.1 定位与作用
LocalQueue 是 ClusterQueue 在命名空间维度的映射,它:
- 将 ClusterQueue 的能力暴露给特定命名空间
- 实现多租户隔离
- 简化用户操作
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
namespace: ai-team-a
name: training-queue
spec:
clusterQueue: ai-training # 关联的 ClusterQueue
3.2 工作流程
- 用户在工作负载中指定 LocalQueue
- Kueue 通过 LocalQueue 找到对应的 ClusterQueue
- 根据 ClusterQueue 的规则进行资源分配
四、三者的协同关系
4.1 层级架构
ResourceFlavor (资源类型定义)
↑
ClusterQueue (核心资源池)
↑
LocalQueue (命名空间接入点)
↑
Workload (用户任务)
4.2 交互流程
-
资源定义阶段:
- 管理员创建 ResourceFlavor 描述资源特性
- 创建 ClusterQueue 并绑定 ResourceFlavor
- 在各命名空间创建 LocalQueue 关联 ClusterQueue
-
工作负载提交阶段:
apiVersion: kueue.x-k8s.io/v1beta1 kind: Workload metadata: namespace: ai-team-a spec: queueName: training-queue # 指定 LocalQueue podSets: - name: "trainer" template: spec: containers: - name: cuda resources: requests: nvidia.com/gpu: 2
-
调度决策阶段:
- Kueue 检查 LocalQueue → ClusterQueue → ResourceFlavor 的完整链路
- 根据配额、优先级和调度策略决定是否接纳工作负载
4.3 关键约束关系
-
ResourceFlavor 必须性:
- 每个 ClusterQueue 必须至少绑定一个 ResourceFlavor
- 工作负载最终调度到的节点必须满足 ResourceFlavor 的约束
-
命名空间隔离:
- LocalQueue 确保只有特定命名空间的工作负载能使用关联的 ClusterQueue
- 通过 ClusterQueue 的
namespaceSelector
二次验证
-
资源借用规则:
- 只能在相同 cohort 的 ClusterQueue 之间发生
- 借用受 borrowingLimit/lendingLimit 限制
五、典型应用场景
5.1 异构 GPU 集群管理
5.2 多租户资源共享
# 共享集群核心配置
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: shared-core
spec:
cohort: shared-pool
resourceGroups:
- coveredResources: ["cpu"]
flavors:
- name: "default"
resources:
- name: "cpu"
nominalQuota: 1000
lendingLimit: 500 # 允许借出50%资源
六、最佳实践建议
-
ResourceFlavor 设计:
- 按实际硬件差异定义(如 GPU 型号、CPU 架构)
- 通过 taints/tolerations 实现硬隔离
-
ClusterQueue 规划:
- 生产环境使用
StrictFIFO
保证公平性 - 开发环境使用
BestEffortFIFO
提高利用率 - 合理设置 borrowingLimit 防止资源饿死
- 生产环境使用
-
LocalQueue 管理:
- 按团队/项目划分 LocalQueue
- 结合 RBAC 控制访问权限
七、常见问题解答
Q:能否绕过 LocalQueue 直接使用 ClusterQueue?
A:技术上可以,但会破坏多租户隔离,不建议在生产环境这样做。
Q:ResourceFlavor 必须对应实际的节点标签吗?
A:是的,nodeLabels
必须与节点上存在的标签匹配,否则无法调度。
Q:如何监控资源借用情况?
A:通过 Kueue 的 Metrics 或检查 ClusterQueue 状态中的 flavorUsage
字段。
通过这种三层架构,Kueue 实现了灵活而强大的资源管理能力,既能满足复杂的异构环境需求,又能保持清晰的权限和配额隔离。