Kubernetes 容器 - 容器的生命周期 hooks

Table of Contents

本页面描述 kubelet 管理的容器可以使用容器的生命周期 hook 框架来运行事件在其管理生命周期中触发的代码。

1. 概览

类似许多编程语言框架有生命周期 hooks,比如 Angular,Kubernetes 提供了容器的生命周期 hook。 hooks 使容器能够了解其管理生命周期中的事件和执行相应的生命周期 hook 时运行处理程序中事件的代码。

2. 容器 hooks

有两个暴露给容器的 hooks:

PostStart

创建容器之后立即执行此 hook。但是,不能保证该 hook 在容器的 ENTRYPOINT 之前执行。没有参数传递给处理程序。

PreStop

在容器终止之前(由于 API 请求或者管理事件如存活/启动探针失败,抢占,资源竞争等)hook 会被立即调用。 如果容器已经处于终止状态或者已完成,并且 hook 必须在给容器发送给 TERM 信号之前完成。在执行 PreStop hook 之前,Pod 的宽限期倒计时开始, 因此,无论处理程序的结果如何,容器最终将在 Pod 的终止宽限期内终止。没有参数传递给处理程序。

有关终止行为的更多说明,参见 Pod 的终止 文档。

2.1. Hook 处理器的实现

实现和注册一个 hook 的处理器,容器才可以使用 hook。有两种类型的 hook 处理器:

  • Exec - 执行一个特定的命令,比如 pre-stop.sh ,在容器的 cgroups 和 namespaces 中。该命令消耗的资源计入容器中;
  • HTTP - 针对容器上的特定端点执行 HTTP 请求;

2.2. Hook 处理器执行

当容器生命周期管理 hook 被调用时,Kubernetes 管理系统根据 hook 行为执行处理器, httpGettcpSocket 是通过 kubelet 进程执行的, 而 exec 在容器内部执行的。

Hook 处理器调用在包含 Container 的 Pod 的上下文中是同步的。对于 PostStart hook,容器 ENTRYPOINT 和 hook 是异步的。 但是,如果 hook 执行太长时间时间或者 hang 住的情况下,容器也无法到达 running 状态。

PreStop hook 不是从终止容器信号之后异步执行的;hook 必须执行完毕之后,才能发送 TERM 信号。如果 PreStop hook 在执行期间 hang 住了 Pod 的 phase 会被设置为 Terminating 然后一直保持这个状态,直到 Pod 的 GracePeriodSeconds 到时间之后才被杀死为止。 此宽限期适用于 PreStop hook 执行和容器正常停止所话费的总时间。 比如说, terminationGracePeriodSeconds 的值是 60,hook 花费了 55 秒,容器在收到信号之后需要 10 秒才能耐正常终止,这种情况下, 容器在终止之前会被杀掉,因为 terminationGracePeriodSeconds 小于总时间(55+10)。

无论是 PostStart 还是 PreStop hook 失败,都会杀掉容器。

用户应该保证 hook 处理程序尽可能的轻巧。但是,有些情况下,长时间运行的命令才有意义。比如在停止容器之前保存状态。

2.3. Hook 交付保证

Hook 会保证至少执行一次,这意味着给定任何事件 (PostStart 或者 PreStop),hook 可能被多次调用。hook 的执行程序需要能够适配这种可能情况。

通常情况下,只执行一次。比如,HTTP hook 接收者已被关闭,无法正常通信,也不会进行重试。但是,在极少数情况下,可能出现两次调用。例如,如果 kubelet 在发送 hook 的过程中重新启动,可能会出现重启之后再次发送。

2.4. 调试 Hook 处理器

Hook 处理程序的日志没有在 Pod 事件中公开。如果处理程序因为某种原因失败,它将广播一个事件。对于 PostStartFailedPostStartHook 事件, 对于 PreStopFailedPreStopHook 事件。你可以通过 kubectl describe pod <pod_name> 来查看这些事件。 事件可能如下:

Events:
  FirstSeen  LastSeen  Count  From                                                   SubObjectPath          Type      Reason               Message
  ---------  --------  -----  ----                                                   -------------          --------  ------               -------
  1m         1m        1      {default-scheduler }                                                          Normal    Scheduled            Successfully assigned test-1730497541-cq1d2 to gke-test-cluster-default-pool-a07e5d30-siqd
  1m         1m        1      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Normal    Pulling              pulling image "test:1.0"
  1m         1m        1      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Normal    Created              Created container with docker id 5c6a256a2567; Security:[seccomp=unconfined]
  1m         1m        1      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Normal    Pulled               Successfully pulled image "test:1.0"
  1m         1m        1      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Normal    Started              Started container with docker id 5c6a256a2567
  38s        38s       1      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Normal    Killing              Killing container with docker id 5c6a256a2567: PostStart handler: Error executing in Docker Container: 1
  37s        37s       1      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Normal    Killing              Killing container with docker id 8df9fdfd7054: PostStart handler: Error executing in Docker Container: 1
  38s        37s       2      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}                         Warning   FailedSync           Error syncing pod, skipping: failed to "StartContainer" for "main" with RunContainerError: "PostStart handler: Error executing in Docker Container: 1"
  1m         22s       2      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Warning   FailedPostStartHook

First created: 2021-04-19 22:16:45
Last updated: 2021-11-15 Mon 10:18
Power by Emacs 27.2 (Org mode 9.4.6)