Pod 生命周期

此页面描述了 Pod 的生命周期。Pod 遵循一个明确定义的生命周期,从 Pending 阶段开始,如果其至少一个主容器启动正常,则进入 Running 阶段,然后根据 Pod 中是否有容器终止失败,进入 SucceededFailed 阶段。

与单个应用容器一样,Pod 被认为是相对短暂(而非持久)的实体。Pod 被创建,分配一个唯一的 ID(UID),并调度到节点上运行,它们会一直留在节点上,直到终止(根据重启策略)或删除。如果一个 节点发生故障,在该节点上运行(或调度到该节点上运行)的 Pod 将被标记为删除。控制面会在超时后标记 Pod 进行移除。

Pod 生命周期

当 Pod 运行时,kubelet 能够重启容器以处理某些类型的故障。在一个 Pod 中,Kubernetes 跟踪不同的容器状态,并确定采取什么措施使 Pod 再次健康。

在 Kubernetes API 中,Pod 既有规范也有实际状态。Pod 对象的 Status 包含一组 Pod 条件。如果这对你的应用有用,你还可以将自定义就绪信息注入到 Pod 的条件数据中。

Pod 在其生命周期中只调度一次;将 Pod 分配到特定节点称为 绑定,选择使用哪个节点的过程称为 调度。一旦 Pod 被调度并绑定到节点,Kubernetes 就会尝试在该节点上运行该 Pod。Pod 将在该节点上运行,直到它停止或 Pod 终止;如果 Kubernetes 无法在选定的节点上启动 Pod(例如,在 Pod 启动之前节点崩溃),则该特定的 Pod 永远不会启动。

你可以使用 Pod 调度就绪来延迟 Pod 的调度,直到所有其 调度门都被移除。例如,你可能希望定义一组 Pod,但只在所有 Pod 都被创建后才触发调度。

Pod 和故障恢复

如果 Pod 中的一个容器失败,Kubernetes 可能会尝试重启该特定容器。阅读Pod 如何处理容器问题以了解更多信息。

然而,Pod 可能会以集群无法恢复的方式失败,在这种情况下,Kubernetes 不会尝试进一步修复 Pod;相反,Kubernetes 会删除 Pod,并依赖其他组件提供自动修复。

如果一个 Pod 被调度到一个 节点,然后该节点发生故障,Pod 将被视为不健康,Kubernetes 最终会删除该 Pod。Pod 在因资源不足或节点维护而导致的驱逐后不会存活。

Kubernetes 使用一个更高级别的抽象,称为控制器,它负责管理相对可丢弃的 Pod 实例。

一个给定的 Pod(由 UID 定义)永远不会被“重新调度”到不同的节点;相反,该 Pod 可以被一个新的、几乎相同的 Pod 替换。如果你创建一个替换 Pod,它甚至可以与旧 Pod 具有相同的名称(如 .metadata.name),但替换 Pod 将具有与旧 Pod 不同的 .metadata.uid

Kubernetes 不保证现有 Pod 的替换品将调度到与被替换的旧 Pod 相同的节点上。

关联的生命周期

当某个事物(例如)与 Pod 具有相同的生命周期时,这意味着该事物存在的时间与该特定 Pod(具有精确的 UID)存在的时间相同。如果该 Pod 因任何原因被删除,即使创建了一个相同的替换品,相关事物(本例中的卷)也会被销毁并重新创建。

A multi-container Pod that contains a file puller sidecar and a web server. The Pod uses an ephemeral emptyDir volume for shared storage between the containers.

图 1。

一个包含文件拉取器边车容器和 Web 服务器的多容器 Pod。Pod 使用临时 emptyDir在容器之间共享存储。

Pod 阶段

Pod 的 status 字段是一个 PodStatus 对象,它有一个 phase 字段。

Pod 的阶段是对 Pod 在其生命周期中所处位置的简单、高层次总结。该阶段并非旨在全面汇总容器或 Pod 状态的观察结果,也并非旨在成为全面的状态机。

Pod 阶段值的数量和含义受到严格保护。除了此处记录的内容,不应假定具有给定 phase 值的 Pod 的任何其他信息。

以下是 phase 可能的值

