Kubernetes 优雅地停止 Pod
Pod
作为k8s
的计算单元,当我们在部署新版本或者重启Pod
时,k8s
给我们提供了优雅退出Pod
的机制,让我们有机会做一些事情,比如:
- 获得更好的用户体验;
- 保存数据,保护数据的完整性;
- 完成其它善尾工作,保护相关状态。
k8s如何停止Pod
我们要清楚k8s
在停止Pod
时的流程。
首先在Pod
模板里,有一个属性terminationGracePeriodSeconds
,默认值是30,它代表Pod
有30秒的宽限期,过了这个时间Pod
便被当做死亡
。
示例流程
下面是一个示例流程:
- 用户发送命令删除
Pod
,默认terminationGracePeriodSeconds
(宽限期)为30s; Pod
会根据宽限期进行更新,同时被标记为Terminating
:- 通过命令行查询,可以看到
Pod
为Terminating
状态; Service
会将Pod
从它的Endpoints
中移除,同时Replication Controller
也会认为Pod
不是运行状态。负载均衡也不会再将流量分配到该Pod
中;Pod
处于Terminating
状态时,Kubelet
会执行Pod
关闭流程:- 如果
Pod
定义了preStop
的勾子,便在Pod
中执行它。 - 当宽限期结束后
preStop
还在执行时,会给Pod
内的进程发送SIGTERM
信号(相当于kill pid),增加等待时间是2秒(扩展宽限期)。
- 如果
- 通过命令行查询,可以看到
- 当宽限期结束后,任何还在
Pod
中运行的进程都会被SIGKILL
杀死。 Kubelet
将通过设置宽限期为0(立即删除)来完成删除 API 服务器上的 Pod。Pod 从 API 中消失,从客户端也不再可见。
停止流程的重点
在Pod
的停止流程中,我们可以注意几个重点:
terminationGracePeriodSeconds
(宽限期):
这个在上面提到过了,它代表着整个Pod
停止流程的宽限期。preStop
勾子:
如果我们定义了preStop
勾子,那在关闭Pod
时,会先执行它。SIGTERM
信号:
如果没有定义preStop
勾子,那在关闭Pod
时,会直接发送SIGTERM
信号。或者是有定义preStop
,然而在宽限期结束了,preStop
依旧没执行完,那么也会发送SIGTERM
信号,并扩展2秒钟的宽限期。SIGKILL
信号:
当时间超过了宽限期,Pod
中的所有进程都会被SIGKILL
杀死。- 如何强制删除
Pod
:
通过kubectl delete
命令的--grace-period
参数,可以覆盖掉宽限期,设置为「0」时会强制删除Pod。如果kubectl
版本大于等于1.5,还需要增加一个--force
参数。
我们要如何优雅地停止Pod
上面说了那么多,其实根据k8s
提供的机制,我们只能做两件事情:
- 定义
preStop
操作; - 监听
SIGTERM
信号。
对于preStop
而言,我们可以提供两种 Hook: Exec 和 HttpGet,配置位于Pod
的.spec.containers[].lifecycle.preStop
中,可以为每一个container
都做配置。
而监听SIGTERM
信号,需要写在程序代码里面,当程序接收到信号后,做退出的操作。
两个注意(坑)
preStop接口Path
preStop
如果使用的是httpGet
的形式,要注意接口的路径问题,根据k8s
目前代码:
1 | url := fmt.Sprintf("http://%s/%s", net.JoinHostPort(host, strconv.Itoa(port)), handler.HTTPGet.Path) |
路径的拼接可能会出现问题,比如我们填写 path
为/shutdown
时,接收到的请求将会是:{your.ip}//shutdown
,有两个/
,所以你的应用很可能会没有做对相应的响应。
SIGTERM信号的接收
SIGTERM
信号的接收需要注意,在Pod
中只有pid
为1的进程会接收到信号,其他进程是接收不到的。
参考
- 本文链接:https://keepmoving.ren/kubernetes/gracefully-terminate/
- 版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!