理论
当我们在 Kubernetes 中触发停止一个 Pod 时,它会向每个容器中的进程发送一个 SIGTERM 信号,等待一段时间,这段时间被称为终止宽限期(termination grace period)。如果超过宽限期 Pod 中仍有容器进程没有被终止,会发送 SIGKILL 强行终止该进程。
所以作为开发者要注意配置:
- 正确处理应用对 SIGTERM 信号的响应方式
- 指定更加合理的宽限期
设置宽限期
在配置文件和命令行中都可以设置宽限期。
配置文件
使用 kubectl explain
配置我们可以知道默认的终止宽限期为30秒。
1 | $ kubectl explain pod.spec.terminationGracePeriodSeconds |
通过配置 pod.spec.terminationGracePeriodSeconds
可以修改终止宽限期。例如:
1 | apiVersion: v1 |
命令行
我们还可以在终止一个 Pod(或者 Deployment)的时候设置 --grace-period
来指定终止宽限期^command-termination。
1 | kubectl delete pod <name> --grace-period=<seconds> |
对无法优雅关闭的应用进行处理
如果有一些应用不是我们开发的,那么可能无法修改它处理 SIGTERM 信号的方式。这时该如何优雅地关闭该应用呢?这时我们需要用到配置 pod.spec.containers.lifecycle.preStop
。我们先看一下官方文档的解释:
PreStop
hooks are not executed asynchronously from the signal to stop the Container; the hook must complete its execution before the TERM signal can be sent. If aPreStop
hook hangs during execution, the Pod’s phase will beTerminating
and remain there until the Pod is killed after itsterminationGracePeriodSeconds
expires.
所以在 preStop
hook 执行完之前,不会向容器发送 SIGTERM 信号,并且 Pod 会处于 Terminating 状态。
例如 Nginx 接收到 SIGTERM 信号会立即退出进程,必须通过在 preStop
中执行命令 /usr/sbin/nginx -s quit
来优雅地结束进程。指定触发 Pod 停止的时候容器中的,来执行命令关闭 Nginx。示例代码[^nginx-termination]:
1 | apiVersion: v1 |
总结
从运维角度我们可以在部署时通过配置文件指定 Pods 的终止宽限期,也可以在手动终止时指定宽限期。
从开发者的角度,我们应该保证自己的应用可以正确处理 Kubernetes 对 Pods 的终止动作。一般情况下我们需要正确处理 SIGTERM 信号;如果有些服务无法正确处理 SIGTERM 信号,但是提供了终止命令,我们可以在 preStop
中指定。
[^nginx-termination]: 参考文章 Graceful shutdown of pods with Kubernetes。