描述
PendingPod 已被 Kubernetes 集群接受,但一个或多个容器尚未设置并准备运行。这包括 Pod 等待调度的时间以及通过网络下载容器镜像所花费的时间。
RunningPod 已被绑定到节点,并且所有容器都已创建。至少一个容器仍在运行,或者正在启动或重启过程中。
SucceededPod 中的所有容器都已成功终止,并且不会被重启。
FailedPod 中的所有容器都已终止,并且至少有一个容器终止失败。也就是说,容器要么以非零状态退出,要么被系统终止,并且未设置为自动重启。
Unknown由于某种原因无法获取 Pod 的状态。此阶段通常是由于与 Pod 应该运行的节点通信时出错而发生的。

自 Kubernetes 1.27 起,kubelet 会将已删除的 Pod(静态 Pod 和未带 finalizer 的强制删除的 Pod 除外)转换到终止阶段(根据 Pod 容器的退出状态,可以是 FailedSucceeded),然后才从 API 服务器中删除。

如果节点死亡或与集群的其余部分断开连接,Kubernetes 会应用策略,将丢失节点上所有 Pod 的 phase 设置为 Failed。

容器状态

除了 Pod 的整体阶段之外,Kubernetes 还跟踪 Pod 中每个容器的状态。你可以使用容器生命周期钩子来触发事件,使其在容器生命周期中的特定点运行。

一旦 调度器 将 Pod 分配给一个节点,kubelet 就会使用容器运行时为该 Pod 创建容器。容器有三种可能的状态:WaitingRunningTerminated

要检查 Pod 容器的状态,可以使用 kubectl describe pod <pod-name>。输出将显示该 Pod 中每个容器的状态。

每种状态都有特定含义

Waiting

如果容器既不在 Running 状态也不在 Terminated 状态,则它处于 Waiting 状态。处于 Waiting 状态的容器仍在执行完成启动所需的操作:例如,从容器镜像仓库拉取容器镜像,或者应用Secret 数据。当你使用 kubectl 查询一个带有 Waiting 状态容器的 Pod 时,你还会看到一个 Reason 字段,总结容器处于该状态的原因。

Running

Running 状态表示容器正在执行而没有问题。如果配置了 postStart 钩子,它已经执行并完成。当你使用 kubectl 查询一个带有 Running 状态容器的 Pod 时,你还会看到容器进入 Running 状态的时间信息。

Terminated

处于 Terminated 状态的容器已经开始执行,然后要么运行完成,要么因某种原因失败。当你使用 kubectl 查询一个带有 Terminated 状态容器的 Pod 时,你会看到该容器执行期间的原因、退出代码以及开始和结束时间。

如果容器配置了 preStop 钩子,则该钩子在容器进入 Terminated 状态之前运行。

Pod 如何处理容器问题

Kubernetes 使用 Pod spec 中定义的 restartPolicy 来管理 Pod 内的容器故障。此策略决定了 Kubernetes 如何响应因错误或其他原因退出的容器,它遵循以下序列:

  1. 初始崩溃:Kubernetes 根据 Pod 的 restartPolicy 尝试立即重启。
  2. 重复崩溃:在初始崩溃后,Kubernetes 会对后续重启应用指数回退延迟,如restartPolicy中所述。这可以防止快速、重复的重启尝试导致系统过载。
  3. CrashLoopBackOff 状态:这表示回退延迟机制当前正在对处于崩溃循环、反复失败和重启的给定容器生效。
  4. 回退重置:如果容器成功运行了一定时间(例如 10 分钟),Kubernetes 会重置回退延迟,将任何新的崩溃视为第一次崩溃。

在实践中,当 Pod 中的容器未能正确启动,然后在一个循环中反复尝试并失败时,CrashLoopBackOff 是在描述或列出 Pod 时,从 kubectl 命令输出中可能看到的一种条件或事件。

换句话说,当容器进入崩溃循环时,Kubernetes 会应用 容器重启策略中提到的指数回退延迟。此机制可防止故障容器因连续的失败启动尝试而使系统不堪重负。

CrashLoopBackOff 可能由以下问题引起:

  • 导致容器退出的应用程序错误。
  • 配置错误,例如不正确的环境变量或缺少配置文件。
  • 资源限制,容器可能没有足够的内存或 CPU 来正确启动。
  • 如果应用程序未在预期时间内开始提供服务,则健康检查失败。
  • 容器活性探针或启动探针返回 Failure 结果,如探针部分所述。

