SkyPilot 优先级调度与抢占实战:利用 Kubernetes PriorityClass 实现高优任务抢占
2026/9/16 21:14:41 网站建设 项目流程

SkyPilot 优先级调度与抢占实战:利用 Kubernetes PriorityClass 实现高优任务抢占

【免费下载链接】skypilotThe AI Compute Platform for frontier teams. SkyPilot turns fragmented AI compute into one AI supercomputer, so frontier AI teams build custom intelligence faster.项目地址: https://gitcode.com/GitHub_Trending/sk/skypilot

SkyPilot 支持基于优先级的调度(priority-based scheduling)、抢占(preemption)与重新排队(re-queuing)。当 Kubernetes 集群资源不足时,高优先级任务可以抢占低优先级任务的 Pod,被抢占的任务会在资源释放后由 SkyPilot 自动恢复运行。本文将基于 kubernetes-priorities.rst 的核心流程,结合仓库源码深入讲解 PriorityClass 的创建、SkyPilot 任务优先级配置、抢占与恢复机制,以及需要注意的限制。

注意:优先级与抢占功能仅支持 Kubernetes基础设施,不适用于公有云 VM 等环境。

一、整体思路:三步启用优先级调度

要在 SkyPilot 中启用基于优先级的调度,只需完成三个步骤:

  1. 在 Kubernetes 集群中创建 PriorityClass(优先级类);
  2. 在 SkyPilot 任务的 YAML 中,通过config.kubernetes.pod_config.spec.priorityClassName字段为任务指定优先级类;
  3. 使用sky jobs launch将任务作为 managed job 启动。

完成上述配置后,当资源受限时,高优先级任务将抢占低优先级任务的资源,保证关键作业优先运行。下面以high-prioritylow-priority两个优先级类为例,给出完整可运行的示例。

二、Step 1:创建 Kubernetes PriorityClass

在集群中创建两个 PriorityClass。Kubernetes 原生的 PriorityClass 定义在scheduling.k8s.io/v1API 组中,核心字段包括:

  • value:优先级数值,数值越大优先级越高(取值范围 -2^31 到 10^9);
  • globalDefault:是否作为集群默认优先级类,整个集群中最多只能有一个为true
  • description:可读性说明文本;
  • preemptionPolicy(可选):PreemptLowerPriority(默认,允许抢占低优先级 Pod)或Never(禁止抢占)。

以下priorities.yaml创建两个优先级类:high-priority(value 200)用于关键任务,low-priority(value 100)作为全局默认类,用于后台任务:

# priorities.yaml apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: high-priority value: 200 globalDefault: false description: "High priority class for critical jobs" --- apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: low-priority value: 100 globalDefault: true description: "Low priority class for background jobs"

更高的value意味着更高的优先级。你可以按需创建任意数量的优先级类,例如为不同业务线或不同团队设置不同档位。

将优先级类应用到集群:

$ kubectl apply -f priorities.yaml

三、Step 2:在 SkyPilot 任务中设置优先级

SkyPilot 任务通过顶层config.kubernetes.pod_config字段将任意 Pod 配置注入集群 Pod。在 YAML 中写入spec.priorityClassName即可为该任务指定优先级类。下面使用两个简单的计数任务演示:high-priority-job.yaml每秒打印一次计数(共 1000 次),并绑定high-priority类:

# high-priority-job.yaml resources: infra: k8s cpus: 4 run: | python -c ' import time for i in range(1000): print(f"High priority counter: {i}") time.sleep(1) ' config: kubernetes: pod_config: spec: priorityClassName: high-priority

对应的低优先级任务low-priority-job.yaml结构完全一致,仅将priorityClassName改为low-priority

# low-priority-job.yaml resources: infra: k8s cpus: 4 run: | python -c ' import time for i in range(1000): print(f"Low priority counter: {i}") time.sleep(1) ' config: kubernetes: pod_config: spec: priorityClassName: low-priority

Tip(观察抢占行为的关键):请将resources.cpus设置为“一个任务运行后,集群就没有剩余 CPU 留给另一个任务”的数值。你可以用kubectl get nodes查看集群的 CPU 总量,据此确定该值。

关于 pod_config 的注入机制

config.kubernetes.pod_config不仅能设置优先级类,还能注入imagePullSecretstolerationshostNetwork等任意 Kubernetes Pod 字段。在 sky/provision/kubernetes/utils.py 的resolve_effective_pod_config中,SkyPilot 会从全局配置(~/.sky/config.yaml)与任务级配置中合并出“有效的 pod_config”;随后 combine_pod_config_fields 将其合并进渲染后的 Ray 集群 YAML——合并语义为“新字段追加、已有字段更新,嵌套对象递归合并、列表追加”。

