生命周期钩子

Pod 中的 每个容器 都支持定义两种生命周期钩子:

  • 启动后钩子(Post-start):容器启动后,与容器中的主进程 并行执行,只有该钩子执行成功,容器才会被判定 Running;

  • 停止前钩子(Pre-stop):在容器开始终止进程之前,执行钩子,在容器被停止之前尽可能完成(因为可能容器被要求立即结束,那么钩子还没有来得及被执行);

钩子与探针类似的,有三种执行机制:

  • HTTP GET针对设定的URL执行请求,根据响应状态码判断执行状态(2xx或3xx为成功,其他或不响应为失败);

  • TCP套接字:与指定端口建立TCP连接,建立失败则探测失败;

  • Exec:在容器内执行任意命令,根据命令返回的状态码判断执行状态(0为成功,其他为失败);

启动后钩子

启动后钩子可以让开发者在不改动应用的情况下,执行一些额外的工作。包括向外部监控服务发送应用已启动的信号,或是初始化应用以使得应用能够顺利运行。

在钩子执行完毕之前,容器会一直停留在 Waiting 状态,Pod 的状态停留在 ContainerCreating 状态。

🚀 如果钩子执行失败,那么容器会被重新创建。

如果钩子执行失败,在 Events 中会看到一个 FailedPostStartHook 警告。

钩子进程若将日志输出至 stdin,那么是无法看到的,解决方法是将其输出至临时文件中,然后从该文件中查看输出的日志信息。

案例

下面创建一个带启动后钩子容器的 Pod,在 spec.containers.lifecycle.postStart 中定义,如下。在该案例中,共创建了三种启动后钩子:

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-poststart-hook
spec:
  containers:
  - image: luksa/kubia
    name: kubia
    lifecycle:
      postStart:    # 启动后钩子
        exec:    # Exec 机制;沉睡5s后,以15为状态码退出
          command: 
          - sh
          - -c
          - "echo 'hook will fail with exit code 15'; sleep 5 ; exit 15"
        httpGet:    # http GET 机制;向本容器的9090端口并以postStart为path发送GET请求
          port: 9090
          path: postStart
        tcpSocket:    # TCP 套接字机制;向本容器的8081建立TCP连接
          port: 8081

🍓 lifecycle.httpGet 中还包括下面几个字段:

  • host: 这里的 host 默认是 Pod 的 IP 地址,因为钩子程序的执行者是 Kubelet

  • httpHeaders

  • path

  • port

  • scheme

停止前钩子

停止前钩子是在容器停止之前执行的,在容器需要被终止时,Kubelet 会执行该钩子,即 Pod 的状态称为 Terminating 后,立刻开始执行该钩子,在执行完该钩子后,再向容器发送 SIGTERM 信号。

🌝 和启动前钩子不同的是,无论停止前钩子是否成功,容器都会被终止。

如果钩子执行失败,在 Events 中会看到一个 FailedPreStopHook 警告。

案例

下面创建一个带停止前钩子容器的 Pod,在 spec.containers.lifecycle.preStop 中定义,如下。在该案例中,共创建了三种停止前钩子:

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-prestop-hook
spec:
  containers:
  - image: luksa/kubia
    name: kubia
    lifecycle:
      preStop:    # 停止前钩子
        exec:    # Exec 机制;沉睡5s后,以15为状态码退出
          command: 
          - sh
          - -c
          - "echo 'hook will fail with exit code 15'; exit 15"
        httpGet:    # http GET 机制;向本容器的8080端口并以shutdown为path发送GET请求
          port: 8080
          path: shutdown
        tcpSocket:    # TCP 套接字机制;向本容器的8081建立TCP连接
          port: 8081

🍓 lifecycle.httpGet 中还包括下面几个字段:

  • host:这里的 host 默认是 Pod 的 IP 地址,因为钩子程序的执行者是 Kubelet

  • httpHeaders

  • path

  • port

  • scheme

Pod 关闭流程

当 API 服务器收到 HTTP 的 DELETE 请求后,会给指定的 Pod 设置一个 deletionTimeStamp 值。当 Kubelet 发现需要终止的 Pod 时,它会开始终止该 Pod 中的所有容器。

可以为 Pod 设置一个终止宽限时间 pod.spec.terminationGracePeriodSeconds,给每个容器一定的时间来优雅地停止。

或者也可以使用 --grace-period 参数覆盖在 pod.spec 中指定的终止宽限时间:

kubectl delete pod mypod --grace-period 5

强制立即结束命令:

kubectl delete pod mypod --grace-period 0 --force

该命令尽量不要使用,因为比如在 StatefulSet 中,会避免在同一时间运行两个完全一样的 Pod(具有相同的序号、名称、挂载相同的 PV),使用该命令删除时,可能导致原容器还未退出,就有新容器创建,即两个容器同时存在,可能会造成无法预知的错误

在终止进程开始后,计时器就开始计时,接着开始按照下述流程执行以下事件:

  1. 执行停止前钩子进程(如果配置了的话),然后 等它执行完毕

  2. 向容器主进程发送 SIGTERM 信号;

  3. 等待容器优雅地关闭或者等待终止宽限期超时;

  4. 如果容器主进程还在运行,则发送 SIGKILL 信号强制终止进程;

容器终止流程

Last updated

Was this helpful?