要调查 CrashLoopBackOff 问题的根本原因,用户可以:

  1. 检查日志:使用 kubectl logs <pod-name> 检查容器的日志。这通常是诊断导致崩溃问题的最直接方法。
  2. 检查事件:使用 kubectl describe pod <pod-name> 查看 Pod 的事件,这可以提供有关配置或资源问题的提示。
  3. 审查配置:确保 Pod 配置(包括环境变量和挂载卷)正确,并且所有必需的外部资源都可用。
  4. 检查资源限制:确保为容器分配了足够的 CPU 和内存。有时,增加 Pod 定义中的资源可以解决问题。
  5. 调试应用程序:应用程序代码中可能存在错误或配置错误。在本地或开发环境中运行此容器镜像有助于诊断应用程序特有的问题。

容器重启

当 Pod 中的容器停止或发生故障时,Kubernetes 可以重启它。重启并非总是合适的;例如,初始化容器仅在 Pod 启动期间运行一次。

你可以将重启配置为适用于所有 Pod 的策略,或者使用容器级配置(例如:当你定义边车容器时)。

容器重启和弹性

Kubernetes 项目建议遵循云原生原则,包括考虑意外或任意重启的弹性设计。你可以通过使 Pod 失败并依赖自动替换来实现这一点,或者你可以设计容器级别的弹性。这两种方法都有助于确保你的整体工作负载在部分故障的情况下仍然可用。

Pod 级别的容器重启策略

Pod 的 spec 具有 restartPolicy 字段,可能的值为 Always、OnFailure 和 Never。默认值为 Always。

Pod 的 restartPolicy 适用于 Pod 中的应用容器和常规初始化容器边车容器会忽略 Pod 级别的 restartPolicy 字段:在 Kubernetes 中,边车容器定义为 initContainers 中的一个条目,其容器级别的 restartPolicy 设置为 Always。对于退出并带有错误的初始化容器,如果 Pod 级别的 restartPolicyOnFailureAlways,kubelet 会重启该初始化容器。

  • Always:在任何终止后自动重启容器。
  • OnFailure:仅当容器因错误(非零退出状态)退出时才重启容器。
  • Never:不自动重启已终止的容器。

当 kubelet 根据配置的重启策略处理容器重启时,这仅适用于在同一 Pod 内部并在同一节点上运行的替换容器的重启。在 Pod 中的容器退出后,kubelet 会以指数回退延迟(10 秒、20 秒、40 秒等)重新启动它们,最长延迟为 300 秒(5 分钟)。一旦容器连续运行 10 分钟没有任何问题,kubelet 会重置该容器的重启回退计时器。边车容器和 Pod 生命周期解释了在初始化容器上指定 restartpolicy 字段时的行为。

单个容器重启策略和规则

功能状态: Kubernetes v1.34 [alpha] (默认禁用)

如果你的集群启用了功能门控 ContainerRestartRules,你可以在 单个容器 上指定 restartPolicyrestartPolicyRules 来覆盖 Pod 重启策略。容器重启策略和规则适用于 Pod 中的应用容器和常规初始化容器

Kubernetes 原生的边车容器的容器级 restartPolicy 设置为 Always,并且不支持 restartPolicyRules

容器重启将遵循与上述 Pod 重启策略相同的指数回退。支持的容器重启策略:

  • Always:在任何终止后自动重启容器。
  • OnFailure:仅当容器因错误(非零退出状态)退出时才重启容器。
  • Never:不自动重启已终止的容器。

此外,_单个容器_ 可以指定 restartPolicyRules。如果指定了 restartPolicyRules 字段,则容器 restartPolicy **也必须**指定。restartPolicyRules 定义了在容器退出时应用的一系列规则。每个规则将包含一个条件和一个动作。支持的条件是 exitCodes,它将容器的退出代码与给定值列表进行比较。支持的动作是 Restart,这意味着容器将被重启。规则将按顺序评估。在第一次匹配时,将应用该动作。如果没有规则的条件匹配,Kubernetes 将回退到容器配置的 restartPolicy

例如,一个具有 OnFailure 重启策略的 Pod,其中包含一个 try-once 容器。这允许 Pod 只重启某些容器。

apiVersion: v1
kind: Pod
metadata:
  name: on-failure-pod
