Kubernetes 批处理调度框架 Kueue 核心资源与高级特性深度解析
一、核心资源对象体系
1. ResourceFlavor(资源规格)
定义:描述集群中可用的异构资源类型,通过标签/污点机制与物理节点建立映射关系
核心功能:
- 资源类型标记:区分不同特性的计算资源(如 CPU/GPU、按需/Spot 实例)
- 调度约束管理:通过污点机制控制资源使用权限
- 动态资源适配:自动注入节点选择器到工作负载
关键配置属性:
apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
name: "gpu-a100"
spec:
nodeLabels: # 节点标识标签
accelerator: nvidia-a100
nodeTaints: # 资源访问控制
- key: gpu-tier
value: premium
effect: NoSchedule
tolerations: # 自动注入的污点容忍
- key: "gpu-tier"
operator: "Exists"
effect: "NoSchedule"
版本兼容性:
- Kubernetes ≥1.23 支持标签动态注入
- v1beta1 API 版本需配合 Kueue 0.6.0+ 使用
- 污点容忍自动注入要求启用 MutatingWebhook
校验机制:
func ValidateWorkload(workload *Workload) error {
for _, flavor := range GetClusterFlavors() {
if !CheckTolerations(workload, flavor.Tolerations) {
return ErrIncompatibleTaint
}
if !CheckNodeAffinity(workload, flavor.NodeLabels) {
return ErrNodeSelectorMismatch
}
}
return nil
}
2. ClusterQueue(集群队列)
资源池化模型:定义跨命名空间的全局资源配额池,支持多级资源借用策略
架构设计:
ClusterQueue 资源模型
+-----------------------+
| ResourceGroup |
| - coveredResources |
| +-------------------+ |
| | Flavor | |
| | - nominalQuota | | -> 静态配额
| | - borrowingLimit | | -> 跨队列借用上限
| | - lendingLimit | | -> 资源出借上限(Alpha)
+-----------------------+
高级配置参数:
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: "ai-training"
spec:
namespaceSelector: # 命名空间过滤
matchLabels:
env: production
queueingStrategy: "BestEffortFIFO" # 队列策略
cohort: "gpu-cluster" # 资源联盟组
preemption: # 抢占策略三要素
reclaimWithinCohort:
policy: LowerPriority
borrowWithinCohort:
policy: Any
maxPriorityThreshold: 200
withinClusterQueue: LowerOrNewerEqualPriority
flavorFungibility: # 规格降级策略
whenCanBorrow: TryNextFlavor
whenCanPreempt: Preempt
stopPolicy: HoldAndDrain # 队列停止策略
队列策略对比:
| 策略类型 | 调度特点 | 适用场景 |
|---|---|---|
| StrictFIFO | 严格顺序执行,可能产生队头阻塞 | 作业依赖性强,需顺序执行 |
| BestEffortFIFO | 跳过不可调度作业,资源利用率高 | 异构作业混合场景 |
资源借用规则:
- 借用总量 ≤ nominalQuota + borrowingLimit
- 仅限同 Cohort 内 ClusterQueue 间借用
- 单作业只能借用单一 Flavor 资源
- 借入方优先级高于贷出方时可触发抢占
3. LocalQueue(本地队列)
租户隔离机制:命名空间维度的虚拟队列,实现资源配额二次分配
配置示例:
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
namespace: ml-team-a
name: high-prio-queue
spec:
clusterQueue: "ai-training" # 绑定集群队列
priority:
className: "critical-job" # 自定义优先级类
value: 1000
运行特征:
- 单 LocalQueue 只能绑定一个 ClusterQueue
- 支持跨命名空间资源共享(需 ClusterQueue 开放访问)
- 优先级可覆盖 ClusterQueue 全局设置
4. Workload(工作负载)
单元化设计:Kubernetes 原生 Job 的增强抽象,支持多框架集成
优先级继承模型:
多框架支持:
apiVersion: kubeflow.org/v1
kind: TFJob
metadata:
annotations:
kueue.x-k8s.io/queue-name: "ml-queue"
spec:
tfReplicaSpecs:
Worker:
replicas: 4
template:
spec:
containers:
- name: tensorflow
resources:
requests:
cpu: 8
memory: 32Gi
nvidia.com/gpu: 1
状态流转机制:
Workload 生命周期
Created → Pending → Admitted → Running
→ Inadmissible (资源不足)
→ Preempted (被抢占)
→ Evicted (手动驱逐)
二、高级调度策略解析
1. 多维度抢占机制
三级抢占策略:
-
队列内抢占(withinClusterQueue)
- 策略类型:LowerPriority / LowerOrNewerEqualPriority
- 触发条件:新作业优先级 ≥ 运行中作业优先级 + 阈值
-
Cohort 内回收(reclaimWithinCohort)
- 回收模式:
func ShouldReclaim(resource *Resource, borrower *Workload) bool { if currentUsage > nominalQuota && borrower.Priority < current.Priority { return true } return false }
- 回收模式:
-
跨队列抢占(borrowWithinCohort)
- 需开启 reclaimWithinCohort
- 水位线控制:maxPriorityThreshold
抢占执行流程:
- 检查目标作业的 PreemptionPolicy
- 计算可释放资源量
- 按优先级逆序选择牺牲者
- 驱逐选定 Pod 并回收资源
- 重试目标作业调度
2. 资源弹性伸缩
与 Cluster Autoscaler 集成:
弹性扩缩流程:
1. Kueue 检测到待调度作业
2. 计算所需节点类型及数量
3. 通过 Annotation 标记未调度 Pod
4. Cluster Autoscaler 识别需求并扩容
5. 节点就绪后触发 Pod 调度
弹性配置最佳实践:
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
spec:
resourceGroups:
- flavors:
- name: spot
resources:
- name: "cpu"
nominalQuota: 100
borrowingLimit: 500 # 允许突发借用
- name: ondemand
resources:
- name: "cpu"
nominalQuota: 200
lendingLimit: 100 # 控制资源外借量
3. 拓扑感知调度
NUMA 亲和性优化:
apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
name: numa-node-0
spec:
nodeLabels:
topology.kubernetes.io/zone: zone-a
numa-node: "0"
---
apiVersion: batch/v1
kind: Job
spec:
template:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: numa-node
operator: In
values: ["0"]
调度优化效果:
- 减少跨 NUMA 内存访问延迟
- 提升 GPU 间 NVLINK 带宽利用率
- 降低网络层跳跃(Hops)
三、生产环境实践指南
1. 多租户配额规划
配额分配矩阵:
| 租户团队 | GPU Quota | CPU Quota | 优先级 | 资源类型偏好 |
|---|---|---|---|---|
| ML-Prod | 40 A100 | 400 Cores | 1000 | OnDemand (80%) |
| Research | 20 V100 | 200 Cores | 500 | Spot (70%) |
| CI/CD | 0 | 100 Cores | 300 | Preemptible (90%) |
对应 ClusterQueue 配置:
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: ml-prod-pool
spec:
resourceGroups:
- coveredResources: ["nvidia.com/gpu", "cpu"]
flavors:
- name: a100-ondemand
resources:
- name: "nvidia.com/gpu"
nominalQuota: 32 # 80% of 40
borrowingLimit: 8
- name: "cpu"
nominalQuota: 320
- name: a100-spot
resources:
- name: "nvidia.com/gpu"
nominalQuota: 8
2. 监控与可观测性
关键 Prometheus 指标:
kueue_clusterqueue_usage{resource="cpu",flavor="spot"} 750
kueue_clusterqueue_borrowing{resource="gpu"} 12
kueue_workload_preemption_count{clusterqueue="ml-prod"} 5
kueue_scheduling_delay_seconds{quantile="0.99"} 12.7
Grafana 看板配置要点:
- 队列深度趋势图
- 资源借用率环形图
- 调度延迟热力图
- 抢占事件流监控
3. 灾备与优雅降级
多集群容灾方案:
MultiKueue 架构:
[Cluster A] ←→ [Central Kueue] ←→ [Cluster B]
↑
[Backup Cluster]
降级策略配置:
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
spec:
stopPolicy: Hold # 停止接受新作业但不驱逐运行中任务
flavorFungibility:
whenCanPreempt: TryNextFlavor # 优先尝试降级而非抢占
四、简单使用实例
- 定义 ResourceFlavor:
- 首先,你需要定义两个 ResourceFlavor 对象,每个对象代表一种类型的节点组。
对于按需节点组(instance-type=ondemand),你将创建一个 ResourceFlavor,它具有适当的标签,例如 ondemand=true,并且指定它能够提供的最大核心数为 1000。 - 对于即用节点组(instance-type=spot),你将创建另一个 ResourceFlavor,它具有 spot=true 标签,并且指定它能够提供的最大核心数为 2000。
- 首先,你需要定义两个 ResourceFlavor 对象,每个对象代表一种类型的节点组。
- 设置 ClusterQueue:
- 接下来,你将创建一个或多个 ClusterQueue 对象,为不同的作业类型或租户设置资源配额。
- 在 ClusterQueue 中,你可以为每个 ResourceFlavor 设置配额限制。例如,你可以为按需节点设置 1000 核心的配额,为即用节点设置 2000 核心的配额。
- 配置 LocalQueue:
- 对于每个租户或作业类型,你可以创建 LocalQueue 对象,这些对象指向相应的 ClusterQueue。
- 在 LocalQueue 中,你可以设置作业的调度偏好,例如,某些作业可能需要容忍即用节点,而其他作业则不能。
- 管理作业调度:
- 当作业提交时,Kueue 将根据 LocalQueue 中的设置和 ClusterQueue 中的配额来调度作业。
- 如果作业需要在即用节点上运行,Kueue 将检查作业的容忍度和即用节点的可用性,然后根据 ResourceFlavor 的定义和 ClusterQueue 的配额来调度作业。
- 监控和调整:
- 作为管理员,你需要监控作业的执行情况和资源的使用情况。
- 根据作业的执行情况和资源的实际使用情况,你可能需要调整 ResourceFlavor 的定义或 ClusterQueue 的配额设置,以优化成本和资源利用率。
ResourceFlavor
---
apiVersion: kueue.x-k8s.io/v1alpha2
kind: ResourceFlavor
metadata:
name: ondemand
labels:
instance-type: ondemand
---
apiVersion: kueue.x-k8s.io/v1alpha2
kind: ResourceFlavor
metadata:
name: spot
labels:
instance-type: spot
taints:
- effect: NoSchedule
key: spot
value: "true"
ClusterQueue
apiVersion: kueue.x-k8s.io/v1alpha2
kind: ClusterQueue
metadata:
name: research-pool
spec:
namespaceSelector: {}
resources:
- name: "cpu"
flavors:
- name: ondemand
quota:
min: 1000
- name: spot
quota:
min: 2000
LocalQueue
对于每个命名空间,定义一个指向上述 ClusterQueue 的 LocalQueue:
apiVersion: kueue.x-k8s.io/v1alpha2
kind: LocalQueue
metadata:
name: training
namespace: team-ml
spec:
clusterQueue: research-pool
Job
要提交作业,需要创建一个 Job 并设置 kueue.x-k8s.io/queue-name 注解,如下所示:
apiVersion: batch/v1
kind: Job
metadata:
generateName: sample-job-
annotations:
kueue.x-k8s.io/queue-name: training
spec:
parallelism: 3
completions: 3
template:
spec:
tolerations:
- key: spot
operator: "Exists"
effect: "NoSchedule"
containers:
- name: example-batch-workload
image: registry.example/batch/calculate-pi:3.14
args: ["30s"]
resources:
requests:
cpu: 1
restartPolicy: Never
2613

被折叠的 条评论
为什么被折叠?



