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 永久性的失败,而这类状态都需要手工干预才能解决。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