使用命令行等待 kubernetes 作业在 failure/success 上完成

Wait for kubernetes job to complete on either failure/success using command line

等待 kubernetes 作业完成的最佳方法是什么?我注意到很多使用建议:

kubectl wait --for=condition=complete job/myjob

但我认为只有在工作成功时才​​有效。如果失败,我必须做类似的事情:

kubectl wait --for=condition=failure job/myjob

有没有办法使用 wait 来等待这两个条件?如果没有,等待工作成功或失败的最佳方式是什么?

kubectl wait --for=condition=<condition name 正在等待特定条件,所以 afaik 目前无法指定多个条件。

我的解决方法是使用 oc get --wait,如果目标资源已更新,--wait 将关闭命令。我将使用 oc get --wait 监视作业的 status 部分,直到 status 更新。 status 部分的更新意味着作业已完成并具有某些状态条件。

如果作业成功完成,则 status.conditions.type 会立即更新为 Complete。但是,如果作业失败,那么无论 restartPolicyOnFailure 还是 Never,作业 pod 都会自动重启。但是我们可以认为作业是 Failed 状态,如果在第一次更新后没有更新为 Complete

看我的测试证据如下

  • 用于测试成功完成的作业 yaml
    # vim job.yml
    apiVersion: batch/v1
    kind: Job
    metadata:
      name: pi
    spec:
      parallelism: 1
      completions: 1
      template:
        metadata:
          name: pi
        spec:
          containers:
          - name: pi
            image: perl
            command: ["perl",  "-wle", "exit 0"]
          restartPolicy: Never
  • 如果它成功完成作业,它将显示 Complete
    # oc create -f job.yml &&
      oc get job/pi -o=jsonpath='{.status}' -w &&
      oc get job/pi -o=jsonpath='{.status.conditions[*].type}' | grep -i -E 'failed|complete' || echo "Failed" 

    job.batch/pi created
    map[startTime:2019-03-09T12:30:16Z active:1]Complete
  • 用于测试的作业 yaml 未能完成
    # vim job.yml
    apiVersion: batch/v1
    kind: Job
    metadata:
      name: pi
    spec:
      parallelism: 1
      completions: 1
      template:
        metadata:
          name: pi
        spec:
          containers:
          - name: pi
            image: perl
            command: ["perl",  "-wle", "exit 1"]
          restartPolicy: Never
  • 如果第一个作业更新不是 Complete,它将显示 Failed。测试是否在删除现有作业资源后。
    # oc delete job pi
    job.batch "pi" deleted

    # oc create -f job.yml &&
      oc get job/pi -o=jsonpath='{.status}' -w &&
      oc get job/pi -o=jsonpath='{.status.conditions[*].type}' | grep -i -E 'failed|complete' || echo "Failed" 

    job.batch/pi created
    map[active:1 startTime:2019-03-09T12:31:05Z]Failed

希望对你有所帮助。 :)

运行 将第一个等待条件作为子进程并捕获其PID。如果满足条件,此进程将退出,退出代码为 0。

kubectl wait --for=condition=complete job/myjob &
completion_pid=$!

对失败等待条件做同样的事情。这里的技巧是添加 && exit 1 以便子进程 returns 作业失败时的非零退出代码。

kubectl wait --for=condition=failed job/myjob && exit 1 &
failure_pid=$! 

然后使用Bash内置函数wait -n $PID1 $PID2等待其中一个条件成功。该命令将捕获第一个退出的进程的退出代码:

wait -n $completion_pid $failure_pid

最后,您可以检查 wait -n 的实际退出代码以查看作业是否失败:

exit_code=$?

if (( $exit_code == 0 )); then
  echo "Job completed"
else
  echo "Job failed with exit code ${exit_code}, exiting..."
fi

exit $exit_code

完整示例:

# wait for completion as background process - capture PID
kubectl wait --for=condition=complete job/myjob &
completion_pid=$!

# wait for failure as background process - capture PID
kubectl wait --for=condition=failed job/myjob && exit 1 &
failure_pid=$! 

# capture exit code of the first subprocess to exit
wait -n $completion_pid $failure_pid

# store exit code in variable
exit_code=$?

if (( $exit_code == 0 )); then
  echo "Job completed"
else
  echo "Job failed with exit code ${exit_code}, exiting..."
fi

exit $exit_code

您可以利用 --timeout=0 时的行为。

在这种情况下,命令行 returns 立即显示结果代码 0 或 1。这是一个示例:

retval_complete=1
retval_failed=1
while [[ $retval_complete -ne 0 ]] && [[ $retval_failed -ne 0 ]]; do
  sleep 5
  output=$(kubectl wait --for=condition=failed job/job-name --timeout=0 2>&1)
  retval_failed=$?
  output=$(kubectl wait --for=condition=complete job/job-name --timeout=0 2>&1)
  retval_complete=$?
done

if [ $retval_failed -eq 0 ]; then
    echo "Job failed. Please check logs."
    exit 1
fi

因此,当 condition=failedcondition=complete 为真时,执行将退出 while 循环(retval_completeretval_failed 将为 0)。

接下来,您只需要检查并根据您想要的条件进行操作即可。就我而言,我想快速失败并在作业失败时停止执行。

wait -n 方法对我不起作用,因为我需要它同时适用于 Linux 和 Mac。

我对 Clayton 提供的答案做了一点改进,因为他的脚本在启用 set -e -E 的情况下无法运行。即使在这种情况下,以下内容也能正常工作。

while true; do
  if kubectl wait --for=condition=complete --timeout=0 job/name 2>/dev/null; then
    job_result=0
    break
  fi

  if kubectl wait --for=condition=failed --timeout=0 job/name 2>/dev/null; then
    job_result=1
    break
  fi

  sleep 3
done

if [[ $job_result -eq 1 ]]; then
    echo "Job failed!"
    exit 1
fi

echo "Job succeeded"

您可能想要添加超时以避免无限循环,具体取决于您的情况。