spec:
  restartPolicy: OnFailure
  containers:
  - name: try-once-container    # This container will run only once because the restartPolicy is Never.
    image: docker.io/library/busybox:1.28
    command: ['sh', '-c', 'echo "Only running once" && sleep 10 && exit 1']
    restartPolicy: Never     
  - name: on-failure-container  # This container will be restarted on failure.
    image: docker.io/library/busybox:1.28
    command: ['sh', '-c', 'echo "Keep restarting" && sleep 1800 && exit 1']

一个具有 Always 重启策略的 Pod,其中包含一个只执行一次的初始化容器。如果初始化容器失败,Pod 将失败。这允许 Pod 在初始化失败时失败,但在初始化成功后继续运行。

apiVersion: v1
kind: Pod
metadata:
  name: fail-pod-if-init-fails
spec:
  restartPolicy: Always
  initContainers:
  - name: init-once      # This init container will only try once. If it fails, the pod will fail.
    image: docker.io/library/busybox:1.28
    command: ['sh', '-c', 'echo "Failing initialization" && sleep 10 && exit 1']
    restartPolicy: Never
  containers:
  - name: main-container # This container will always be restarted once initialization succeeds.
    image: docker.io/library/busybox:1.28
    command: ['sh', '-c', 'sleep 1800 && exit 0']

一个具有 Never 重启策略的 Pod,其中包含一个忽略特定退出代码并重新启动的容器。这对于区分可重启错误和不可重启错误很有用。

apiVersion: v1
kind: Pod
metadata:
  name: restart-on-exit-codes
spec:
  restartPolicy: Never
  containers:
  - name: restart-on-exit-codes
    image: docker.io/library/busybox:1.28
    command: ['sh', '-c', 'sleep 60 && exit 0']
    restartPolicy: Never     # Container restart policy must be specified if rules are specified
    restartPolicyRules:      # Only restart the container if it exits with code 42
    - action: Restart
      exitCodes:
        operator: In
        values: [42]

重启规则可用于更高级的生命周期管理场景。请注意,重启规则会受到与常规重启策略相同的缺陷的影响。Kubelet 重启、容器运行时垃圾回收、与控制平面间歇性连接问题可能导致状态丢失,并且即使你期望容器不重启,容器也可能重新运行。

减少容器重启延迟

特性状态: `Kubernetes v1.33 [alpha]`(默认启用:false)

启用 alpha 功能门控 ReduceDefaultCrashLoopBackOffDecay 后,集群中的容器启动重试将从 1 秒(而不是 10 秒)开始,每次重启以 2 倍指数增长,直到最大延迟为 60 秒(而不是 300 秒,即 5 分钟)。

如果将此功能与 alpha 功能 KubeletCrashLoopBackOffMax(下文所述)一起使用,则单个节点可能具有不同的最大延迟。

可配置的容器重启延迟

功能状态: Kubernetes v1.32 [alpha] (默认禁用)

启用 alpha 功能门控 KubeletCrashLoopBackOffMax 后,你可以重新配置容器启动重试之间的最大延迟,从默认的 300 秒(5 分钟)更改。此配置通过 kubelet 配置在每个节点上设置。在你的 kubelet 配置中,在 crashLoopBackOff 下,将 maxContainerRestartPeriod 字段设置为 "1s""300s" 之间的值。如上文 容器重启策略 中所述,该节点上的延迟仍将从 10 秒开始,每次重启以 2 倍指数增长,但现在将限制在你的配置最大值。如果配置的 maxContainerRestartPeriod 小于默认初始值 10 秒,则初始延迟将改为配置的最大值。

请参阅以下 kubelet 配置示例

# container restart delays will start at 10s, increasing
# 2x each time they are restarted, to a maximum of 100s
kind: KubeletConfiguration
crashLoopBackOff:
    maxContainerRestartPeriod: "100s"
# delays between container restarts will always be 2s
kind: KubeletConfiguration
crashLoopBackOff:
    maxContainerRestartPeriod: "2s"

如果将此功能与 alpha 功能 ReduceDefaultCrashLoopBackOffDecay(如上所述)一起使用,则集群的初始回退和最大回退的默认值将不再是 10 秒和 300 秒,而是 1 秒和 60 秒。每个节点配置优先于 ReduceDefaultCrashLoopBackOffDecay 设置的默认值,即使这会导致节点具有比集群中其他节点更长的最大回退。

Pod 条件

