BroadcastJob

149 阅读2分钟

阅读本节前请了解 BroadcastJob 的使用和功能

系列教程: Openkruise

doc :openkruise.io/zh/docs/use…

关键词: each nodo one job

Reconcile

预处理

  1. 打 lables( addLabelToPodTemplate(job) ) broadcastjob-name = job.Name broadcastjob-controller-uid = job.UID

  2. 通过函数 IsJobFinished(job)pastTTLDeadline(job) 检测 job 是否超时,相关字段: TTLSecondsAfterFinished

  3. 获取所对应的 pods 以及 node,生成一个 (node, pod) map existingNodeToPodMap, 该 map 一定是一对一关系

  4. 根据 pod 的 Status.Phase 对这些 pods 进行分类,分别放在三个数组里:activePods, failedPods, succeededPods := filterPods(job.Spec.FailurePolicy.RestartLimit, pods)

  5. 将 nodes 也分类 desiredNodes, restNodesToRunPod, podsToDelete := getNodesToRunPod(nodes, job, existingNodeToPodMap) desiredNodes: 目标态,即需要在哪些 nodes 上运行 pod restNodesToRunPod: 应该有 running pod 但还没有的 podsToDelete: pod 和 node 不匹配,但 pod 还挂在上面的

    1. 通过函数 checkNodeFitness(pod *corev1.Pod, node *corev1.Node)检测包括但不限于 名字/affinity/taint 等是否匹配
    2. 对于未存在的 pod,通过先 mock 再验证,最后放入 restNodesToRunPod 来实现
    3. mockPod := NewMockPod(job, node.Name)
      canFit, err = checkNodeFitness(mockPod, &node)
      

状态流转

通过预处理我们知道了各个pod应有的分布和当前的状态,那么接下来就需要根据当前的状态和策略来分叉

失败处理

必须是 jobFailed 的时候进行,进入该流程有以下两个途径

  1. failedPods > 0 && completionPolicy == FailFast

  2. jobFailed, failureReason, failureMessage = isJobFailed(job, pods) 第一个返回值为 true

    1. 该函数对于 Never 失败策略永远返回 (false, "", "")
    2. 如果 job 执行时间超过 ActiveDeadlineSeconds,也会被标记为失败

失败处理流程主要与失败策略(FailurePolicyType)字段有关, 该字段有三个可选值

  1. Continue: 什么都不做继续流程

  2. FailFast: 立即失败

    1. 删除 active pods: failed, active, err = r.deleteJobPods(job, activePods, failed, active),这里删除失败的 pod 数也会被记入 failed(int)
    2. Job 状态流转为 failed
    3. 通过 finishJob(job, appsv1alpha1.JobFailed, failureMessage)来获取 job 的结束时间,如果标记了 TTLSecondsAfterFinished,则返回该值 + 1 second,否则返回 0
  3. Pause: job 状态流转为 paused,且标记 job.Spec.Paused = true

调整 pod 分布

根据 restNodesToRunPodpodsToDelete 来使得 pod 分布在正确的 node 上

  1. 首先删除 podsToDelete 中的 pod: failed, active, err = r.deleteJobPods(job, podsToDelete, failed, active)

  2. 尝试创建 pod: active, err = r.reconcilePods(job, restNodesToRunPod, active, desired)

    1. 创建受参数 Parallelism 限制( if exist ),如果当前 active pod > parallelism, 则跳过;否则尝试将尝试创建 min(parallelism-active, rest) 个 pod

      1. 这里创建仍然采用慢启动算法,即最开始 1 个,然后二倍增长, 每一个批次起多个协程来创建
      2. for batchSize := integer.Int32Min(diff, kubecontroller.SlowStartInitialBatchSize); diff > 0; batchSize = integer.Int32Min(2*batchSize, diff) {......}
        

Job 结束条件判断

尝试结束 job isJobComplete(job, desiredNodes)

  1. 如果完成策略是 Never,则 job 用不结束
  2. 如果 desiredNodes 数组是空的,则 job 会 pending
  3. 如果每个 pod in desiredNodes 都 active 了,则顺利完成