容器生命周期钩子

此页面描述了 kubelet 管理的容器如何使用容器生命周期钩子框架来运行在容器管理生命周期中事件触发时触发的代码。

概述

类似于许多具有组件生命周期钩子的编程语言框架,例如 Angular,Kubernetes 为容器提供了生命周期钩子。 钩子使容器能够感知其管理生命周期中的事件,并在执行相应的生命周期钩子时运行在处理程序中实现的代码。

容器钩子

容器有两个钩子

PostStart

此钩子在创建容器后立即执行。 但是,无法保证钩子在容器 ENTRYPOINT 之前执行。 处理程序不传递任何参数。

PreStop

此钩子在由于 API 请求或管理事件(例如存活性/启动探测失败、抢占、资源争用等)导致容器终止之前立即调用。 如果容器已处于终止或已完成状态,则调用 PreStop 钩子将失败,并且必须在发送 TERM 信号以停止容器之前完成钩子。 在执行 PreStop 钩子之前,Pod 的终止宽限期倒计时开始,因此无论处理程序的结果如何,容器最终都会在 Pod 的终止宽限期内终止。 处理程序不传递任何参数。

有关终止行为的更详细描述,请参阅 Pod 终止

钩子处理程序实现

容器可以通过为该钩子实现和注册处理程序来访问钩子。 容器可以为三个类型的钩子处理程序实现

  • Exec - 在容器的 cgroups 和命名空间内执行特定命令,例如 pre-stop.sh。 命令消耗的资源计入容器。
  • HTTP - 对容器上的特定端点执行 HTTP 请求。
  • Sleep - 将容器暂停指定持续时间。 这是由 PodLifecycleSleepAction 特性开关 默认启用的测试版功能。

钩子处理程序执行

当调用容器生命周期管理钩子时,Kubernetes 管理系统根据钩子操作执行处理程序,httpGettcpSocketsleep 由 kubelet 进程执行,exec 在容器中执行。

当创建容器时,会启动 PostStart 钩子处理程序调用,这意味着容器 ENTRYPOINT 和 PostStart 钩子同时触发。 但是,如果 PostStart 钩子执行时间过长或挂起,它可能会阻止容器转换为 运行中 状态。

PreStop 钩子不会与停止容器的信号异步执行;钩子必须在发送 TERM 信号之前完成其执行。 如果 PreStop 钩子在执行期间挂起,则 Pod 的阶段将为 终止中,并保持该状态,直到 Pod 在其 terminationGracePeriodSeconds 到期后被杀死。 此宽限期适用于 PreStop 钩子执行和容器正常停止所花费的总时间。 例如,如果 terminationGracePeriodSeconds 为 60,并且钩子执行时间为 55 秒,并且容器在收到信号后正常停止时间为 10 秒,那么容器将在能够正常停止之前被杀死,因为 terminationGracePeriodSeconds 小于这两者发生所需的总时间(55+10)。

如果 PostStartPreStop 钩子失败,则会杀死容器。

用户应使他们的钩子处理程序尽可能轻量级。 但是,在某些情况下,长时间运行的命令是有意义的,例如在停止容器之前保存状态时。

钩子传递保证

钩子传递旨在为 至少一次,这意味着对于任何给定事件,钩子可能会被调用多次,例如 PostStartPreStop。 钩子实现负责正确处理这种情况。

通常,只进行一次传递。 例如,如果 HTTP 钩子接收器处于关闭状态,无法接收流量,则不会尝试重新发送。 但是,在某些极少数情况下,可能会发生双重传递。 例如,如果 kubelet 在发送钩子的过程中重新启动,则 kubelet 恢复后可能会重新发送钩子。

调试钩子处理程序

钩子处理程序的日志不会在 Pod 事件中公开。 如果处理程序由于某种原因失败,它会广播事件。 对于 PostStart,这是 FailedPostStartHook 事件,对于 PreStop,这是 FailedPreStopHook 事件。 为了自己生成失败的 FailedPostStartHook 事件,请修改 lifecycle-events.yaml 文件,将 postStart 命令更改为 "badcommand" 并应用它。 以下是运行 kubectl describe pod lifecycle-demo 时看到的生成的事件的一些示例输出

Events:
  Type     Reason               Age              From               Message
  ----     ------               ----             ----               -------
  Normal   Scheduled            7s               default-scheduler  Successfully assigned default/lifecycle-demo to ip-XXX-XXX-XX-XX.us-east-2...
  Normal   Pulled               6s               kubelet            Successfully pulled image "nginx" in 229.604315ms
  Normal   Pulling              4s (x2 over 6s)  kubelet            Pulling image "nginx"
  Normal   Created              4s (x2 over 5s)  kubelet            Created container lifecycle-demo-container
  Normal   Started              4s (x2 over 5s)  kubelet            Started container lifecycle-demo-container
  Warning  FailedPostStartHook  4s (x2 over 5s)  kubelet            Exec lifecycle hook ([badcommand]) for Container "lifecycle-demo-container" in Pod "lifecycle-demo_default(30229739-9651-4e5a-9a32-a8f1688862db)" failed - error: command 'badcommand' exited with 126: , message: "OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: \"badcommand\": executable file not found in $PATH: unknown\r\n"
  Normal   Killing              4s (x2 over 5s)  kubelet            FailedPostStartHook
  Normal   Pulled               4s               kubelet            Successfully pulled image "nginx" in 215.66395ms
  Warning  BackOff              2s (x2 over 3s)  kubelet            Back-off restarting failed container

下一步

上次修改时间:2024 年 6 月 7 日下午 4:54 PST:更新 container-lifecycle-hooks.md (16e3ad4bae)