Pod 具有 PodStatus,其中包含一个 PodConditions 数组,表示 Pod 已通过或未通过的条件。Kubelet 管理以下 PodConditions:

  • PodScheduled:Pod 已被调度到一个节点。
  • PodReadyToStartContainers:(beta 功能;默认启用) Pod 沙箱已成功创建,网络已配置。
  • ContainersReady:Pod 中所有容器都已就绪。
  • Initialized:所有初始化容器已成功完成。
  • Ready:Pod 能够处理请求,并且应该添加到所有匹配的服务负载均衡池中。
  • DisruptionTarget:Pod 即将因中断(例如抢占、驱逐或垃圾回收)而终止。
  • PodResizePending:已请求 Pod 大小调整但无法应用。请参阅Pod 大小调整状态
  • PodResizeInProgress:Pod 正在调整大小。请参阅Pod 大小调整状态
字段名称描述
type此 Pod 条件的名称。
status表示该条件是否适用,可能的值为 “True”、“False” 或 “Unknown”。
lastProbeTime上次探测 Pod 条件的时间戳。
lastTransitionTimePod 上次从一种状态转换到另一种状态的时间戳。
reason机器可读的 UpperCamelCase 文本,表示条件上次转换的原因。
message人类可读的消息,指示上次状态转换的详细信息。

Pod 就绪

功能状态:`Kubernetes v1.14 [stable]`

你的应用程序可以将额外的反馈或信号注入到 PodStatus 中:Pod 就绪。为此,请在 Pod 的 spec 中设置 readinessGates,以指定 kubelet 评估 Pod 就绪状况的其他条件列表。

就绪门控由 Pod 的 status.condition 字段的当前状态决定。如果 Kubernetes 在 Pod 的 status.conditions 字段中找不到这样的条件,则该条件的状态默认为 “False”。

这是一个例子:

kind: Pod
...
spec:
  readinessGates:
    - conditionType: "www.example.com/feature-1"
status:
  conditions:
    - type: Ready                              # a built in PodCondition
      status: "False"
      lastProbeTime: null
      lastTransitionTime: 2018-01-01T00:00:00Z
    - type: "www.example.com/feature-1"        # an extra PodCondition
      status: "False"
      lastProbeTime: null
      lastTransitionTime: 2018-01-01T00:00:00Z
  containerStatuses:
    - containerID: docker://abcd...
      ready: true
...

你添加的 Pod 条件名称必须符合 Kubernetes 标签键格式

Pod 就绪状态

kubectl patch 命令不支持修补对象状态。要为 Pod 设置这些 status.conditions,应用程序和操作员应该使用 PATCH 动作。你可以使用 Kubernetes 客户端库编写代码,为 Pod 就绪设置自定义 Pod 条件。

对于使用自定义条件的 Pod,仅当以下两个语句都适用时,该 Pod 才被评估为就绪:

  • Pod 中的所有容器都已就绪。
  • readinessGates 中指定的所有条件都为 True

当 Pod 的容器就绪,但至少有一个自定义条件缺失或为 False 时,kubelet 会将 Pod 的条件设置为 ContainersReady

Pod 网络就绪

功能状态: Kubernetes v1.29 [beta]

Pod 被调度到节点后,需要被 kubelet 接纳并挂载任何所需的存储卷。一旦这些阶段完成,kubelet 将与容器运行时(使用 容器运行时接口 (CRI))协作,为 Pod 设置运行时沙箱并配置网络。如果 PodReadyToStartContainersCondition 功能门控 已启用(Kubernetes 1.34 默认启用),则 PodReadyToStartContainers 条件将被添加到 Pod 的 status.conditions 字段中。

当 Kubelet 检测到 Pod 没有配置网络的运行时沙箱时,它会将 PodReadyToStartContainers 条件设置为 False。这发生在以下情况:

  • 在 Pod 生命周期的早期,当 kubelet 尚未开始使用容器运行时为 Pod 设置沙箱时。
  • 在 Pod 生命周期的后期,当 Pod 沙箱因以下任一原因被销毁时:
    • 节点重启,而 Pod 未被驱逐
    • 对于使用虚拟机进行隔离的容器运行时,Pod 沙箱虚拟机重启,这需要创建新的沙箱和新的容器网络配置。

在运行时插件成功完成 Pod 的沙箱创建和网络配置后,kubelet 将 PodReadyToStartContainers 条件设置为 True。在 PodReadyToStartContainers 条件设置为 True 后,kubelet 可以开始拉取容器镜像并创建容器。

