Skip to main content

本文详细介绍VolcanoJob核心对象的关键设计以及使用。关于Job的基础介绍,请参考Volcano基本介绍章节 Volcano介绍

Volcano JobVolcano调度系统中的核心工作负载对象,用于定义和管理复杂的分布式、批处理和高性能计算任务。与原生Kubernetes Job相比,Volcano Job提供了更丰富的功能和更灵活的调度策略,特别适合机器学习、大数据分析、科学计算等领域。

基本结构

Volcano Job的数据结构如下:

apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: distributed-training # 作业名称
spec:
minAvailable: 3 # 最小可用Pod数量,作业启动所需的最小资源数量
minSuccess: 2 # 最小成功Pod数量,任务被认为完成所需的最小成功数量
schedulerName: volcano # 指定使用volcano调度器
priorityClassName: high # 作业优先级(可选)
queue: ai-training # 所属队列
maxRetry: 5 # 最大重试次数
ttlSecondsAfterFinished: 3600 # 作业完成后保留时间(秒)
plugins: # 使用的插件
ssh: [] # SSH插件配置
env: [] # 环境变量插件配置
svc: [] # 服务插件配置
policies: # 策略配置
- event: PodEvicted # 触发事件
action: RestartJob # 对应动作
tasks: # 任务定义,一个Job可以包含多个任务
- replicas: 1 # 副本数
name: ps # 任务名称
policies: # 任务级别策略
- event: TaskCompleted # 触发事件
action: CompleteJob # 对应动作
template: # Pod模板
metadata:
labels:
role: ps
spec:
containers:
- name: tensorflow
image: tensorflow/tensorflow:2.4.0-gpu
resources:
limits:
cpu: 4
memory: 8Gi
nvidia.com/gpu: 1
- replicas: 4 # 副本数
name: worker # 任务名称
template: # Pod模板
metadata:
labels:
role: worker
spec:
containers:
- name: tensorflow
image: tensorflow/tensorflow:2.4.0-gpu
resources:
limits:
cpu: 2
memory: 4Gi
nvidia.com/gpu: 1

Job、PodGroup、Task状态

Job状态

Volcano Job是一个更高级别的抽象。

Job的状态定义如下:

// JobPhase defines the phase of the job.
type JobPhase string

const (
// Pending is the phase that job is pending in the queue, waiting for scheduling decision
Pending JobPhase = "Pending"
// Aborting is the phase that job is aborted, waiting for releasing pods
Aborting JobPhase = "Aborting"
// Aborted is the phase that job is aborted by user or error handling
Aborted JobPhase = "Aborted"
// Running is the phase that minimal available tasks of Job are running
Running JobPhase = "Running"
// Restarting is the phase that the Job is restarted, waiting for pod releasing and recreating
Restarting JobPhase = "Restarting"
// Completing is the phase that required tasks of job are completed, job starts to clean up
Completing JobPhase = "Completing"
// Completed is the phase that all tasks of Job are completed
Completed JobPhase = "Completed"
// Terminating is the phase that the Job is terminated, waiting for releasing pods
Terminating JobPhase = "Terminating"
// Terminated is the phase that the job is finished unexpected, e.g. events
Terminated JobPhase = "Terminated"
// Failed is the phase that the job is restarted failed reached the maximum number of retries.
Failed JobPhase = "Failed"
)

Job有以下几种状态:

状态说明描述
Pending等待中Job正在调度排队中或者已调度但不满足spec.minMember要求
Aborting中止中Job正在被中止,等待释放Pod
Aborted已中止Job已被中止,所有Pod已被释放
Running运行中Job中的最小可用任务正在运行
Restarting重启中Job正在重启,等待Pod释放和重新创建
Completing完成中Job的必需任务已完成,开始清理工作
Completed已完成Job的所有任务都已完成
Terminating终止中Job正在终止,等待释放Pod
Terminated已终止Job意外结束,如由于事件触发
Failed失败Job重启失败,达到最大重试次数

PodGroup状态

PodGroupVolcano中用于管理Pod集合的抽象,PodGroupownerReferences指向Job。 每个Job生成的PodGroup名称是唯一的,是一对一关系,PodGroup名称格式为{JobName}-{JobUID}

PodGroup的状态定义如下:

// PodGroupPhase is the phase of a pod group at the current time.
type PodGroupPhase string

