k8s中配置prestop不生效
k8s的prestop主要是用于pod的优雅停止,那么什么是优雅停止呢?
何为优雅停止?
优雅停止(Graceful shutdown)这个说法来自于操作系统,我们执行关机之后都得 OS 先完成一些清理操作,而与之相对的就是硬中止(Hard shutdown),比如拔电源。
到了分布式系统中,优雅停止就不仅仅是单机上进程自己的事了,往往还要与系统中的其它组件打交道。比如说我们起一个微服务,网关把一部分流量分给我们,这时:
假如我们一声不吭直接把进程杀了,那这部分流量就无法得到正确处理,部分用户受到影响。不过还好,通常来说网关或者服务注册中心会和我们的服务保持一个心跳,过了心跳超时之后系统会自动摘除我们的服务,问题也就解决了;这是硬中止,虽然我们整个系统写得不错能够自愈,但还是会产生一些抖动甚至错误;
假如我们先告诉网关或服务注册中心我们要下线,等对方完成服务摘除操作再中止进程,那不会有任何流量受到影响;这是优雅停止,将单个组件的启停对整个系统影响最小化;
按照惯例,SIGKILL 是硬终止的信号,而 SIGTERM 是通知进程优雅退出的信号,因此很多微服务框架会监听 SIGTERM 信号,收到之后去做反注册等清理操作,实现优雅退出。
pod的停止流程
由于Pod所代表的是在集群中节点上运行的进程,当不再需要这些进程时允许其体面地 终止是很重要的。一般不应武断地使用KILL信号终止它们,导致这些进程没有机会完成清理操作。
设计的目标是令你能够请求删除进程,并且知道进程何时被终止,同时也能够确保删除操作终将完成。当你请求删除某个Pod时,集群会记录并跟踪Pod 体面终止周期, 而不是直接强制地杀死 Pod。在存在强制关闭设施的前提下, kubelet会尝试体面地终止 Pod。
通常情况下,容器运行时会发送一个TERM信号到每个容器中的主进程。 很多容器运行时都能够注意到容器镜像中 STOPSIGNAL 的值,并发送该信号而不是 TERM。 一旦超出了体面终止限期,容器运行时会向所有剩余进程发送 KILL信号,之后Pod就会被从API服务器上移除。如果kubelet或者容器运行时的管理服务在等待进程终止期间被重启, 集群会从头开始重试,赋予 Pod完整的体面终止限期。
Pod退出的流程大致如下:
1.用户删除 Pod。
- 2.1 Pod 进入 Terminating 状态。
- 2.2 与此同时,K8s 会将 Pod 从对应的 service 上摘除。
- 2.3 与此同时,针对有 PreStop Hook 的容器,kubelet 会调用每个容器的 PreStop Hook,假如 PreStop Hook 的运行时间超出了 grace period,kubelet 会发送 SIGTERM 并再等 2 秒。
- 2.4 与此同时,针对没有 PreStop Hook 的容器,kubelet 发送 SIGTERM。
3.grace period 超出之后,kubelet 发送 SIGKILL 干掉尚未退出的容器。
prestop配置不生效
为了服务做平滑升级或无损发布,我们会通过配置停止前的等待时间的prestop Hook,但是当我们sleep时间较长会发现prestop没有生效,其实pod的停止流程是有说明的
说明: 如果 preStop 回调所需要的时间长于默认的体面终止限期,你必须修改terminationGracePeriodSeconds属性值来使其正常工作。
terminationGracePeriodSeconds默认是30s,当我们的prostop配置的sleep 70s,就会出现pod不会等70s才被销毁,会马上kill掉,那么要怎么要配置才会生效呢?
其实这里只需要将terminationGracePeriodSeconds时长修改比prestop所执行的时间长即可,也就是说你的prestop需要100s执行完成,你的terminationGracePeriodSeconds设置为101s就不会出现不生效的问题。
prestop配置多行命令
如何你的prestop想执行多条命令操作,可以参考下面配置
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /bin/bash
- '-c'
- |-
curl http://www.baidu.com
sleep 70
curl http://www.qq.com