k8s集群Job Pod 容器可能因为多种原因失效,想要更加稳定的使用Job负载,有哪些需要注意的地方?

  • Post author:
  • Post category:其他


k8s集群Job Pod 容器可能因为多种原因失效,想要更加稳定的使用Job负载,有哪些需要注意的地方?

面试官:“计数性Job默认完成模式是什么?Indexed模式如何发布自定义索引呢?”

面试官:“k8s的Job Pod 中的容器可能因为多种不同原因失效,想要更加稳定的使用Job负载,有哪些可以注意的地方?“

面试官:“为什么k8s建议在调试 Job 时将

restartPolicy

设置为 “Never”?”

面试官:“Job 终止与清理了解嘛?Pod重试次数还未 达到

backoffLimit

所设的限制,为什么突然被终止了?猜测原因?“

囧么肥事-胡说八道

计数性Job默认完成模式是什么?Indexed模式如何发布自定义索引呢?

计数性Job默认完成模式是无索引模式

NonIndexed

实际上,带有

确定完成计数

的 Job,即

.spec.completions

不为 null 的 Job, 都可以在其

.spec.completionMode

中设置完成模式:

NonIndexed

(默认)和

Indexed

两种。


先看默认模式NonIndexed,无索引模式

👨‍💻‍

1、每个Job完成事件都是独立无关且同质的
2、成功完成的Pod个数达到.spec.completions值时认为Job已经完成
3、当.spec.completions取值null时,Job被隐式处理为NonIndexed


再看Indexed,索引模式

👨‍💻‍

1、Job 的 Pod 会分配对应的完成索引
2、索引取值为 0 到.spec.completions-1
3、当每个索引都对应一个完成的 Pod 时,Job 被认为是已完成的
4、同一索引值可能被分配给多个Pod,但是只有一个会被记入完成计数

对于索引模式来说,我下发10个索引,我不关注10个索引分别由多少个Pod去完成,我只关注10个索引任务是否按需完成即可。

Indexed模式下,索引有三种获取方式:🤓

  • 第一种:基于注解,Pod 索引在注解

    batch.kubernetes.io/job-completion-index

    中呈现,具体表示为一个十进制值字符串。

  • 第二种:基于主机名,作为 Pod 主机名的一部分,遵循模式

    $(job-name)-$(index)

    。当你同时使用带索引的 Job(Indexed Job)与服务(Service), Job 中的 Pods 可以通过 DNS 使用确切的主机名互相寻址。

  • 第三种:基于环境变量,对于容器化的任务,在环境变量

    JOB_COMPLETION_INDEX

    中体现。


Indexed模式如何发布自定义索引呢?

上面提到了三种获取索引的方式:注解,主机名,环境变量。


Downward API

机制有两种方式可以把将

Pod 和 Container

字段信息呈现给 Pod 中运行的容器:

  • 环境变量

  • 卷文件

你使用 Job 控制器为所有容器设置的内置

JOB_COMPLETION_INDEX

环境变量。

Init 容器将索引映射到一个静态值

,并将其写入一个文件,该文件

通过 emptyDir 卷与运行 worker 的容器共享


举例

👨‍💻‍

  1. 定义使用

    带索引完成信息的 Job 清单


  2. Downward API

    将 Pod

    索引注释作为环境变量



    文件

    传递给容器。例如环境变量控制平面自动设置 downward API 以在

    JOB_COMPLETION_INDEX

    环境变量中公开索引

  3. 根据该清单启动一个带索引(

    Indexed

    )的 Job。

Pod 中的容器可能因为多种不同原因失效,想要更加稳定的使用Job负载,有哪些可以注意的地方?

首先需要理解的是,失效有两种形式,需要适配的能力也不同。

第一种Pod管理的部分容器失效

第二种Pod失效


第一种Pod管理的部分容器失效

Pod 中的容器可能因为多种不同原因失效,例如因为其中的进程退出时返回值非零, 或者容器因为超出内存约束而被杀死等。

如果发生这类事件,并且

.spec.template.spec.restartPolicy = "OnFailure"

, Pod 则继续留在当前节点,但容器会被重新运行。


面对这种场景,你的程序需要具备能够处理在本地被重启的情况的能力,或者容器设置

.spec.template.spec.restartPolicy = "Never"


注意

,即使你将

.spec.parallelism

设置为 1,且将

.spec.completions

设置为 1,并且

.spec.template.spec.restartPolicy

设置为 “Never”,

同一程序仍然有可能被启动两次

😈,程序猿思维:“永远不要假想某某情况不会发生🤣🤣🤣”。

它就发生了,你能咋滴,不管啊???

🤡🤡🤡


第二种Pod失效

整个 Pod 也可能会失败,且原因各不相同。😇😇😇

例如,当 Pod 启动时,