// These are the valid phase of podGroups.
const (
// PodGroupPending means the pod group has been accepted by the system, but scheduler can not allocate
// enough resources to it.
PodGroupPending PodGroupPhase = "Pending"

// PodGroupRunning means `spec.minMember` pods of PodGroup has been in running phase.
PodGroupRunning PodGroupPhase = "Running"

// PodGroupUnknown means part of `spec.minMember` pods are running but the other part can not
// be scheduled, e.g. not enough resource; scheduler will wait for related controller to recover it.
PodGroupUnknown PodGroupPhase = "Unknown"

// PodGroupInqueue means controllers can start to create pods,
// is a new state between PodGroupPending and PodGroupRunning
PodGroupInqueue PodGroupPhase = "Inqueue"

// PodGroupCompleted means all the pods of PodGroup are completed
PodGroupCompleted PodGroupPhase = "Completed"
)

PodGroup有以下几种状态:

状态说明描述
Pending等待中PodGroup刚创建的初始状态,还未被调度器处理,此时不会创建任何Pod
Running运行中PodGroupspec.minMemberPod已处于运行状态
Unknown未知部分spec.minMemberPod正在运行,但其他部分无法调度(如资源不足)
Inqueue入队控制器可以开始创建Pod,是PendingRunning之间的新状态,处于该状态的PodGroup可能已经被创建出了部分Pod
Completed已完成PodGroup的所有Pod都已完成

Task状态

Job直接包含一个或多个Task,每个Task可以有多个Pod副本,PodownerReferences指向JobTaskVolcano中用于管理Pod集合的抽象。

Task的状态定义如下:

// TaskStatus defines the status of a task/pod.
type TaskStatus int

const (
// Pending means the task is pending in the apiserver.
Pending TaskStatus = 1 << iota

// Allocated means the scheduler assigns a host to it.
Allocated

// Pipelined means the scheduler assigns a host to wait for releasing resource.
Pipelined

// Binding means the scheduler send Bind request to apiserver.
Binding

// Bound means the task/Pod bounds to a host.
Bound

// Running means a task is running on the host.
Running

// Releasing means a task/pod is deleted.
Releasing

// Succeeded means that all containers in the pod have voluntarily terminated
// with a container exit code of 0, and the system is not going to restart any of these containers.
Succeeded

// Failed means that all containers in the pod have terminated, and at least one container has
// terminated in a failure (exited with a non-zero exit code or was stopped by the system).
Failed

// Unknown means the status of task/pod is unknown to the scheduler.
Unknown
)

Task有以下几种状态:

状态说明描述
Pending等待中Taskapiserver中等待处理
Allocated已分配调度器为Task分配了主机节点
Pipelined流水线调度器为Task分配了主机,等待释放资源
Binding绑定中调度器向apiserver发送绑定请求
Bound已绑定Task/Pod已绑定到主机节点
Running运行中Task正在主机上运行
Releasing释放中Task/Pod正在被删除
Succeeded成功Pod中所有容器都以退出码0自愿终止,系统不会重启这些容器
Failed失败Pod中所有容器都已终止,至少一个容器以非零退出码终止或被系统停止
Unknown未知Task/Pod的状态对调度器来说是未知的

