pod PreStop 钩子挂在 Terminating 状态,只有在 terminationGracePeriodSeconds 后才会被杀死

The pod PreStop hook is hanging in Terminating status and is killed only after terminationGracePeriodSeconds

我在 statefulset pod 资源中定义了一个 preStop 挂钩,它 运行 是一个 bash 脚本,以确保在应用程序中只有几个进程 finishes/cancels/errors 之前不会终止 pod。我没有定义 terminationGracePeriodSeconds。现在,当我删除 pod 时,我测试了作为 preStop 挂钩一部分的脚本如预期的那样 运行 。但是在添加 terminationGracePeriodSeconds 10 分钟后,首先 bash 脚本是 运行 作为 preStop 挂钩的一部分成功持续了几分钟,它应该会杀死 pod。但 pod 挂在 TERMINATING 状态,仅在 10 分钟后被杀死。

  1. 为什么 pod 挂了?无法为此找到答案。
  2. 当未添加 terminationGracePeriodSeconds 时,流程按预期工作,方法是在完成脚本后或在 30 秒(即 terminationGracePeriodSeconds)内终止 pod。但是当我添加 10 分钟或更长时间的宽限期时,它会等到那个时间然后杀死 pod。

如何解决这个问题。有没有办法将 SIGTERM 或 SIGKILL 发送到 pod。有任何想法吗?提前致谢!

STATEFULSET.YAML

apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app: appx
  name: appx
spec:
  serviceName: appx
  replicas: 1
  updateStrategy:
    type: RollingUpdate
  selector:
    matchLabels:
      app: appx
  template:
    metadata:
      labels:
        app: appx
    spec:
      #removed some of the sensitive info
      terminationGracePeriodSeconds: 600
      containers:
        - image: appx
          imagePullPolicy: IfNotPresent
          name: appx
          lifecycle:
            preStop:
              exec:
                command: ["/bin/sh", "-c", "sleep 30 && bash /var/tmp/runscript.sh; sleep10"]

KUBECTL 描述 POD


**kubectl describe pod appx**
Name:           appx
Namespace:      default
Priority:       0
Node:           docker-desktop/192.168.65.3
Start Time:     Mon, 21 Sep 2020 07:30:55 -0500
Labels:         app=appx
Annotations:    <none>
Status:         Running
IP:             x.x.x.x
Controlled By:  StatefulSet/appx
Containers:
  appx:
    Container ID:   docker://dfdgfgfgfgfgfgfg
    Image:          appx
    Image ID:       docker://sha256:49dfgfgfgfgfgfgfgfgfg96a6fc
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Mon, 21 Sep 2020 07:30:56 -0500
    Ready:          True
    Restart Count:  0
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  data:
    Type:       EmptyDir (a temporary directory that shares a pod's lifetime)
    Medium:
    SizeLimit:  <unset>
  appx-token-xj6q9:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  appx-token-fhfdlf
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age    From                     Message
  ----    ------     ----   ----                     -------
  Normal  Scheduled  2m43s  default-scheduler        Successfully assigned default/appx to docker-desktop
  Normal  Pulled     2m42s  kubelet, docker-desktop  Container image "appx" already present on machine
  Normal  Created    2m42s  kubelet, docker-desktop  Created container appx
  Normal  Started    2m42s  kubelet, docker-desktop  Started container appx

preStop hook 和 terminationGracePeriodSeconds 是异步的。这意味着一旦 kubelet 看到 Pod 已被标记为终止,kubelet 就会开始本地 Pod 关闭过程。这意味着如果容器没有在宽限期内终止,则无论 preStop 挂钩中的命令是否完成,都会发送一个 SIGKILL 信号并终止容器。

  1. When the terminationGracePeriodSeconds was not added, the flow was working as expected by killing the pod as soon as finishing the script or within 30 sec which is the terminationGracePeriodSeconds. But when I added the grace period of 10 min or more, it is waiting until that time and then killing the pod.

terminationGracePeriodSeconds 始终添加宽限期。正如我在评论中提到的那样,它只是默认为 30 秒。那么,如果 terminationGracePeriodSeconds 小于完成 preStop 钩子的时间怎么办?

那么容器会在terminationGracePeriodSeconds结束时终止,preStop hook不会finish/run.

当 terminationGracePeriodSeconds 设置为 600 秒时,preStop 挂钩脚本挂起(目前尚不清楚它是否曾经工作过,因为由于抢先终止而未使用默认的 30 秒 terminationGracePeriodSeconds 进行正确测试)。这意味着一些进程没有正确处理 SIGTERM,目前在 preStop 挂钩中没有更正,这意味着容器正在等待 SIGKILL 在 10 分钟的 terminationGracePeriod 结束后发送。

如果你看一下 here 你会发现即使用户指定了 preStop 挂钩,他们也需要 SIGTERM nginx 才能正常关闭。

在您将 terminationGracePeriodSeconds 设置为 10 分钟的情况下,即使您的 preStop 挂钩成功执行,Kubernetes 也会在终止您的容器之前等待 10 分钟,因为这正是您告诉他要做的。终止信号由 kubelet 发送,但没有传递给容器内的应用程序。最常见的原因是,当您的容器运行一个运行应用程序进程的 shell 时,信号可能是由 shell 本身 consumed/interrupted 而不是传递给子进程。此外,由于不清楚您的 runscript.sh 在做什么,因此很难就哪些进程无法处理 SIGTERM 提出任何其他建议。

在这种情况下你能做什么?提前结束的选项是:

  • 减少终止GracePeriodSeconds
  • 通过确保正确处理 SIGTERM 并且所有 运行 进程都在侦听终止来发送正常关闭的信号。如何做到这一点的例子是 here。你可以看到他们对 NGINX 使用了“退出”命令。

有关您的更多信息可以找到很棒的文章here and here