本页面描述 Pod 的生命周期。Pod 遵循明确的生命周期,从 Pending(挂起)阶段开始,如果至少一个主容器启动成功,则进入 Running(运行中)阶段,之后根据 Pod 中的任何容器是否因故障而终止,进入 Succeeded(成功)或 Failed(失败)阶段。
当 Pod 运行时,kubelet 管理容器并将 Pod 的规约(Spec)转换为容器运行时的指令。kubelet 还负责执行探针来跟踪应用程序的健康状况。
与独立的应用程序容器一样,Pod 被视为相对短暂(而非持久)的实体。Pod 被创建、分配一个唯一的 ID(UID),并被调度到节点上运行,直到终止(根据重启策略)或删除。如果某个 节点 宕机,在该节点上运行(或计划运行)的 Pod 将被标记为删除。控制平面在超时后会将这些 Pod 标记为移除。
当 Pod 运行时,kubelet 能够重启容器以处理某些故障。在 Pod 内,Kubernetes 会跟踪不同的容器状态,并确定采取何种操作使 Pod 恢复健康。这是通过一个轮询循环完成的,该循环定期将期望状态(Pod 规约)与正在运行的容器的实际状态进行调节。由于这种轮询机制,API 中显示的状态(例如 kubectl get pod)相比节点上的即时状态可能会有轻微延迟。
在 Kubernetes API 中,Pod 既有规约(Specification)也有实际状态。Pod 对象的状态由一组 Pod 条件组成。如果对您的应用程序有用,您还可以将自定义就绪信息注入到 Pod 的条件数据中。
Pod 在其生命周期中只被调度一次;将 Pod 分配到特定节点称为*绑定*,而选择节点的进程称为*调度*。一旦 Pod 被调度并绑定到节点,Kubernetes 就会尝试在该节点上运行该 Pod。Pod 会在该节点上运行直到停止,或者直到 Pod 被终止;如果 Kubernetes 无法在所选节点上启动 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 因任何原因被删除,即使创建了一个完全相同的替换品,相关的事物(在此例中为存储卷)也会被销毁并重新创建。
一个多容器 Pod,包含一个文件拉取边车(Sidecar)容器和一个 Web 服务器。Pod 使用临时 emptyDir 卷在容器之间共享存储。
Pod 的 status 字段是一个 PodStatus 对象,其中包含一个 phase 字段。
Pod 的阶段是对 Pod 生命周期所处位置的简单、高级别的总结。该阶段并非旨在全面总结容器或 Pod 状态的观察结果,也不旨在成为一个全面的状态机。
Pod 阶段值的数量和含义受到严格限制。除此处记录的内容外,不应假设 Pod 具有给定的 phase 值。
以下是 phase 的可选值:
| 值 | 描述 |
|---|---|
Pending(挂起) | Pod 已被 Kubernetes 集群接受,但尚未设置好一个或多个容器,也未准备好运行。这包括 Pod 等待被调度的时间,以及通过网络下载容器镜像的时间。 |
Running(运行中) | Running(运行中) |
Succeeded(成功) | Pod 中的所有容器都已成功终止,且不会被重启。 |
Failed(失败) | Pod 中的所有容器都已终止,且至少有一个容器终止失败。也就是说,容器要么以非零状态退出,要么被系统终止,且未设置为自动重启。 |
Unknown(未知) | 由于某些原因,无法获取 Pod 的状态。此阶段通常是因为与 Pod 应当运行的节点通信出现错误所致。 |
当 Pod 反复无法启动时,某些 kubectl 命令的 Status 字段中可能会显示 CrashLoopBackOff。同样,当 Pod 被删除时,某些 kubectl 命令的 Status 字段中可能会显示 Terminating。
确保不要将 Status(一个用于用户直觉的 kubectl 显示字段)与 Pod 的 phase 混淆。Pod 阶段是 Kubernetes 数据模型和 Pod API 的明确组成部分。
NAMESPACE NAME READY STATUS RESTARTS AGE
alessandras-namespace alessandras-pod 0/1 CrashLoopBackOff 200 2d9h
Pod 被授予一个优雅终止的期限,默认为 30 秒。您可以使用 --force 标志来强制终止 Pod。
从 Kubernetes 1.27 开始,kubelet 会在从 API 服务器删除已删除的 Pod 之前,将其转换为终端阶段(Failed 或 Succeeded,具体取决于 Pod 容器的退出状态),但有两个例外:
如果节点宕机或与集群其他部分断开连接,Kubernetes 会应用策略,将失联节点上所有 Pod 的 phase 设置为 Failed。
除了整个 Pod 的 阶段 外,Kubernetes 还跟踪 Pod 内每个容器的状态。您可以使用 容器生命周期钩子 来触发在容器生命周期特定点运行的事件。
一旦 调度器 将 Pod 分配给节点,kubelet 就会使用 容器运行时 开始为该 Pod 创建容器。共有三种可能的容器状态:Waiting、Running 和 Terminated。
要查看 Pod 容器的状态,可以使用 kubectl describe pod <pod名称>。输出将显示该 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 状态之前运行。
Kubernetes 使用 Pod spec 中定义的 restartPolicy 来管理 Pod 内的容器故障。该策略决定了 Kubernetes 对由于错误或其他原因退出的容器所做出的反应,序列如下:
restartPolicy 尝试立即重启。restartPolicy。这可以防止频繁、反复的重启尝试导致系统过载。实际上,当 Pod 中的容器无法正常启动并在循环中不断尝试失败时,CrashLoopBackOff 是一个可以在描述或列出 Pod 时作为 kubectl 命令输出显示的条件或事件。
换句话说,当容器进入崩溃循环时,Kubernetes 会应用 容器重启策略 中提到的指数退避延迟。这种机制防止了有故障的容器因持续失败的启动尝试而压垮系统。
CrashLoopBackOff 可能由以下问题导致:
Failure 结果,正如 探针章节 中所提。要调查 CrashLoopBackOff 问题的根本原因,用户可以:
kubectl logs <pod名称> 查看容器日志。这通常是诊断导致崩溃的最直接方式。kubectl describe pod <pod名称> 查看 Pod 的事件,这些事件可以提供有关配置或资源问题的线索。当 Pod 中的容器停止或遇到故障时,Kubernetes 可以重启它。重启并不总是适用的;例如,初始化容器(init containers) 在 Pod 启动时只运行一次(如果成功)。您可以将重启配置为应用于所有 Pod 的策略,或者使用容器级配置(例如:定义 边车容器(sidecar container) 时)或定义容器级覆盖。
Kubernetes 项目建议遵循云原生原则,包括考虑到突发或任意重启的弹性设计。您可以通过让 Pod 失败并依赖自动替换,或者设计容器级弹性来实现这一点。这两种方法都有助于确保您的整体工作负载在部分失败的情况下依然可用。
Pod 的 spec 中有一个 restartPolicy 字段,可选值为 Always、OnFailure 和 Never。默认值为 Always。
Pod 的 restartPolicy 适用于 Pod 中的应用容器(app containers)以及常规的 初始化容器。边车容器(Sidecar containers) 会忽略 Pod 级的 restartPolicy 字段:在 Kubernetes 中,边车定义为 initContainers 中的一个条目,其容器级 restartPolicy 设置为 Always。对于因错误退出的初始化容器,如果 Pod 级的 restartPolicy 为 OnFailure 或 Always,kubelet 会重启该初始化容器。
Always:在任何终止后自动重启容器。OnFailure:仅在容器因错误(非零退出状态)退出时重启。Never:不自动重启终止的容器。下表显示了容器在不同重启策略和退出代码下的行为:
| 退出代码 | restartPolicy: Always | restartPolicy: OnFailure | restartPolicy: Never | Sidecar 容器 |
|---|---|---|---|---|
| 0 (成功) | 重启 | 不重启 | 不重启 | 总是重启 |
| 非零 (失败) | 重启 | 重启 | 不重启 | 总是重启 |
当在 Deployment 和 Job 之间进行选择时,重启行为尤为重要:
restartPolicy: Always(唯一允许的值),以保持应用程序持续运行。restartPolicy: OnFailure 或 restartPolicy: Never 来适当地处理批处理任务。restartPolicy 如何,因为它们有自己的容器级 restartPolicy: Always。以下是演示不同重启行为的具体示例:
示例 1:Web 服务器,restartPolicy: Always(Deployment 的典型配置)
apiVersion: v1
kind: Pod
metadata:
name: web-server
spec:
restartPolicy: Always # Container restarts regardless of exit code
containers:
- name: nginx
image: nginx:1.14.2
# If this container crashes or exits for any reason, it will be restarted
示例 2:批处理任务,restartPolicy: OnFailure
apiVersion: batch/v1
kind: Job
metadata:
name: data-processor
spec:
template:
spec:
restartPolicy: OnFailure # Only restart on non-zero exit codes
containers:
- name: processor
image: busybox:1.28
command: ['sh', '-c', 'echo "Processing data..."; exit 0']
# Exit code 0: Job completes successfully, no restart
# Exit code 1+: Container restarts to retry the task
示例 3:一次性任务,restartPolicy: Never
apiVersion: v1
kind: Pod
metadata:
name: migration-task
spec:
restartPolicy: Never # Never restart, regardless of exit code
containers:
- name: migrate
image: busybox:1.28
command: ['sh', '-c', 'echo "Running migration..."; exit 1']
# Even with exit code 1 (failure), the container will not restart
# The Pod will remain in Failed state
边车容器(Sidecar containers) 具有特殊的重启行为,与常规应用容器不同:
restartPolicy:它们使用自己的容器级 restartPolicy 字段,该字段始终设置为 Always。示例:带有边车容器的 Pod
apiVersion: v1
kind: Pod
metadata:
name: app-with-sidecar
spec:
restartPolicy: OnFailure # Applies to main container only
initContainers:
- name: logging-sidecar # This is a sidecar container
image: fluent/fluent-bit:1.8
restartPolicy: Always # Sidecar always restarts regardless of exit code
# Provides logging services throughout Pod lifetime
containers:
- name: main-app # This follows Pod-level restartPolicy
image: nginx:1.14.2
# Will only restart on failure (non-zero exit) due to Pod's OnFailure policy
restartPolicy: OnFailure,但边车容器无论其退出代码如何都会重启,因为边车容器在容器级始终具有 restartPolicy: Always。当 kubelet 根据配置的重启策略处理容器重启时,这仅适用于在同一 Pod 内、同一节点上进行替换容器的重启。在 Pod 中的容器退出后,kubelet 会以指数退避延迟(10s、20s、40s,……)重启它们,上限为 300 秒(5 分钟)。一旦容器毫无问题地运行了 10 分钟,kubelet 就会重置该容器的重启退避计时器。边车容器与 Pod 生命周期 解释了在 init containers 上指定 restartPolicy 字段时的行为。
Kubernetes v1.35 [beta](默认启用)如果您的集群启用了特性门控 ContainerRestartRules,您可以为个体容器指定 restartPolicy 和 restartPolicyRules,以覆盖 Pod 的重启策略。个体容器重启策略与规则适用于 Pod 中的应用容器和常规的 初始化容器。
Kubernetes 原生边车容器的容器级 restartPolicy 设置为 Always。
容器重启将遵循与上述 Pod 重启策略相同的指数退避。支持的容器重启策略:
Always:在任何终止后自动重启容器。OnFailure:仅在容器因错误(非零退出状态)退出时重启。Never:不自动重启终止的容器。此外,个体容器可以指定 restartPolicyRules。如果指定了 restartPolicyRules 字段,则容器的 restartPolicy 也必须指定。restartPolicyRules 定义了一组应用于容器退出时的规则。每条规则由一个条件和一个动作组成。支持的条件为 exitCodes,它将容器的退出代码与给定的值列表进行比较。支持的动作是 Restart,意味着容器将被重启。规则将按顺序评估。一旦匹配成功,就会应用该动作。如果没有规则匹配,Kubernetes 将回退到容器配置的 restartPolicy。
例如,一个具有 OnFailure 重启策略且包含一个 try-once 容器的 Pod。这允许 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: registry.k8s.io/busybox:1.27.2
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: registry.k8s.io/busybox:1.27.2
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: registry.k8s.io/busybox:1.27.2
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: registry.k8s.io/busybox:1.27.2
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: registry.k8s.io/busybox:1.27.2
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.36 [beta](默认启用)如果您的集群启用了特性门控 RestartAllContainersOnContainerExits,您可以在容器级别的 restartPolicyRules 中指定 RestartAllContainers 作为动作。当容器的退出匹配具有此动作的规则时,整个 Pod 将被终止并原地重启。
这种“原地”重启提供了一种比完全删除和重建更有效的重置 Pod 状态的方法。对于重新调度成本高昂的工作负载(如批处理任务或 AI/ML 训练任务)来说,这一点尤为宝贵。
当触发 RestartAllContainers 动作时,kubelet 执行以下步骤:
快速终止:Pod 中的所有运行容器都被终止。配置的 terminationGracePeriodSeconds 不会被遵循,且任何配置的 preStop 钩子都不会执行。这确保了快速关闭。
Pod 资源保留:Pod 的核心资源得到保留:
emptyDir 和挂载的卷。Pod 状态更新:Pod 的状态被更新,PodRestartInPlace 条件被设置为 True。这使得重启过程可观察。
完整重启序列:一旦所有容器都被终止,PodRestartInPlace 条件被设置为 False,Pod 开始标准启动过程:
此特性的一个关键点是:所有容器都会被重启,包括那些先前已成功完成或失败的容器。RestartAllContainers 动作会覆盖任何已配置的容器级或 Pod 级 restartPolicy。
该机制在需要为所有容器提供“净室”环境的情况下非常有用,例如:
init 容器设置的环境可能变得损坏时,此特性确保重新执行设置过程。考虑一个工作负载,其中守护边车容器负责在主应用程序遇到错误时将其从已知的良好状态重启。守护容器可以以特定的代码退出,从而触发工作 Pod 的完全原地重启。
apiVersion: v1
kind: Pod
metadata:
name: ml-worker
spec:
restartPolicy: Never # The pod itself should not restart unless explicitly told to.
initContainers:
- name: setup-environment
image: registry.k8s.io/busybox:1.27.2
command: ['sh', '-c', 'echo "Setting up environment"']
# This init container runs once to prepare the environment.
# It will run again after a RestartAllContainers action.
- name: watcher-sidecar
image: registry.k8s.io/busybox:1.27.2
# In a real-world scenario, this would be a dedicated watcher image.
# This command simulates the watcher exiting with a special code.
command: ['sh', '-c', 'sleep 60; exit 88']
restartPolicy: Always
restartPolicyRules:
- action: RestartAllContainers
exitCodes:
# Exit code 88 triggers a full pod restart.
operator: In
values: [88]
containers:
- name: main-application
image: registry.k8s.io/busybox:1.27.2
command: ['sh', '-c', 'echo "Application is running"; sleep 3600']
在本例中
restartPolicy 为 Never。watcher-sidecar 运行一个命令,然后以代码 88 退出。RestartAllContainers 动作。setup-environment 初始化容器和 main-application 容器)随后被原地重启。Pod 保留其 UID、沙盒、IP 和卷。Kubernetes v1.33 [alpha](默认禁用)开启 alpha 特性门控 ReduceDefaultCrashLoopBackOffDecay 后,集群范围内的容器启动重试将减少为从 1s 开始(原为 10s),并每次重启指数级增加 2 倍,直到达到 60s 的最大延迟(原为 300s,即 5 分钟)。
如果您将此功能与 alpha 特性 KubeletCrashLoopBackOffMax(见下文)一起使用,则各个节点可能具有不同的最大延迟。
Kubernetes v1.35 [beta](默认启用)开启特性门控 KubeletCrashLoopBackOffMax 后,您可以重新配置容器启动重试之间的最大延迟(默认 300s,即 5 分钟)。此配置通过 kubelet 配置按节点设置。在您的 kubelet 配置 中,在 crashLoopBackOff 下设置 maxContainerRestartPeriod 字段,范围在 "1s" 到 "300s" 之间。如上文 容器重启策略 所述,该节点上的延迟仍将从 10s 开始并每次重启指数级增加 2 倍,但上限将为您配置的最大值。如果您配置的 maxContainerRestartPeriod 小于默认初始值 10s,则初始延迟将设为配置的最大值。
请参见以下 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(见上文)一起使用,您的集群默认初始退避和最大退避将不再是 10s 和 300s,而是 1s 和 60s。节点级配置优先于由 ReduceDefaultCrashLoopBackOffDecay 设置的默认值,即使这会导致该节点的最大退避时间长于集群中其他节点。
Pod 具有 PodStatus,其中包含一组 PodConditions,Pod 通过这些条件表明其是否通过了测试。kubelet 管理以下 PodConditions:
PodScheduled:Pod 已被调度到节点。PodReadyToStartContainers:(beta 特性;默认启用)Pod 沙盒已成功创建,网络已配置,存储卷已挂载,且所有动态资源(如果请求)已分配。ContainersReady:Pod 中的所有容器都已就绪。Initialized:所有 初始化容器 都已成功完成。Ready:Pod 能够服务请求,并应被添加到所有匹配的服务(Services)的负载均衡池中。DisruptionTarget:由于中断(例如抢占、驱逐或垃圾收集),Pod 即将被终止。PodResizePending:请求了 Pod 调整大小,但无法应用。请参阅 Pod 调整大小状态。PodResizeInProgress:Pod 正在调整大小过程中。请参阅 Pod 调整大小状态。| 字段名称 | 描述 |
|---|---|
type | 此 Pod 条件的名称。 |
status | 指示该条件是否适用,可能的值为 "True"、"False" 或 "Unknown"。 |
lastProbeTime | 上次探测 Pod 条件的时间戳。 |
lastTransitionTime | Pod 上次从一个状态转换到另一个状态的时间戳。 |
reason | 机器可读的 UpperCamelCase 文本,指示条件上次转换的原因。 |
message | 人类可读的消息,指示关于上次状态转换的详细信息。 |
Kubernetes v1.14 [稳定]您的应用程序可以将额外反馈或信号注入 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 标签键格式 的名称。
kubectl patch 命令不支持修补对象状态。要为 Pod 设置这些 status.conditions,应用程序和 Operator 应使用 PATCH 动作。您可以使用 Kubernetes 客户端库 编写代码来设置 Pod 就绪性的自定义 Pod 条件。
对于使用自定义条件的 Pod,仅当以下两个陈述均成立时,该 Pod 才被评估为就绪:
readinessGates 中指定的所有条件均为 True。当 Pod 的容器就绪但至少有一个自定义条件缺失或为 False 时,kubelet 会将 Pod 的 条件 设置为 ContainersReady。
Kubernetes v1.29 [beta]PodHasNetwork。在 Pod 被调度到节点上之后,它需要被 kubelet 接纳并挂载任何必要的存储卷。一旦这些阶段完成,kubelet 会与容器运行时(使用 容器运行时接口 (CRI))配合,建立运行时沙盒并为 Pod 配置网络。如果 Pod 使用 动态资源分配 (Dynamic Resource Allocation),则在此时也会分配这些资源。如果启用了 PodReadyToStartContainersCondition 特性门控(Kubernetes 1.36 默认启用),PodReadyToStartContainers 条件将被添加到 Pod 的 status.conditions 字段中。
当 kubelet 检测到 Pod 没有配置网络的运行时沙盒时,它会将 PodReadyToStartContainers 条件设置为 False。这发生在以下场景:
沙盒创建、网络配置、卷挂载和(如果请求)动态资源分配完成后,kubelet 将 PodReadyToStartContainers 条件设置为 True。镜像拉取和容器创建在此之后发生。
对于带有初始化容器的 Pod,kubelet 在初始化容器成功完成后将 Initialized 条件设置为 True(这发生在运行时插件成功创建沙盒并配置网络之后)。对于没有初始化容器的 Pod,kubelet 在沙盒创建和网络配置开始之前将 Initialized 条件设置为 True。
Kubernetes v1.35 [stable](默认启用)Kubernetes v1.36 [beta](默认启用)Kubernetes 支持在 Pod 创建后更改分配给它们的 CPU 和内存资源。(对于其他基础设施资源,您需要使用特定于这些资源的技术。)调整 CPU 和内存大小主要有两种方法:
您可以在不重新创建 Pod 的情况下调整 Pod 的容器级 CPU 和内存资源。这也被称为原地 Pod 垂直扩缩容(in-place Pod vertical scaling)。这允许您调整运行中容器的资源分配,同时可能避免应用程序中断。
如果您已经在 Pod 级指定了资源,也可以原地调整它们。有关详细信息,请参阅 调整分配给 Pod 的 CPU 和内存资源。
要执行原地调整大小,您可以使用 /resize 子资源更新 Pod 的期望状态。kubelet 随后会尝试将新的资源值应用到运行中的容器上。Pod 条件 PodResizePending 和 PodResizeInProgress(详见 Pod 条件)指示调整大小操作的状态。有关调整大小状态的更多详情,请参阅 容器调整大小状态。
原地调整大小的关键注意事项:
resizePolicy 来配置调整大小是否需要重启容器。有关执行原地调整大小的详细指南,请参阅 调整分配给容器的 CPU 和内存资源。
更改 Pod 资源更符合云原生方法的方式是通过管理它的工作负载资源(如 Deployment 或 StatefulSet)。当您更新 Pod 模板中的资源规约时,工作负载控制器会使用更新后的资源创建新的 Pod,并根据其更新策略终止旧的 Pod。
这种方法:
您还可以使用 VerticalPodAutoscaler 来自动管理 Pod 资源建议和更新。
探针(Probe) 是由 kubelet 对容器定期执行的诊断。为了执行诊断,kubelet 可以在容器内执行代码,或者发起网络请求。
有四种使用探针检查容器的不同方法。每个探针必须且仅能定义以下四种机制中的一种:
execgrpcstatus 为 SERVING,则认为诊断成功。httpGetGET 请求。如果响应状态码大于或等于 200 且小于 400,则认为诊断成功。有关 kubelet 如何处理重定向的详细信息,请参阅 配置探针。tcpSocketexec 探针的实现涉及每次执行时创建/分叉多个进程。因此,在 Pod 密度较高的集群中,较低的 initialDelaySeconds 和 periodSeconds 间隔可能会给节点的 CPU 使用率带来开销。在此类场景中,请考虑使用其他探针机制以避免开销。每个探针都有三种结果之一:
Success(成功)Failure(失败)Unknown(未知)kubelet 可以选择对运行中的容器执行并响应三种类型的探针:
livenessProbeSuccess。readinessProbeFailure。如果容器未提供就绪探针,默认状态为 Success。startupProbeSuccess。有关如何设置存活、就绪或启动探针的更多信息,请参阅 配置存活、就绪和启动探针。
如果您的容器内的进程在遇到问题或变得不健康时能够自行崩溃,则不一定需要存活探针;kubelet 会根据 Pod 的 restartPolicy 自动执行正确的操作。
如果您希望容器在探针失败时被杀死并重启,请指定一个存活探针,并将 restartPolicy 设置为 Always 或 OnFailure。
如果您希望仅在探针成功时才开始向 Pod 发送流量,请指定就绪探针。在这种情况下,就绪探针可能与存活探针相同,但在规约中存在就绪探针意味着 Pod 启动时不会接收任何流量,仅在探针开始成功后才开始接收流量。
如果您希望容器能够自行停机进行维护,您可以指定一个检查特定于就绪性的端点的就绪探针,该端点与存活探针不同。
如果您的应用对后端服务有严格依赖,您可以同时实现存活和就绪探针。当应用自身健康时,存活探针通过;而就绪探针额外检查每个必需的后端服务是否可用。这有助于避免将流量引导到只能响应错误信息的 Pod。
如果您的容器在启动期间需要加载大量数据、配置文件或进行迁移,您可以使用 启动探针。但是,如果您想检测已失败的应用与仍在处理其启动数据的应用之间的区别,您可能更倾向于使用就绪探针。
EndpointSlice 中的相应端点将更新其 条件:端点的 ready 条件将被设置为 false,因此负载均衡器将不会将 Pod 用于常规流量。有关 kubelet 如何处理 Pod 删除的更多信息,请参阅 Pod 终止。启动探针(Startup probes)对于需要较长时间才能启动并进入服务状态的容器的 Pod 非常有用。与其设置较长的存活探针间隔,不如为容器启动配置一个单独的探针,从而允许比存活探针所允许的时间更长的启动时间。
如果你的容器通常在超过 \( initialDelaySeconds + failureThreshold \times periodSeconds \) 的时间内启动,你应该指定一个与存活探针检查相同端点的启动探针。periodSeconds 的默认值为 10 秒。然后,你应该将它的 failureThreshold 设置得足够高,以便在不更改存活探针默认值的情况下让容器启动。这有助于防止死锁。
因为 Pod 代表集群节点上运行的进程,所以当这些进程不再需要时,允许它们优雅地终止(而不是被 KILL 信号突然停止且没有机会清理)非常重要。
设计目标是让你能够请求删除并知道进程何时终止,同时也能够确保删除最终完成。当你请求删除一个 Pod 时,集群会记录并跟踪预期的宽限期,然后再允许强制杀死 Pod。有了这种强制关闭跟踪机制,kubelet 会尝试进行优雅的关闭。
通常,在 Pod 的这种优雅终止过程中,kubelet 会向容器运行时发出请求,尝试通过首先向每个容器中的主进程发送一个带有宽限期超时的 TERM(即 SIGTERM)信号来停止 Pod 中的容器。停止容器的请求由容器运行时异步处理。这些请求的处理顺序没有保证。许多容器运行时遵循容器镜像中定义的 STOPSIGNAL 值,如果不同,则发送容器镜像配置的 STOPSIGNAL 而不是 TERM。一旦宽限期到期,KILL 信号会被发送给任何剩余的进程,然后 Pod 会从 API Server 中删除。如果在等待进程终止时 kubelet 或容器运行时的管理服务重启,集群会从头开始重试,包括完整的原始宽限期。
用于杀死容器的停止信号可以在容器镜像中使用 STOPSIGNAL 指令定义。如果镜像中没有定义停止信号,将使用容器运行时的默认信号(containerd 和 CRI-O 均为 SIGTERM)来杀死容器。
Kubernetes v1.33 [alpha](默认禁用)如果启用了 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 终止流程,以一个示例说明
你使用 kubectl 工具手动删除一个特定的 Pod,并使用默认的宽限期(30 秒)。
API Server 中的 Pod 会更新 Pod 被视为“死亡”的时间以及宽限期。如果你使用 kubectl describe 来查看你正在删除的 Pod,该 Pod 会显示为“Terminating”(正在终止)。在 Pod 运行的节点上:一旦 kubelet 看到 Pod 被标记为正在终止(设置了优雅关闭持续时间),kubelet 就会开始本地 Pod 关闭流程。
如果 Pod 的容器之一定义了 preStop 钩子,并且 Pod 规范中的 terminationGracePeriodSeconds 没有设置为 0,kubelet 会在容器内运行该钩子。默认的 terminationGracePeriodSeconds 设置为 30 秒。
如果 preStop 钩子在宽限期届满后仍在运行,kubelet 会请求一次性延长 2 秒的短暂宽限期。
preStop 钩子需要比默认宽限期更长的时间才能完成,你必须相应地修改 terminationGracePeriodSeconds。kubelet 触发容器运行时向每个容器内的进程 1 发送 TERM 信号。
如果 Pod 定义了任何 Sidecar 容器,则存在特殊的顺序。否则,Pod 中的容器会在不同时间以任意顺序接收 TERM 信号。如果关闭顺序很重要,请考虑使用 preStop 钩子进行同步(或切换到使用 Sidecar 容器)。
在 kubelet 开始 Pod 优雅关闭的同时,控制平面会评估是否将该正在关闭的 Pod 从 EndpointSlice 对象中移除,这些对象代表了具有配置 选择器 的 Service。ReplicaSets 和其他工作负载资源不再将正在关闭的 Pod 视为有效的在线副本。
缓慢关闭的 Pod 不应继续处理常规流量,而应开始终止并完成正在处理的连接。有些应用程序需要超越完成打开的连接,并需要更优雅的终止,例如会话耗尽(draining)和完成。
任何代表正在终止的 Pod 的端点都不会立即从 EndpointSlice 中删除,并且 EndpointSlice API 会暴露指示 终止状态 的状态。正在终止的端点的 ready 状态始终为 false(为了向后兼容 1.26 之前的版本),因此负载均衡器不会将它们用于常规流量。
如果需要对正在终止的 Pod 进行流量耗尽,可以检查实际就绪状态作为 serving 条件。你可以在教程 Pod 和端点终止流程 中找到有关如何实现连接耗尽的更多详细信息。
默认情况下,所有删除操作都是在 30 秒内优雅完成的。kubectl delete 命令支持 --grace-period= 选项,允许你覆盖默认值并指定你自己的值。
将宽限期设置为 0 会强制并立即从 API Server 中删除 Pod。如果 Pod 当时仍在节点上运行,该强制删除会触发 kubelet 开始立即清理。
使用 kubectl 时,你必须在 --grace-period=0 的基础上额外指定 --force 标志,才能执行强制删除。
如果你需要强制删除属于 StatefulSet 的 Pod,请参考关于 从 StatefulSet 中删除 Pod 的任务文档。
如果你的 Pod 包含一个或多个 Sidecar 容器(具有 Always 重启策略的初始化容器),kubelet 将会延迟向这些 Sidecar 容器发送 TERM 信号,直到最后一个主容器完全终止。Sidecar 容器将按照它们在 Pod 规范中定义的顺序的相反顺序进行终止。这确保了 Sidecar 容器能够持续为 Pod 中的其他容器提供服务,直到它们不再被需要。
这意味着主容器的缓慢终止也会延迟 Sidecar 容器的终止。如果在终止过程完成之前宽限期届满,Pod 可能会进入强制终止。在这种情况下,Pod 中所有剩余的容器都将被同时终止,并获得一个短暂的宽限期。
类似地,如果 Pod 具有超出终止宽限期的 preStop 钩子,则可能会发生紧急终止。通常,如果你之前使用 preStop 钩子在没有 Sidecar 容器的情况下控制终止顺序,现在可以移除它们,并允许 kubelet 自动管理 Sidecar 终止。
对于失败的 Pod,API 对象会保留在集群的 API 中,直到人工或 控制器 进程显式将其删除。
Pod 垃圾收集器 (PodGC) 是控制平面中的一个控制器,当 Pod 数量超过配置的阈值(由 kube-controller-manager 中的 terminated-pod-gc-threshold 确定)时,它会清理已终止的 Pod(状态为 Succeeded 或 Failed)。这避免了随着时间的推移 Pod 创建和终止导致的资源泄漏。
此外,PodGC 会清理任何满足以下任一条件的 Pod:
node.kubernetes.io/out-of-service 标记且不可用的节点上。在清理 Pod 的同时,如果 Pod 处于非终止状态,PodGC 还会将其标记为失败。此外,PodGC 在清理孤儿 Pod 时会添加一个 Pod 中断条件。更多详细信息,请参阅 Pod 中断条件。
如果你重启 kubelet,Pod(及其容器)即使在重启期间也会继续运行。当节点上有正在运行的 Pod 时,停止或重启该节点上的 kubelet 不会导致 kubelet 在其自身停止之前停止所有本地 Pod。要停止节点上的 Pod,你可以使用 kubectl drain。
Kubernetes v1.35 [已弃用](默认禁用)当 kubelet 启动时,它会检查是否已经存在一个绑定了 Pod 的节点。如果节点的 Ready 条件保持不变,换句话说,条件没有从 true 变为 false,Kubernetes 会将其检测为 kubelet 重启。(可以通过其他方式重启 kubelet,例如修复节点错误,但在这些情况下,Kubernetes 会选择安全的选项,将其视为你先停止了 kubelet 然后又启动了它)。
当 kubelet 重启时,根据特性门控的设置,容器状态的管理方式会有所不同:
默认情况下,kubelet 在重启后不会更改容器状态。设置为 ready: true 状态的容器将保持就绪。
如果你停止 kubelet 的时间足够长,导致它无法通过一系列 节点心跳 检查,并且你在再次启动 kubelet 之前进行了等待,Kubernetes 可能会开始从该节点驱逐 Pod。然而,即使 Pod 驱逐开始发生,Kubernetes 也不会将这些 Pod 中的单个容器标记为 ready: false。Pod 级别的驱逐是在控制平面将节点污点标记为 node.kubernetes.io/not-ready(由于心跳失败)之后发生的。
在 Kubernetes 1.36 中,你可以选择启用一种遗留行为,即在 kubelet 重启后,kubelet 总是将容器的 ready 值修改为 false。
这种遗留行为长期以来是默认设置,但对于使用 Kubernetes 的用户,特别是在大规模部署中,导致了问题。虽然该特性门控允许暂时恢复此遗留行为,但 Kubernetes 项目建议如果你遇到问题,请提交 bug 报告。ChangeContainerStatusOnKubeletRestart 特性门控 将在未来被移除。
获取 将处理器附加到容器生命周期事件 的实践经验。
获取 配置存活、就绪和启动探针 的实践经验。
了解更多关于 容器生命周期钩子 的信息。
了解更多关于 Sidecar 容器 的信息。
有关 API 中 Pod 和容器状态的详细信息,请参阅涵盖 Pod status 的 API 参考文档。