admin管理员组文章数量:1595917
我们在使用 Kubernetes 时遇到了设置 --grace-period 参数不生效的问题,从 kubelet 日志看是 kubelet 接受到 Pod DELETE 事件后在同一秒内又接受到了 REMOVE 事件,所以 Pod 立刻就会删掉了。经过比较曲折的排查最后终于解决了这个问题,下面分享一下 kubernetes grace period 相关的一些概念和理论然后再介绍一下我们踩到的坑。
根据 kubernetes 官方文档《Termination of Pods》这一节的介绍可知 Kubernetes 删除 Pod 时是可以配置 --grace-period 参数的,而且即使没设置这个参数它也有 30 秒的默认值。那么:
- 这个宽限期到底有什么作用是怎么生效的呢?
- grace-period 和 docker stop -t 参数有关系吗?
- 在 Kubernetes 中使用 grace-period 的最佳实践应该怎样的?
在解答这些问题前我们从优雅下线的作用、 Pod 中容器的生命周期 和 Pod 删除的流程说起。
优雅下线有什么用?
我们知道集团的应用都有 online 和 offline 的操作。online 是在应用启动后可能会做一些注册服务或者开启告警之类的操作,offline 是在了停容器前会做关闭告警或者注销服务的操作。所以 online 和 offline 对于一个复杂的分布式集群来说是必不可少的操作。
Container Lifecycle Hooks
Kubernetes 给 Pod 中的 container 添加了两个 hook 点(官方文档看这里):容器启动后和容器停止前。容器启动后正是做 online 的好时机,容器停止前正是做 offline 的好时机。
- PostStart hook
PostStart 执行的时机是在容器启动以后,但是并不是等容器启动完成再执行。容器启动以后和容器启动完成的区别是什么呢?我们先看一下 Docker 官网的 Entrypoint 和 CMD 的配置可知容器有可以通过 Entrypoint 和 CMD 配置启动指令,如果 Entrypoint 和 CMD 都做了配置那么 CMD 会作为 Entrypoint 的参数由 Entrypoint 来决定如何使用 CMD。但是 Entrypoint 执行之后是不会结束的,如果容器的一号进程结束容器也就退出了。所以在标准的容器玩法中是不知道容器什么时候启动成功的,只知道容器已经启动了。所以 kubelet 是在执行 Entrypoint 之后就会立即执行 PostStart hook,而不是等 Entrypoint 执行完再去执行的。所以理论上来说 PostStart 和 Entrypoint 是并行执行的。
这个 hook 点是执行应用 online 好时机,PostStart 可以探测应用是否启动成功,如果应用启动成功就执行 online 的动作
- PreStop hook
PreStop 是在 Pod 销毁前 kubelet 对容器执行的指令,可以是到容器中执行一个命令也可以是向容器的某个端口发起一个 HTTP 请求。PreStop 的作用是做一些下线前的准备工作,比如集团的精卫应用再下线前需要从 zk 中注销当前的服务实例。
这个 hook 是执行 offline 的好时机,可以在下线前做一些清理动作。
Termination of Pods
当发起一个删除 Pod 的指令时 Pod 的删除逻辑是这样的:
- 调用 kube-apiserver 发起删除 Pod 请求,如果删除 Pod 时没有设置 grace period 参数那么就会使用 30 秒的默认值,否则就会使用用户指定的 grace period 进行优雅下线
- kube-apiserver 接受到这个请求以后给相应的 Pod 标记为“删除状态”。其实 Pod 没有“删除状态”,此时 Pod 的 status 还是 Running 状态,所谓的“删除状态”只是 deletionTimestamp 和 deletionGracePeriodSeconds 字段会被设置,这时候 kubelet 或者 kube-proxy 监听到这样的 Pod 就会认为此 Pod 已经不能提供服务了,然后开始做相应的清理操作。
- 此时如果通过 Dashbord 查看 Pod 的状态是 Terminating ,其实 Terminating 也不是 Pod status 的字段的值。只是因为设置了 deletionTimestamp 和 deletionGracePeriodSeconds 字段所以 Dashbord 就会把 Pod 标记为 Terminating 状态。这也是 Kubernetes 官方文档中提到的状态
- (和第三条同时发生)当 kube-proxy 监听到 Pod 处于 Terminatiing 状态时就把 Pod 从 Service 的 EndPoint 中摘掉,这样对外暴露的服务就摘掉了这个 Pod,防止新的请求发送到这个 Pod 上来
- kubelet 监测到 Pod 处于 Terminating 状态的话会下线 Pod,下线的过程分成两个步骤。1. 执行 PreStop 2. 杀死容器。第一步:如果 Pod 设置了 PreStop hook 的话 kubelet 监测到 Pod 处于 Terminating 状态后就会执行 PreStop 操作,执行 PreStop 设置的超时时间和删除 Pod 时指定的 grace period 一致(如果没设置默认是 30 秒)
- PreStop 执行完以后还有第二步杀死容器,第二部也有超时时间,这个超时时间是 grace period 减去 PreStop 耗时。如果执行 PreStop 超时或者 grace period 减去 PreStop 耗时剩余的时间不够两秒(甚至可能是负数) kubelet 会强制设置成两秒。第二部的超时时间暂且称之为 tm2, kubelet 停止容器时执行的是 docker stop -t tm2 命令。所以 tm2 的逻辑是:首先发送 term 信号到容器的一号进程,如果容器在 tm2 时间内没有停止就强制发送 kill 信号杀死容器
- kubelet 执行完 PreStop 和杀死容器两步以后会回调 kube-apiserver,把 Pod 从 kube-apiserver 中删除,这次的删除是真的删除,这时候通过 API 就再也看不到这个 Pod 的信息了
上面这些过程也可以查看Kubernetes 官方文档,官方文档也有详细的说明。从这里可以判断出来 Pod 下线现在 kube-apiserver 中标记为删除状态,然后 kubelet 执行完正真的删除动作才会真的删除 Pod。
优雅下线时间也可以设置成零,零的意思是立即从 Kubernetes 中删除此 Pod。参数设置方法是:--forc --grace-period=0
这两个参数同时被设置
回答上面的问题
- 这个宽限期到底有什么作用是怎么生效的呢?
grace-period 的作用是让 kubelet 可以在删掉 Pod 前优雅的下线掉 Pod 中
本文标签: KubernetesgracePeriod
版权声明:本文标题:kubernetes grace period 失效问题排查 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dianzi/1728236917a1150530.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论