Kubernetes延迟Pod终止-FailedPreStopHook

时间:2020-06-12 15:43:40

标签: kubernetes kubernetes-helm

我有k8s集群,在其中使用Helm部署Spring应用程序。
我想设置“宽限期”,让旧容器在终止并被新吊舱替换之前完成其工作。 deployment.yml

      terminationGracePeriodSeconds: 600    # ~ 10 minutes
      containers:
        - name: receiver
          lifecycle:
            preStop:
              exec:
                command: ["/bin/sleep","600"]

但是我可以在kubectl get events中看到奇怪的错误:

3m15s       Warning   FailedPreStopHook   pod/robot-7bd4c6956f-ltbpn                Exec lifecycle hook ([/bin/sleep 600]) for Container "receiver" in Pod "robot-7bd4c6956f-ltbpn_rpa-uat(b0d17f4f-4adf-4b8b-a4df-fd84f694b92c)" failed - error: command '/bin/sleep 600' exited with 137: , message: ""

有人知道如何让容器/吊舱等待那600秒吗?

1 个答案:

答案 0 :(得分:1)

k8s docs on lifecycles中,您可以阅读:

PreStop - 在容器终止之前会立即调用此钩子[...]

这意味着当pod终止开始时,在将SIGTERM发送到容器之前,将执行此prestop挂钩。

在启动preStop挂钩的同时,k8s正在启动倒数计时器以等待terminationGracePeriodSeconds秒,然后才将SIGKILL发送到容器。

请注意,在您的preStop睡眠600秒并且terminationGracePeriodSeconds也设置为600秒的情况下,可能会导致比赛状态。

在kubernetes源代码中查看this piece of code

select {
case <-time.After(time.Duration(gracePeriod) * time.Second):
    klog.V(2).Infof("preStop hook for container %q did not complete in %d seconds", containerID, gracePeriod)
case <-done:
    klog.V(3).Infof("preStop hook for container %q completed", containerID)
}

如您所见,kubelet等待首先发生的一切。 但是,在您的情况下,这两种情况都需要600秒,并且它们在同一时间或多或少地完成比赛,因此可能会导致比赛情况。因此,要么preStop先成功完成,然后倒计时完成,以杀死吊舱,要么倒数计时器首先完成,将SIGKILL发送到容器,以杀死内部运行的所有内容,这也意味着终止preStop,然后以错误Warning FailedPreStopHook完成preStop。还要注意,exited with 137意味着该进程被SIGKILL(137-128 = 9,其中9是SIGKILL编号)杀死了k8s。

最重要的是,您的应用程序甚至都不知道它即将终止。


好的,那你该怎么办?如何正确使用preStop?

preStop应该用于通知正在容器中运行的主进程即将终止,并且应该开始为其进行准备,或者用于通知应用集群的其他成员该应用实例将被终止。它也可以按您描述的那样(带睡眠)使用一段时间,以便iptables中的更改有时间传播。您可能还没有意识到,但是在终止过程开始后,k8s正在重新配置网络,因此不会创建新的连接。这就是为什么有时会使用较小的延迟来使k8s有时间传播更改并允许应用在终止之前响应正在进行的请求。

因此,您能做的最好的事情是使您的应用程序了解终止过程,并使其对SIGTERM信号做出适当的响应。 长时间睡眠并不能解决您面临的问题。


此外,这是一些有关springboot的信息,您可能会觉得有用。