容器生命周期钩子
此页面描述了 kubelet 管理的容器如何使用容器生命周期钩子框架来运行在容器管理生命周期中事件触发时触发的代码。
概述
类似于许多具有组件生命周期钩子的编程语言框架,例如 Angular,Kubernetes 为容器提供了生命周期钩子。 钩子使容器能够感知其管理生命周期中的事件,并在执行相应的生命周期钩子时运行在处理程序中实现的代码。
容器钩子
容器有两个钩子
PostStart
此钩子在创建容器后立即执行。 但是,无法保证钩子在容器 ENTRYPOINT 之前执行。 处理程序不传递任何参数。
PreStop
此钩子在由于 API 请求或管理事件(例如存活性/启动探测失败、抢占、资源争用等)导致容器终止之前立即调用。 如果容器已处于终止或已完成状态,则调用 PreStop
钩子将失败,并且必须在发送 TERM 信号以停止容器之前完成钩子。 在执行 PreStop
钩子之前,Pod 的终止宽限期倒计时开始,因此无论处理程序的结果如何,容器最终都会在 Pod 的终止宽限期内终止。 处理程序不传递任何参数。
有关终止行为的更详细描述,请参阅 Pod 终止。
钩子处理程序实现
容器可以通过为该钩子实现和注册处理程序来访问钩子。 容器可以为三个类型的钩子处理程序实现
- Exec - 在容器的 cgroups 和命名空间内执行特定命令,例如
pre-stop.sh
。 命令消耗的资源计入容器。 - HTTP - 对容器上的特定端点执行 HTTP 请求。
- Sleep - 将容器暂停指定持续时间。 这是由
PodLifecycleSleepAction
特性开关 默认启用的测试版功能。
钩子处理程序执行
当调用容器生命周期管理钩子时,Kubernetes 管理系统根据钩子操作执行处理程序,httpGet
、tcpSocket
和 sleep
由 kubelet 进程执行,exec
在容器中执行。
当创建容器时,会启动 PostStart
钩子处理程序调用,这意味着容器 ENTRYPOINT 和 PostStart
钩子同时触发。 但是,如果 PostStart
钩子执行时间过长或挂起,它可能会阻止容器转换为 运行中
状态。
PreStop
钩子不会与停止容器的信号异步执行;钩子必须在发送 TERM 信号之前完成其执行。 如果 PreStop
钩子在执行期间挂起,则 Pod 的阶段将为 终止中
,并保持该状态,直到 Pod 在其 terminationGracePeriodSeconds
到期后被杀死。 此宽限期适用于 PreStop
钩子执行和容器正常停止所花费的总时间。 例如,如果 terminationGracePeriodSeconds
为 60,并且钩子执行时间为 55 秒,并且容器在收到信号后正常停止时间为 10 秒,那么容器将在能够正常停止之前被杀死,因为 terminationGracePeriodSeconds
小于这两者发生所需的总时间(55+10)。
如果 PostStart
或 PreStop
钩子失败,则会杀死容器。
用户应使他们的钩子处理程序尽可能轻量级。 但是,在某些情况下,长时间运行的命令是有意义的,例如在停止容器之前保存状态时。
钩子传递保证
钩子传递旨在为 至少一次,这意味着对于任何给定事件,钩子可能会被调用多次,例如 PostStart
或 PreStop
。 钩子实现负责正确处理这种情况。
通常,只进行一次传递。 例如,如果 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
下一步
- 详细了解 容器环境。
- 获得动手实践经验 将处理程序附加到容器生命周期事件。