对于带有初始化容器的 Pod,kubelet 在初始化容器成功完成后(发生在运行时插件成功创建沙箱和网络配置之后)将 Initialized 条件设置为 True。对于没有初始化容器的 Pod,kubelet 在沙箱创建和网络配置开始之前将 Initialized 条件设置为 True

容器探针

探针kubelet 定期对容器执行的诊断。为了执行诊断,kubelet 要么在容器内执行代码,要么发出网络请求。

检查机制

有四种不同的方法可以使用探针检查容器。每个探针必须精确定义以下四种机制中的一种:

exec
在容器内执行指定命令。如果命令以状态码 0 退出,则诊断被认为是成功的。
grpc
使用 gRPC 执行远程过程调用。目标应实现 gRPC 健康检查。如果响应的 statusSERVING,则诊断被认为是成功的。
httpGet
对 Pod 的 IP 地址上的指定端口和路径执行 HTTP GET 请求。如果响应状态码大于或等于 200 且小于 400,则诊断被认为是成功的。
tcpSocket
对 Pod 的 IP 地址上的指定端口执行 TCP 检查。如果端口打开,则诊断被认为是成功的。如果远程系统(容器)在打开连接后立即关闭连接,则这算作健康。

探测结果

每个探针有三种结果之一:

成功
容器通过诊断。
失败
容器诊断失败。
Unknown
诊断失败(不应采取任何措施,kubelet 将进行进一步检查)。

探针类型

kubelet 可以选择对运行中的容器执行并响应三种类型的探针:

livenessProbe
指示容器是否正在运行。如果活性探针失败,kubelet 会杀死容器,并且容器将受到其重启策略的约束。如果容器未提供活性探针,默认状态为 Success
readinessProbe
指示容器是否已准备好响应请求。如果就绪探针失败,EndpointSlice 控制器将从所有匹配 Pod 的服务的 EndpointSlices 中移除 Pod 的 IP 地址。初始延迟之前的就绪默认状态为 Failure。如果容器未提供就绪探针,默认状态为 Success
startupProbe
指示容器内的应用程序是否已启动。如果提供了启动探针,则在它成功之前,所有其他探针都将被禁用。如果启动探针失败,kubelet 会杀死容器,并且容器将受到其重启策略的约束。如果容器未提供启动探针,默认状态为 Success

有关如何设置活性、就绪或启动探针的更多信息,请参阅配置活性、就绪和启动探针

何时使用活性探针?

如果你的容器中的进程在遇到问题或变得不健康时能够自行崩溃,那么你并不一定需要活性探针;kubelet 会根据 Pod 的 restartPolicy 自动执行正确的操作。

如果你希望容器在探针失败时被杀死并重启,那么请指定活性探针,并将 restartPolicy 指定为 Always 或 OnFailure。

何时使用就绪探针?

如果你希望只有当探测成功时才开始向 Pod 发送流量,请指定就绪探针。在这种情况下,就绪探针可能与活性探针相同,但在规范中存在就绪探针意味着 Pod 将在不接收任何流量的情况下启动,并且只有在探测开始成功后才开始接收流量。

如果你希望容器能够自行停机进行维护,你可以指定一个就绪探针,该探针检查一个特定于就绪的端点,该端点与活性探针不同。

如果你的应用程序对后端服务有严格的依赖,你可以实现活性探针和就绪探针。当应用程序本身健康时,活性探针会通过,但就绪探针还会额外检查每个必需的后端服务是否可用。这有助于你避免将流量导向只能响应错误消息的 Pod。

如果你的容器需要在启动期间加载大量数据、配置文件或进行迁移,你可以使用启动探针。但是,如果你想区分应用程序已失败和应用程序仍在处理其启动数据的情况,你可能更喜欢就绪探针。

何时使用启动探针?

启动探针对于那些需要很长时间才能启动的容器的 Pod 很有用。你可以配置一个独立的配置来探测容器启动,而不是设置一个很长的活性间隔,允许的时间比活性间隔允许的时间更长。

如果你的容器通常在 \( initialDelaySeconds + failureThreshold \times periodSeconds \) 之外启动,你应该指定一个启动探针,该探针检查与活性探针相同的端点。periodSeconds 的默认值为 10 秒。然后,你应该将其 failureThreshold 设置得足够高,以允许容器启动,而无需更改活性探针的默认值。这有助于防止死锁。