配置校验方面,sky/provision/kubernetes/utils.py 中的check_pod_config会调用PodValidator.validate验证 pod_config 的合法性;而在 sky/utils/schemas.py 的配置模式中,pod_config允许任意键(注释明确说明“Allow arbitrary keys since validating pod spec is hard”),因此你可以放心写入任意 Kubernetes Pod spec 字段。最终,渲染模板 sky/templates/kubernetes-ray.yml.j2 中还会把优先级类记录为skypilot-priority-class注解,供后续调度与观测使用。

四、Step 3:以 managed job 方式启动并观察抢占

使用sky jobs launch将任务作为 managed job 启动。先启动低优先级任务

$ sky jobs launch low-priority-job.yaml

随后启动高优先级任务:

$ sky jobs launch high-priority-job.yaml

sky jobs queue查看任务状态,可以看到高优先级任务立即开始运行,低优先级任务被抢占:

$ sky jobs queue Fetching managed job statuses... Managed jobs In progress tasks: 1 RECOVERING, 1 RUNNING ID NAME RESOURCES SUBMITTED TOT. DURATION #RECOVERIES STATUS 2 sky-0232-romilb 1x[CPU:4] 5 mins ago 5m 35s 0 RUNNING 1 sky-0d6f-romilb 1x[CPU:4] 7 mins ago 7m 13s 1 RECOVERING

此时低优先级任务进入RECOVERING状态,SkyPilot 会在资源可用时自动将其重启。待高优先级任务运行完成后,低优先级任务自动恢复运行:

$ sky jobs queue Fetching managed job statuses... Managed jobs No in-progress managed jobs. ID NAME RESOURCES SUBMITTED TOT. DURATION #RECOVERIES STATUS 2 sky-0232-romilb 1x[CPU:4] 23 mins ago 17m 22s 0 SUCCEEDED 1 sky-0d6f-romilb 1x[CPU:4] 25 mins ago 23m 47s 1 RUNNING

从输出可以看到,高优先级任务(ID 2)以 0 次恢复直接SUCCEEDED,而低优先级任务(ID 1)经历 1 次恢复后继续运行,#RECOVERIES字段记录了恢复次数。

背后的恢复机制

managed job 的抢占恢复由 SkyPilot 的任务控制器负责。在 sky/jobs/controller.py 中,控制器通过繁忙轮询监控集群状态,当检测到 Pod 被抢占/驱逐时触发恢复逻辑,并通过 sky/jobs/recovery_strategy.py 中的StrategyExecutor执行清理与重放(#RECOVERIES次数即由此记录)。任务进入RECOVERING状态后,控制器会在资源可用时重新调度该任务。

五、优先级与抢占的工作原理

  • 抢占行为:当集群没有足够资源容纳所有任务时,高优先级任务会抢占低优先级任务——即终止低优先级任务的 Pod,为高优先级任务腾出空间。该行为由 Kubernetes 调度器基于 Pod 的priorityClassName对应数值判定。
  • 自动恢复:被抢占的任务不会丢失,SkyPilot 会在资源重新可用时自动重新调度。建议在代码中启用 Checkpointing and Recovery(断点续训与恢复)以减少重复工作。
  • 同级优先级:优先级相同的任务遵循 SkyPilot 的 默认排队调度行为。
  • 非托管集群:优先级类同样可以应用于非托管(unmanaged)SkyPilot 集群,但被抢占后不会自动重启

六、限制与注意事项

  1. 作用域:优先级设置仅在单个 Kubernetes 集群内部生效,跨集群(如多 Kubernetes 上下文)之间不存在优先级比较。
  2. 抢占范围:抢占行为取决于集群本身的配置,高优先级 Pod可能抢占集群中任何低优先级的 Pod——包括并非由 SkyPilot 管理的其他工作负载。请在共享集群中谨慎设置preemptionPolicy与优先级数值,避免影响他人任务。
  3. 资源估算:优先级抢占的前提是 kube-scheduler 能正确感知资源余量。请确保集群节点资源可被准确上报(例如通过 Kubernetes 部署配置 正确设置节点可分配资源),否则调度器可能无法触发预期的抢占。

七、进一步阅读

  • Managed Jobs 使用指南:managed job 的完整语义、排队与自动重启行为;
  • Checkpointing and Recovery:如何在任务代码中实现断点续训,减少抢占带来的重复计算;
  • SkyPilot 配置参考:config.kubernetes命名空间的完整配置项,包括pod_config的全局/任务级合并规则;
  • Kubernetes 官方文档:Pod Priority and Preemption:PriorityClass 与抢占调度器的底层原理(Kubernetes 原生概念)。

通过优先级类 + managed job 的组合,SkyPilot 团队可以在共享的 Kubernetes 集群上实现“关键任务优先、后台任务让路、被抢占后自动恢复”的混合负载调度,让有限的集群资源始终服务于最有价值的作业。

【免费下载链接】skypilotThe AI Compute Platform for frontier teams. SkyPilot turns fragmented AI compute into one AI supercomputer, so frontier AI teams build custom intelligence faster.项目地址: https://gitcode.com/GitHub_Trending/sk/skypilot

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询