节点失效(被升级、被重启、被删除等)

🙃

或者其中的

容器失败

并且设置了

.spec.template.spec.restartPolicy = "Never"

当 Pod 失败时,Job 控制器会启动一个新的 Pod 替身,去接替失败的Pod未处理完成的工作。

这意味着,你的应用需要处理在一个新 Pod 中被重启的情况。尤其是应用需要

处理之前运行所产生的临时文件、锁、不完整的输出

等问题。


再次注意

😈

如果你将

.spec.parallelism



.spec.completions

都设置为比 1 大的值, 那就有可能同时出现多个 Pod 运行的情况。

为此,你的 Pod 也必须能够处理并发性问题☺️。

为什么k8s建议在调试 Job 时将 `restartPolicy` 设置为 “Never”?

回答这个问题前,先看下Job Pod 回退失效策略

在有些情形下,你可能希望

Job 在经历若干次重试之后直接进入失败状态

,因为这很可能意味着Job遇到了配置错误。


  • .spec.backoffLimit

    字段设置Job Pod 回退失效策略,标识Job失败重试次数,失效回退的限制值默认为 6。

  • 与 Job 相关的

    失效的 Pod

    会被 Job 控制器

    重建

    ,同时

    回退重试时间将会按指数增长

    (从 10 秒、20 秒到 40 秒)最多至 6 分钟。

  • 当 Job 的 Pod 被删除,或者 Pod 成功时没有其它 Pod 处于失败状态,失效回退的次数也会

    被重置

    (为 0)。

好了,这下可以回答刚才的问题,

为什么重启策略要设置为Never?

如果你的 Job 的

restartPolicy

被设置为 ”

OnFailure

“,那么该 Job 管理的 Pod 会在 Job 到达

失效回退次数上限时自动被终止

Pob 被终止,那么调试 Job 中可执行文件的工作变得非常棘手,难以把控。也许你刚调试没多久,结果Pod终止了,调试过程中断了,绝望不!!!

为了

解决Pod终止后 Jobs 的输出遗失掉的问题

,k8s建议在调试 Job 时将

restartPolicy

设置为 “Never”, 或者使用日志系统来确保失效 Jobs 的输出不会意外遗失。

Job 终止与清理了解嘛?Pod重试次数还未 达到 `backoffLimit` 所设的限制,为什么突然被终止了?猜测原因?


Job终止和清理策略

Job

完成时不会再创建新的 Pod

,不过已有的 Pod

也不会被删除

保留这些 Pod 使得你可以

查看已完成的 Pod 的日志输出

,以便检查错误、警告 或者其它诊断性输出。

Job 完成时 Job 对象也一样被保留下来,这样你就可以查看它的状态。

删除老的 Job 的操作留给了用户自己,在查看了 Job 状态之后,你可以使用

kubectl

来删除 Job(例如,

kubectl delete jobs/pi

或者

kubectl delete -f ./job.yaml

)。当使用

kubectl

来删除 Job 时,该 Job 所创建的 Pods 也会被删除。

默认情况下,Job 会持续运行,除非某个 Pod 失败(

restartPolicy=Never

) 或者某个容器出错退出(

restartPolicy=OnFailure

)。这时,Job 基于前述的

spec.backoffLimit

来决定是否以及如何重试。一旦重试次数到达

.spec.backoffLimit

所设的上限,Job 会被标记为失败, 其中运行的 Pods 都会被终止。

终止 Job 的

另一种方式是设置一个活跃期限

。你可以为 Job 的

.spec.activeDeadlineSeconds

设置一个秒数值。该值适用于 Job 的整个生命期,无论 Job 创建了多少个 Pod。一旦 Job 运行时间达到

activeDeadlineSeconds

秒,其所有运行中的 Pod 都会被终止,并且 Job 的状态更新为

type: Failed



reason: DeadlineExceeded

注意 Job 的

.spec.activeDeadlineSeconds

优先级高于其

.spec.backoffLimit

设置。

因此,如果一个 Job 正在重试一个或多个失效的 Pod,该 Job 一旦到达

activeDeadlineSeconds

所设的时限,即不再部署额外的 Pod,即使其重试次数还未达到

backoffLimit

所设的限制


注意问题

Job 规约和 Job 中的Pod 模版规约都有

activeDeadlineSeconds

字段。请确保你在合适的层次设置正确的字段。

还要注意的是,

restartPolicy

对应的是 Pod,而不是 Job 本身:一旦 Job 状态变为

type: Failed

,就不会再发生 Job 重启的动作。换言之,由

.spec.activeDeadlineSeconds



.spec.backoffLimit

所触发的 Job 终结机制

都会导致 Job 永久性的失败

,而这类状态都需要手工干预才能解决。



版权声明:本文为weixin_47838062原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。