Pod 的终止

由于 Pod 代表在集群节点上运行的进程,因此在不再需要这些进程时允许它们优雅地终止(而不是被 KILL 信号突然停止而没有机会进行清理)非常重要。

设计目标是让你能够请求删除并知道进程何时终止,同时也能确保删除最终完成。当你请求删除 Pod 时,集群会记录并跟踪允许 Pod 被强制终止之前的预期宽限期。有了这种强制关闭跟踪,kubelet 会尝试优雅关闭。

通常,在 Pod 优雅终止时,kubelet 会向容器运行时发出请求,尝试通过首先向每个容器中的主进程发送 TERM(也称为 SIGTERM)信号(带有宽限期超时)来停止 Pod 中的容器。停止容器的请求由容器运行时异步处理。无法保证这些请求的处理顺序。许多容器运行时会遵守容器镜像中定义的 STOPSIGNAL 值,如果不同,则发送容器镜像配置的 STOPSIGNAL 而不是 TERM。一旦宽限期过期,KILL 信号将发送给任何剩余的进程,然后 Pod 将从 API 服务器中删除。如果在等待进程终止时 kubelet 或容器运行时的管理服务重新启动,则集群会从头开始重试,包括完整的原始宽限期。

停止信号

用于杀死容器的停止信号可以在容器镜像中使用 STOPSIGNAL 指令定义。如果镜像中没有定义停止信号,则将使用容器运行时的默认信号(containerd 和 CRI-O 均为 SIGTERM)来杀死容器。

定义自定义停止信号

特性状态: `Kubernetes v1.33 [alpha]`(默认启用:false)

如果启用了 ContainerStopSignals 功能门控,你可以从容器生命周期中为容器配置自定义停止信号。我们要求 Pod 的 spec.os.name 字段作为在容器生命周期中定义停止信号的要求。有效信号列表取决于 Pod 调度到的操作系统。对于调度到 Windows 节点的 Pod,我们仅支持 SIGTERM 和 SIGKILL 作为有效信号。

以下是一个定义自定义停止信号的 Pod 规范示例:

spec:
  os:
    name: linux
  containers:
    - name: my-container
      image: container-image:latest
      lifecycle:
        stopSignal: SIGUSR1

如果在生命周期中定义了停止信号,它将覆盖容器镜像中定义的信号。如果容器规范中没有定义停止信号,容器将回退到默认行为。

Pod 终止流程

Pod 终止流程,以一个示例说明:

  1. 你使用 kubectl 工具手动删除一个特定的 Pod,使用默认宽限期(30 秒)。

  2. API 服务器中的 Pod 会更新为 Pod 被视为“已死”的时间以及宽限期。如果你使用 kubectl describe 检查你正在删除的 Pod,该 Pod 将显示为“Terminating”。在 Pod 运行的节点上:一旦 kubelet 发现 Pod 被标记为终止(已设置优雅关机持续时间),kubelet 就会开始本地 Pod 关机过程。

    1. 如果 Pod 的某个容器定义了 preStop 钩子,并且 Pod 规范中的 terminationGracePeriodSeconds 未设置为 0,kubelet 将在容器内部运行该钩子。默认的 terminationGracePeriodSeconds 设置为 30 秒。

      如果 preStop 钩子在宽限期过期后仍在运行,kubelet 会请求一个小的、一次性的 2 秒宽限期延长。

    2. kubelet 触发容器运行时向每个容器内的进程 1 发送 TERM 信号。

      如果 Pod 定义了任何边车容器,则存在特殊的顺序。否则,Pod 中的容器会在不同的时间以任意顺序接收 TERM 信号。如果关闭顺序很重要,请考虑使用 preStop 钩子进行同步(或切换为使用边车容器)。

  3. 在 kubelet 开始 Pod 优雅关闭的同时,控制平面评估是否从 EndpointSlice 对象中移除该正在关闭的 Pod,这些对象代表具有已配置选择器服务ReplicaSets 和其他工作负载资源不再将正在关闭的 Pod 视为有效、在服务中的副本。

    缓慢关闭的 Pod 不应继续处理常规流量,而应开始终止并完成处理打开的连接。有些应用程序需要超越完成打开的连接,需要更优雅的终止,例如会话排空和完成。

    表示终止 Pod 的任何端点不会立即从 EndpointSlices 中移除,并且 EndpointSlice API 会公开指示终止状态的状态。终止中的端点始终将其 ready 状态设置为 false(为了向后兼容 1.26 之前的版本),因此负载均衡器将不会将其用于常规流量。

    如果需要对终止中的 Pod 进行流量排空,则实际就绪状态可以作为条件 serving 进行检查。有关如何实现连接排空的更多详细信息,请参阅教程Pod 和端点终止流程

  4. kubelet 确保 Pod 已关闭并终止:

    1. 当宽限期过期时,如果 Pod 中仍有任何容器正在运行,kubelet 将触发强制关闭。容器运行时将 SIGKILL 发送给 Pod 中任何容器中仍在运行的进程。如果容器运行时使用了隐藏的 pause 容器,kubelet 也会清理该容器。
    2. kubelet 将 Pod 转换为终止阶段(根据其容器的最终状态,可以是 FailedSucceeded)。
    3. kubelet 通过将宽限期设置为 0(立即删除)来强制从 API 服务器中删除 Pod 对象。
    4. API 服务器删除 Pod 的 API 对象,此后任何客户端都无法再看到该对象。

