使用 Pod 故障策略处理可重试和不可重试的 Pod 故障
Kubernetes v1.26 [beta]
本文档介绍了如何使用 Pod 失败策略,结合默认的 Pod 回退失败策略,来更好地控制 Job 中容器或 Pod 级别失败的处理方式。
Pod 失败策略的定义可以帮助您
开始之前
您应该已经熟悉 Job 的基本用法。
您需要有一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与您的集群通信。建议在至少有两个节点的集群上运行本教程,这些节点不充当控制平面主机。如果您还没有集群,可以使用 minikube 创建一个,或者可以使用以下 Kubernetes 游乐场之一
您的 Kubernetes 服务器必须是 v1.25 或更高版本。要检查版本,请输入kubectl version
。确保 功能网关 PodDisruptionConditions
和 JobPodFailurePolicy
在您的集群中都已启用。
使用 Pod 失败策略来避免不必要的 Pod 重试
通过以下示例,您可以了解如何使用 Pod 失败策略来避免在 Pod 失败表明不可重试的软件错误时不必要的 Pod 重启。
首先,根据配置创建 Job
apiVersion: batch/v1
kind: Job
metadata:
name: job-pod-failure-policy-failjob
spec:
completions: 8
parallelism: 2
template:
spec:
restartPolicy: Never
containers:
- name: main
image: docker.io/library/bash:5
command: ["bash"]
args:
- -c
- echo "Hello world! I'm going to exit with 42 to simulate a software bug." && sleep 30 && exit 42
backoffLimit: 6
podFailurePolicy:
rules:
- action: FailJob
onExitCodes:
containerName: main
operator: In
values: [42]
通过运行
kubectl create -f job-pod-failure-policy-failjob.yaml
大约 30 秒后,整个 Job 应该会终止。通过运行以下命令检查 Job 的状态
kubectl get jobs -l job-name=job-pod-failure-policy-failjob -o yaml
在 Job 状态中,可以看到一个 job Failed
条件,其字段 reason
等于 PodFailurePolicy
。此外,message
字段包含有关 Job 终止的更详细的信息,例如:Container main for pod default/job-pod-failure-policy-failjob-8ckj8 failed with exit code 42 matching FailJob rule at index 0
。
为了比较,如果 Pod 失败策略被禁用,它将需要 6 次 Pod 重试,至少需要 2 分钟。
清理
删除您创建的 Job
kubectl delete jobs/job-pod-failure-policy-failjob
集群会自动清理 Pod。
使用 Pod 失败策略来忽略 Pod 中断
通过以下示例,您可以了解如何使用 Pod 失败策略来忽略 Pod 中断,从而避免将 Pod 重试计数器递增到 .spec.backoffLimit
限制。
注意
此示例的时机很重要,因此您可能需要在执行之前阅读步骤。为了触发 Pod 中断,重要的是在 Pod 在节点上运行时(在 Pod 被调度后的 90 秒内)将节点排空。根据配置创建 Job
apiVersion: batch/v1 kind: Job metadata: name: job-pod-failure-policy-ignore spec: completions: 4 parallelism: 2 template: spec: restartPolicy: Never containers: - name: main image: docker.io/library/bash:5 command: ["bash"] args: - -c - echo "Hello world! I'm going to exit with 0 (success)." && sleep 90 && exit 0 backoffLimit: 0 podFailurePolicy: rules: - action: Ignore onPodConditions: - type: DisruptionTarget
通过运行
kubectl create -f job-pod-failure-policy-ignore.yaml
运行此命令以检查 Pod 被调度到的
nodeName
nodeName=$(kubectl get pods -l job-name=job-pod-failure-policy-ignore -o jsonpath='{.items[0].spec.nodeName}')
在 Pod 完成之前(在 90 秒内)将节点排空以驱逐 Pod
kubectl drain nodes/$nodeName --ignore-daemonsets --grace-period=0
检查
.status.failed
以查看 Job 的计数器是否未递增kubectl get jobs -l job-name=job-pod-failure-policy-ignore -o yaml
解除节点隔离
kubectl uncordon nodes/$nodeName
Job 恢复并成功。
为了比较,如果 Pod 失败策略被禁用,Pod 中断将导致整个 Job 终止(因为 .spec.backoffLimit
设置为 0)。
清理
删除您创建的 Job
kubectl delete jobs/job-pod-failure-policy-ignore
集群会自动清理 Pod。
使用 Pod 失败策略来避免基于自定义 Pod 条件的不必要的 Pod 重试
通过以下示例,您可以了解如何使用 Pod 失败策略来避免基于自定义 Pod 条件的不必要的 Pod 重启。
首先,根据配置创建 Job
apiVersion: batch/v1 kind: Job metadata: name: job-pod-failure-policy-config-issue spec: completions: 8 parallelism: 2 template: spec: restartPolicy: Never containers: - name: main image: "non-existing-repo/non-existing-image:example" backoffLimit: 6 podFailurePolicy: rules: - action: FailJob onPodConditions: - type: ConfigIssue
通过运行
kubectl create -f job-pod-failure-policy-config-issue.yaml
请注意,镜像配置错误,因为它不存在。
通过运行以下命令检查 Job 的 Pod 状态
kubectl get pods -l job-name=job-pod-failure-policy-config-issue -o yaml
您将看到类似于以下内容的输出
containerStatuses: - image: non-existing-repo/non-existing-image:example ... state: waiting: message: Back-off pulling image "non-existing-repo/non-existing-image:example" reason: ImagePullBackOff ... phase: Pending
请注意,Pod 仍然处于
Pending
阶段,因为它无法拉取配置错误的镜像。原则上,这可能是一个瞬态问题,镜像可以被拉取。但是,在这种情况下,镜像不存在,因此我们通过自定义条件来指示这一事实。添加自定义条件。首先通过运行以下命令准备补丁
cat <<EOF > patch.yaml status: conditions: - type: ConfigIssue status: "True" reason: "NonExistingImage" lastTransitionTime: "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" EOF
其次,通过运行以下命令选择 Job 创建的 Pod 之一
podName=$(kubectl get pods -l job-name=job-pod-failure-policy-config-issue -o jsonpath='{.items[0].metadata.name}')
然后,通过运行以下命令将补丁应用于 Pod 之一
kubectl patch pod $podName --subresource=status --patch-file=patch.yaml
如果应用成功,您将收到类似于以下内容的通知
pod/job-pod-failure-policy-config-issue-k6pvp patched
通过运行以下命令删除 Pod 以将其过渡到
Failed
阶段kubectl delete pods/$podName
通过运行以下命令检查 Job 的状态
kubectl get jobs -l job-name=job-pod-failure-policy-config-issue -o yaml
在 Job 状态中,可以看到一个 job
Failed
条件,其字段reason
等于PodFailurePolicy
。此外,message
字段包含有关 Job 终止的更详细的信息,例如:Pod default/job-pod-failure-policy-config-issue-k6pvp has condition ConfigIssue matching FailJob rule at index 0
。
注意
在生产环境中,步骤 3 和 4 应该由用户提供的控制器自动执行。清理
删除您创建的 Job
kubectl delete jobs/job-pod-failure-policy-config-issue
集群会自动清理 Pod。
替代方案
您可以完全依赖 Pod 回退失败策略,通过指定 Job 的 .spec.backoffLimit
字段。但是,在许多情况下,在设置 .spec.backoffLimit
的低值以避免不必要的 Pod 重试,以及设置足够高的值以确保 Job 不会因 Pod 中断而终止之间找到平衡是比较困难的。