如何收集pod重启前现场

之前分享过几篇优化pod重启的文章,有朋友发私信问:看你的优化文章很过瘾,可否分享下如何收集pod重启前的现场。

案例分享-full gc导致k8s pod重启

记一次k8s pod频繁重启的优化之旅

的确是个好问题,之前写文章的时候忽略了这一点,一个完整的现场对破案的作用不言而喻,今天花点时间和大伙探讨一下。

守株待兔阶段

这个时期处于人工盯屏阶段,打开rancher(一款k8s集群管理工具)界面观察pod的状态,如果发现pod的状态变成下图(Container with unready status意味着健康检查失败)这样的时候立刻进入容器的命令行使用jmap命令收集dump信息。

显然运气的成分多一些,比较浪费时间。

全自动阶段

盯屏效率太低,有没有机制能在pod重启前自动收集现场,无人值守,为开发在事后分析提供充分的证据。

接下来就是今天的主角登场,容器的生命周期回调,Kubernetes 为容器提供了生命周期回调。回调使容器能够了解其管理生命周期中的事件,并在执行相应的生命周期回调时运行在处理程序中实现的代码。

有两个回调暴露给容器:

PostStart

这个回调在容器被创建之后立即被执行。但是,不能保证回调会在容器入口点(ENTRYPOINT)之前执行。没有参数传递给处理程序。

PreStop

在容器因 API 请求或者管理事件(诸如存活态探针、启动探针失败、资源抢占、资源竞争等) 而被终止之前,此回调会被调用 。如果容器已经处于已终止或者已完成状态,则对 preStop 回调的调用将失败。在用来停止容器的 TERM 信号被发出之前,回调必须执行结束。Pod 的终止宽限周期在 PreStop 回调被执行之前即开始计数, 所以无论回调函数的执行结果如何,容器最终都会在 Pod 的终止宽限期内被终止。没有参数会被传递给处理程序。

我们最终决定借助PreStop回调来实现自动收集现场,配置如下:

复制代码
lifecycle:
          preStop:
            exec:
              command:
              - /bin/sh
              - -c
              - pid=`ps -ef |grep java | grep -v grep |awk '{print $1}'`; jmap -dump:format=b,file=/data/dump/${JAR_NAME}.dump
                ${pid}

大致意思是在容器销毁前通过jmap命令收集dump到指定目录。

有两点需要特别说明:

1.注意这个目录需要做持久化,而且要及时清理减少磁盘占用,因为日常的发布也会触发preStop;

2.另一个需要注意的是终止宽限期-terminationGracePeriodSeconds需要调整,给jmap预留充分的时间保留现场,也不能太长,调长的副作用是滚动发布会变慢。

推荐阅读

https://kubernetes.io/zh-cn/docs/concepts/containers/container-lifecycle-hooks/