Job、PodGroup、Task、Pod关系模型

  • Job ← 直接管理 → Task(定义、创建、管理Pod
  • Job ← 创建 → PodGroup(调度协调)
  • PodGroup ← 存储 → Task元信息(MinTaskMember字段)

关系模型如下:

Job (控制器层面)
├── PodGroup (调度层面) - 存储Task的调度元信息
└── Tasks (逻辑分组) - Job直接管理
└── Pods (实际资源) - 由Task创建

tensorflow-training为例:

Job (tensorflow-training)
├── PodGroup (tensorflow-training-abc123def456) [1:1关系]
│ ├── minAvailable: 4
│ ├── minTaskMember: {ps: 2, worker: 3} ← Task信息存储在这里
│ ├── queue: default
│ └── status: Running
├── Task: ps (replicas: 2) [Job直接管理]
│ ├── Pod: tensorflow-training-ps-0
│ └── Pod: tensorflow-training-ps-1
└── Task: worker (replicas: 3) [Job直接管理]
├── Pod: tensorflow-training-worker-0
├── Pod: tensorflow-training-worker-1
└── Pod: tensorflow-training-worker-2

批量调度

minAvailable属性是Volcano Job中的核心功能之一,用于实现"批量调度"或"整体调度"机制。这一机制在分布式计算、机器学习等领域特别重要,因为这些应用通常需要多个Pod同时启动才能正常工作。

工作原理

  1. 调度保证

    • 当设置minAvailable=N时,Volcano调度器会确保至少有NPod同时被调度
    • 如果集群资源不足以满足这一要求,所有Pod将保持在Pending状态,而不是部分调度
  2. PodGroup集成

    • Volcano会为每个Job创建一个PodGroup对象
    • minAvailable值会设置到PodGroup中,用于指导调度决策
  3. 资源等待机制

    • 当资源不足时,作业将进入等待状态
    • 一旦有足够资源可以满足minAvailable要求,作业将被调度

应用场景示例

  1. 分布式机器学习

    apiVersion: batch.volcano.sh/v1alpha1
    kind: Job
    metadata:
    name: tf-training
    spec:
    minAvailable: 3 # 1个PS + 2个Worker最小要求
    tasks:
    - replicas: 1
    name: ps
    - replicas: 4
    name: worker
  2. MPI并行计算

    apiVersion: batch.volcano.sh/v1alpha1
    kind: Job
    metadata:
    name: mpi-job
    spec:
    minAvailable: 5 # 1个Launcher + 4个Worker
    tasks:
    - replicas: 1
    name: launcher
    - replicas: 4
    name: worker

与其他属性的配合

  • 与minSuccess的区别minAvailable关注的是调度启动时的最小要求,而minSuccess关注的是任务成功所需的最小成功Pod数量。这里的成功是指Pod处于Succeeded状态(即Pod内所有容器都成功终止,退出码为0

  • 与policies的结合:可以配合PodFailed策略,当Pod失败导致可用Pod数量小于minAvailable时触发重启或终止操作

重试策略

Volcano Job提供了灵活的重试机制,允许用户配置在作业失败时的处理方式。这一机制对于提高分布式任务的可靠性和容错能力至关重要。

重试控制参数

  1. maxRetry

    • 定义作业失败时的最大重试次数
    • 当作业失败次数超过该值时,作业将被标记为最终失败状态
    • 默认值为3
  2. policies

    • 通过eventaction对定义特定事件发生时的处理方式
    • 可以在作业级别或任务级别配置

支持的事件类型(event)

Volcano支持以下事件类型来触发重试策略:

事件描述备注
PodFailedPod失败时触发适用于容器崩溃、内存溢出等异常情况
PodEvictedPod被驱逐时触发适用于资源抢占、节点维护等情况
PodPendingPod处于等待状态时触发通常与timeout参数配合使用,适用于检测调度卡住的情况
PodRunningPod进入运行状态时触发适用于监控Pod状态变化,可用于取消其他延迟操作
JobUnknown (Unknown)当作业状态未知时触发适用于处理异常情况,如部分Pod无法调度而其他已运行
TaskCompleted当任务中所有Pod成功完成时触发适用于一个任务完成后触发作业级别的动作
TaskFailed当任务意外失败时触发适用于检测任务级别的失败
OutOfSyncPodJob状态更新时触发系统内部事件,用于处理添加/更新/删除操作
CommandIssued当用户发出命令时触发系统内部事件,用于响应外部命令
JobUpdatedJob被更新时触发系统内部事件,主要用于扩容/缩容操作
* (AnyEvent)匹配任何事件通配符,可用于捕获所有类型的事件

支持的动作类型(action)

Volcano支持以下动作类型来处理重试:

动作描述备注
AbortJob中止作业,但不清理资源作业可以恢复
RestartJob重启整个作业所有Pod将被终止并重新创建
RestartTask只重启特定任务只能用于任务级别的策略
RestartPod只重启特定的Pod提供更精细的重启控制
TerminateJob终止作业并清理所有资源作业将无法恢复
CompleteJob将作业标记为完成适用于关键任务完成时结束整个作业

重试策略配置示例

  1. 基本重试配置

    apiVersion: batch.volcano.sh/v1alpha1
    kind: Job
    metadata:
    name: job-retry-example
    spec:
    minAvailable: 3
    maxRetry: 5 # 最多重试五次
    policies:
    - event: PodFailed # 当Pod失败时
    action: RestartJob # 重启整个作业
  2. 任务级别重试策略

    apiVersion: batch.volcano.sh/v1alpha1
    kind: Job
    metadata:
    name: task-retry-example
    spec:
    minAvailable: 3
    maxRetry: 3
    tasks:
    - replicas: 1
    name: master
    policies:
    - event: PodFailed # 当master失败时
    action: RestartJob # 重启整个作业
    - replicas: 3
    name: worker
    policies:
    - event: PodFailed # 当worker失败时
    action: RestartTask # 只重启该任务
  3. 带超时的重试策略

    apiVersion: batch.volcano.sh/v1alpha1
    kind: Job
    metadata:
    name: timeout-retry-example
    spec:
    minAvailable: 3
    policies:
    - event: PodPending # 当Pod长时间处于等待状态
    action: AbortJob # 中止作业
    timeout: 1h # 超过1小时后触发

重试策略最佳实践

  1. 区分关键任务和非关键任务

    • 对于关键任务(如主节点)的失败,应触发RestartJob
    • 对于非关键任务(如工作节点)的失败,可以使用RestartTaskRestartPod
  2. 考虑超时设置

    • 对于可能长时间卡住的情况,添加timeout参数
    • 超时时间应根据任务的复杂度和资源需求合理设置
  3. 限制最大重试次数

    • maxRetry值不应设置过大,避免资源浪费
    • 对于大型作业,建议设置为3-5
  4. 与队列策略的协调

    • 考虑队列的reclaimable属性对重试策略的影响
    • 如果作业在可回收的队列中,可能需要更强大的重试策略

与其他特性的结合

  • 与minAvailable的结合:当Pod失败导致可用Pod数量小于minAvailable时,可以触发重试

  • 与minSuccess的结合:当成功的Pod数量无法达到minSuccess时,可以触发重试

  • 与插件的结合:重试时会重新应用插件配置,确保环境变量、SSH密钥等正确重新配置

任务依赖关系

Volcano Job支持在不同任务之间定义依赖关系,这一功能在复杂的工作流程中非常有用,如数据处理管道、模型训练和评估流程等。

依赖关系配置

Volcano Job使用dependsOn字段定义任务之间的依赖关系:

tasks:
- name: task-A
replicas: 1
template:
# ...
- name: task-B
replicas: 2
dependsOn:
name: ["task-A"] # task-B依赖于task-A
template:
# ...
- name: task-C
replicas: 3
dependsOn:
name: ["task-A", "task-B"] # task-C依赖于task-A和task-B
template:
# ...

工作原理

  1. 依赖解析

    • Volcano Job控制器在创建作业时解析任务之间的依赖关系
    • 构建一个有向无环图(DAG)来表示任务执行顺序
  2. 执行顺序

    • 只有当所有依赖的任务完成后,一个任务才会启动
    • 没有依赖关系的任务可以并行启动
  3. 状态传递

    • 当一个任务失败时,依赖于它的任务不会启动
    • 这确保了工作流程的完整性

应用场景

  1. 数据处理管道
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: data-pipeline
spec:
minAvailable: 1
tasks:
- name: data-collection
replicas: 1
template:
# ...
- name: data-preprocessing
replicas: 3
dependsOn:
name: ["data-collection"]
template:
# ...
- name: model-training
replicas: 2
dependsOn:
name: ["data-preprocessing"]
template:
# ...
  1. 复杂的模型训练流程
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: ml-workflow
spec:
minAvailable: 1
tasks:
- name: data-preparation
replicas: 1
template:
# ...
- name: feature-extraction
replicas: 2
dependsOn:
name: ["data-preparation"]
template:
# ...
- name: model-training
replicas: 1
dependsOn:
name: ["feature-extraction"]
template:
# ...
- name: model-evaluation
replicas: 1
dependsOn:
name: ["model-training"]
template:
# ...
- name: model-deployment
replicas: 1
dependsOn:
name: ["model-evaluation"]
template:
# ...

注意事项与最佳实践

  1. 避免循环依赖

    • 不能创建循环依赖,如A依赖B,B依赖C,C依赖A
    • 这将导致作业创建失败
  2. 考虑资源需求

    • 当使用依赖关系时,要考虑minAvailable的设置
    • 如果同时运行的任务很少,可以将minAvailable设置得较小
  3. 与重试策略的结合

    • 当使用依赖关系时,要为关键任务配置适当的重试策略
    • 关键任务的失败可能会导致整个工作流程卡住
  4. 使用有意义的任务名称

    • 任务名称应清晰地反映其功能和在工作流程中的位置
    • 这有助于理解和维护复杂的依赖关系