强制 Pod 终止

默认情况下,所有删除操作均在 30 秒内优雅完成。kubectl delete 命令支持 --grace-period=<seconds> 选项,允许你覆盖默认值并指定自己的值。

将宽限期设置为 0 会强制并立即从 API 服务器中删除 Pod。如果 Pod 仍在节点上运行,则强制删除会触发 kubelet 开始立即清理。

使用 kubectl,你必须同时指定 --force 标志和 --grace-period=0 才能执行强制删除。

当执行强制删除时,API 服务器不会等待 kubelet 确认 Pod 已在其运行的节点上终止。它会立即在 API 中删除 Pod,以便可以使用相同的名称创建新的 Pod。在节点上,设置为立即终止的 Pod 仍将在被强制杀死之前获得一个短暂的宽限期。

如果你需要强制删除 StatefulSet 中的 Pod,请参阅从 StatefulSet 中删除 Pod 的任务文档。

Pod 关机和 Sidecar 容器

如果你的 Pod 包含一个或多个Sidecar 容器(restart 策略为 Always 的 init 容器),kubelet 将延迟向这些 Sidecar 容器发送 TERM 信号,直到最后一个主容器完全终止。Sidecar 容器将按照它们在 Pod 规范中定义的相反顺序终止。这确保了 Sidecar 容器在不再需要之前继续为 Pod 中的其他容器提供服务。

这意味着主容器的缓慢终止也会延迟 Sidecar 容器的终止。如果宽限期在终止过程完成之前到期,Pod 可能会进入强制终止。在这种情况下,Pod 中所有剩余的容器将以短暂的宽限期同时终止。

同样,如果 Pod 有一个超出终止宽限期的 preStop 钩子,可能会发生紧急终止。通常,如果你在没有 Sidecar 容器的情况下使用 preStop 钩子来控制终止顺序,你现在可以删除它们,让 kubelet 自动管理 Sidecar 终止。

Pod 的垃圾回收

对于失败的 Pod,API 对象会保留在集群的 API 中,直到人工或控制器进程明确将其移除。

Pod 垃圾回收器(PodGC)是控制平面中的一个控制器,当 Pod 数量超过配置的阈值(由 kube-controller-manager 中的 terminated-pod-gc-threshold 决定)时,它会清理已终止的 Pod(SucceededFailed 状态)。这可以避免随着 Pod 的创建和终止而导致的资源泄漏。

此外,PodGC 会清理满足以下任一条件的 Pod:

  1. 孤儿 Pod - 绑定到不再存在的节点,
  2. 未调度且正在终止的 Pod,
  3. 正在终止的 Pod,绑定到一个不就绪且被 node.kubernetes.io/out-of-service 污点标记的节点。

除了清理 Pod 之外,如果 Pod 处于非终止阶段,PodGC 还会将其标记为失败。此外,PodGC 在清理孤儿 Pod 时会添加一个 Pod 中断条件。有关更多详细信息,请参阅Pod 中断条件

下一步

上次修改时间为 2025 年 7 月 1 日太平洋标准时间晚上 10:39:添加容器重启规则文档 (5a0ebb3aa7)