SIG Apps 如何守住 Kubernetes 工作负载的可靠性底线

2026-09-23 29 预计阅读时间: 1 分钟
来源: kubernetes.io AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:10 分钟

Kubernetes 的问题早已不只是“能否启动容器”,而是应用在滚动升级、节点故障、扩缩容和批处理失败时,能否继续保持可预测的状态。Deployment、StatefulSet、DaemonSet、Job 与 CronJob 背后的控制器,正是承担这项工作的核心组件,而负责维护和演进它们的 SIG Apps,也因此影响着几乎每一个 Kubernetes 用户。

工作负载 API 是应用生命周期的控制面

开发者提交一个 Deployment 后,真正维持副本数、创建 ReplicaSet 并推进滚动升级的是控制器。不同 API 对应不同的运行语义:

  • Deployment 与 ReplicaSet:适合无状态服务,负责副本管理和渐进式发布。
  • StatefulSet:为数据库等有状态应用提供稳定的 Pod 标识和有序生命周期。
  • DaemonSet:确保符合条件的节点各运行一个 Pod,常用于日志、网络或 GPU 监控代理。
  • Job 与 CronJob:运行一次性任务、批处理任务和周期任务,并处理重试与完成状态。

这些对象的价值并不止于“生成 Pod”。控制器持续执行调谐:比较期望状态与实际状态,再采取创建、删除、替换或重试等动作。也正因为这种行为被用户、自动化脚本和上层控制器依赖了多年,修改控制器语义必须格外谨慎。

一个看起来更合理的重试策略,可能导致旧监控规则误报;更积极地删除卡住的 Pod,也可能破坏依赖旧行为的运维流程。SIG Apps 面临的核心张力,是在可靠性改进、操作简单性和向后兼容之间找到平衡。

最棘手的问题往往发生在节点边界

Pod 异常不一定说明应用本身失败。节点可能失联、网络可能分区、kubelet 可能停止上报,也可能只是短暂变慢。控制器需要判断:

  1. 应该继续等待节点恢复吗?
  2. 是否应当在其他节点创建替代 Pod?
  3. 原 Pod 如果重新出现,会不会造成任务重复或出现两个实例?
  4. 对 Job 而言,这次失败应该重试、忽略,还是立即终止整个任务?

DaemonSet 和 Job 对节点状态尤其敏感。前者与节点一一关联,后者可能运行昂贵且不可重复的计算。节点状态判断错误,轻则导致发布长期卡住,重则造成重复执行、资源浪费或数据不一致。

因此,相关问题正在通过跨 SIG 的 Node Lifecycle Working Group 统筹处理,而不是由每个控制器分别堆叠补丁。对平台团队而言,理想结果非常实际:减少因为某个异常节点导致 DaemonSet 无法完成发布、最终需要人工 cordon、删除 Pod 或重启任务的凌晨告警。

用 PodFailurePolicy 明确 Job 的失败语义

平台团队不应把所有非零退出码都当成同一种失败。比如退出码 42 可以表示输入不可恢复,此时继续重试只会浪费资源;退出码 1 则可能是临时错误,仍可由 Job 的退避机制重试。

下面的示例可以直接提交到支持 PodFailurePolicy 的 Kubernetes 集群。它创建一个必然以 42 退出的 Job,并要求控制器立即将整个 Job 判定为失败。

apiVersion: batch/v1
kind: Job
metadata:
  name: failure-policy-demo
spec:
  backoffLimit: 4
  podFailurePolicy:
    rules:
      - action: FailJob
        onExitCodes:
          containerName: worker
          operator: In
          values: [42]
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: worker
          image: busybox:1.36
          command: [sh, -c]
          args:
            - echo "fatal input error"; exit 42

保存为 job.yaml 后执行:

kubectl apply -f job.yaml
kubectl wait --for=condition=failed job/failure-policy-demo --timeout=60s
kubectl describe job failure-policy-demo
kubectl get pods -l job-name=failure-policy-demo
kubectl logs job/failure-policy-demo

测试结束后清理资源:

kubectl delete job failure-policy-demo

这个例子也揭示了现有 API 的一个细小但真实的缺口:多条 PodFailurePolicy 规则即使针对不同退出码,最终也可能产生相同的通用失败原因。上层工具很难仅根据 Job 条件判断究竟是哪条规则生效。

重新进入开发计划、目标指向 Kubernetes 1.38 的 KEP-4443,拟为每条 PodFailurePolicyRule 增加可选名称,并将其附加到 JobFailed 条件的 reason 中。这样,JobSet 一类上层控制器就能区分不同故障并采取不同动作。由于该字段仍属于未来提案,在对应版本和功能正式可用前,不应把它写进生产清单。

AI 工作负载需要“组级别”恢复

传统 Deployment 通常可以逐个替换 Pod,但分布式训练和分片推理不是一组彼此独立的副本。一次训练可能横跨数百块 GPU,其中任意节点失败,都可能让其他节点继续占用昂贵资源却无法推进。

SIG Apps 正通过 JobSet、LeaderWorkerSet(LWS)以及 Agent Sandbox 等较新的子项目探索这些模式:

  • JobSet 面向由多个 Job 共同组成的分布式任务。
  • LeaderWorkerSet 面向 leader-worker 结构和分片式 LLM 推理。
  • Agent Sandbox 探索动态智能体工作负载需要的隔离与生命周期模式。

关键变化是从“单 Pod 自愈”转向“协调组恢复”。例如,一个成员失败后,系统可以让整个工作负载组回到最近的干净检查点,而不是留下部分成功、部分卡死的中间状态。

这些能力优先以 CRD 和独立子项目演进,而不是直接扩张 Kubernetes 核心 API。这既给新模型保留试验空间,也避免未经长期验证的字段成为永久兼容负担。实际采用时需要确认对应项目的安装方式、API 版本和成熟度,不能假设它们像 Deployment 一样在所有集群中默认可用。

生产采用时应检查什么

平台团队可以从以下几个方面评估自身工作负载是否真正具备恢复能力:

  • 为 Job 区分可重试错误、可忽略错误和不可恢复错误,而不是只设置一个很大的 backoffLimit
  • 监控 Deployment、StatefulSet 和 DaemonSet 的期望副本数、可用副本数以及长时间未完成的 rollout。
  • 对节点失联、磁盘异常和网络分区进行故障演练,观察控制器是否会产生重复任务或无限等待。
  • 对 GPU 训练等高成本任务设计检查点,避免把“重新调度”误认为“能够恢复计算进度”。
  • 引入 JobSet、LWS 或 Agent Sandbox 前,先核对 CRD 版本、升级路径和控制器高可用方案。
  • 升级 Kubernetes 时阅读工作负载控制器相关变更,并在预生产环境验证依赖旧行为的脚本和告警。

如果希望参与 SIG Apps,稳定 API 并不一定是最容易的起点。Deployment 和 StatefulSet 的修改需要承担沉重的兼容性成本;相较之下,Agent Sandbox 等仍在快速演进的子项目通常更适合新贡献者。可以从 SIG Apps 的社区频道、例会、文档问题或可复现的控制器缺陷开始。

SIG Apps 的重要性就在于它很少被应用开发者直接看见,却决定了 Kubernetes 在故障发生时究竟会怎样行动。未来的工作负载可能从普通 Web 服务扩展到大规模训练、分片推理和动态智能体,但演进原则没有改变:新能力必须建立在可预测的控制器行为、清晰的失败语义和可持续的向后兼容之上。


相关推荐