最佳的等待 Kubernetes 作业完成的方法是什么?我注意到很多建议使用:
kubectl wait --for=condition=complete job/myjob
但我认为这只有在工作成功时才有效。如果失败了,我就必须做类似这样的事情:
kubectl wait --for=condition=failed job/myjob
有没有办法使用wait同时等待两个条件?如果没有,那么等待作业成功或失败的最佳方法是什么?
最佳的等待 Kubernetes 作业完成的方法是什么?我注意到很多建议使用:
kubectl wait --for=condition=complete job/myjob
但我认为这只有在工作成功时才有效。如果失败了,我就必须做类似这样的事情:
kubectl wait --for=condition=failed job/myjob
有没有办法使用wait同时等待两个条件?如果没有,那么等待作业成功或失败的最佳方法是什么?
运行第一个等待条件作为子进程并捕获其PID。如果条件满足,此进程将以退出码0退出。
kubectl wait --for=condition=complete job/myjob &
completion_pid=$!
对于失败等待条件,按照相同的方式处理。这里的技巧是添加&& exit 1
,以便在作业失败时子进程返回非零退出代码。
kubectl wait --for=condition=failed job/myjob && exit 1 &
failure_pid=$!
然后使用Bash内置的wait -n $PID1 $PID2
等待其中一个条件成功。该命令将捕获首个退出的进程的退出代码:
Mac用户请注意,
wait -n [...PID]
需要Bash 4.3或更高版本。由于许可问题,MacOS永远停留在3.2版本。请参阅这个Stackoverflow帖子了解如何安装最新版本。
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
,您可以利用这种行为。
在此情况下,命令行会立即返回结果代码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=failed
或condition=complete
任意一个为真时,执行将退出while循环(retval_complete
或retval_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"
根据您的情况,您可能需要添加超时以避免无限循环。
set -e
就不足以识别错误命令呢?那样的话,我就不需要检查失败条件了吗?@Martin Melka - vgdubkubectl wait --for=condition=failed --timeout=0 job/name
并且 pod 的状态 不是 failed
时,该命令将以非零退出代码退出。启用 set -e
后,这将导致整个脚本终止。这里的逻辑是“当 kubectl wait
以非零代码退出时,继续轮询它”。我们只希望在 kubectl wait
以零退出代码退出时退出脚本,因为这意味着 pod 已经完成或失败。 - Martin Melkafirst
失败的任务集中,-e将会正确地退出脚本,对吗? - vgdubkubectl wait
不会以 pod 状态的退出代码退出。如果 pod 目前处于已完成(成功)状态,则 kubectl wait --for=condition=complete --timeout=0 job/name
将以 0(成功)退出。否则将以 1(错误)退出(即,如果 pod 目前仍在运行/挂起/失败/其他)。同样,如果 pod 目前处于失败状态,则 kubectl wait --for=condition=failed --timeout=0 job/name
将以 0(成功)退出。这样做是因为没有 kubectl
命令可以执行“当 pod 成功或出错时退出”。 - Martin Melkakubectl wait --for=condition=<条件名
命令可以等待特定条件,目前似乎无法指定多个条件。
我的解决方法是使用oc get --wait
命令,--wait
选项会在目标资源更新后关闭命令。我将使用oc get --wait
监视作业的status
部分,直到status
被更新。当status
部分被更新时,表示作业已经按照一些状态条件完成了。
如果作业成功完成,则status.conditions.type
立即更新为Complete
。但如果作业失败,则作业的Pod将自动重启,而不论restartPolicy
是否为OnFailure
或Never
。但如果第一个更新后未更新为Complete
,则我们可以认为该作业处于Failed
状态。
以下是我的测试证据。
# 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
# 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
。测试完成后,请删除现有作业资源。# 删除名为 pi 的任务 job.batch "pi" 已删除
# 创建 job.yml 文件中定义的任务,并检查任务状态,直到任务状态为失败或完成,否则输出“Failed” job.batch/pi 已创建 map[active:1 startTime:2019-03-09T12:31:05Z] Failed
until [[ $SECONDS -gt $end ]] || [[ $(kubectl get jobs $job_name -o jsonpath='{.status.conditions[?(@.type=="Failed")].status}') == "True" ]] || [[ $(kubectl get jobs $job_name -o jsonpath='{.status.conditions[?(@.type=="Complete")].status}') == "True" ]]; do
- ruazn2openshift cli
的例子。但你可以使用 kubernetes cli
来赶上进度,它非常棒! - Daein Parkkubectl logs --follow
命令:kubectl wait --for=condition=ready pod --selector=job-name=YOUR_JOB_NAME --timeout=-1s
kubectl logs --follow job/YOUR_JOB_NAME
当你的工作结束时,它将终止,并返回任何状态。
kubectl logs
命令中添加标志 --all-containers=true
。 - Turakubectl logs
有一个选项--pod-running-timeout
,它似乎取代了第一个命令,并且如果Pod永远不会启动,则不会挂起。 - Raphael
if wait ...
代替将退出代码存储在变量中。 - Exagone313--for=condition=failure
应该改为--for=condition=failed
? - James Mkubectl explain job.status.conditions.type
中看到。我已经更新了代码 :) - Sebastian Nwait -n
:( - Martin Melkawait -n
命令将立即退出,您将无法得到漂亮的if
语句日志记录。除此之外,这种方法完美地运作了。 - David Lavender