事件起因:
k8s环境中,我使用的app.yaml文件,在服务器中通过 kubectl create -f app.yaml 指令创建的pod,创建的pod中一共运行了4个容器(linux环境),并且启动了 重启策略的默认配置
restartPolicy: Always
- 容器无论以何种状态退出(包括正常退出或错误),都会自动重启。
于是遇到了一个奇葩情况,这个问题我排查了整整一个星期,多么痛的领悟。
发现问题和排查过程:
发现pod中,有一个容器一直偶现重启现象,一定程度上影响到了业务,于是开始了紧张刺激的排查过程:
1、查看容器上一次最后运行时候的日志:
kubectl logs -n dev --previous apps-66667fd978-l2p7h -c app
发现程序没有明显报错,且业务也是正常运行的,更没有打印堆栈,说明程序不是崩溃的
2、查看容器退出原因:
kubectl describe pod -n dev apps-66667fd978-hvtdv | grep -A 10 "Last State"
发现退出码是141,然后守株待兔,发现后续的偶现重启问题,也是退出码141,那么差不多可以确定了,这个问题的初步原因了。
通过 open lens 也可以看到pod中容器的上次退出码和时间
3、退出码和Linux操作系统信号值的关系
计算方式:退出码 = 128 + linux信号值
那么 141 = 128 + 13 ,可以确定,是因为linux发出了13信号值(SIGPIPE
),导致了容器退出,被pod重新拉起,在pod中的退出码显示141
13信号值:
当进程尝试向已关闭的管道(Pipe)或套接字(Socket)写入数据时,内核会发送 SIGPIPE
信号,默认行为是终止进程并生成退出码 141。
到这里,基本上找到问题原因了。
4、排查代码
实际上该容器中运行的主程序并不是本人维护的,但是既然找到原因了那就简单排查一下,代码是c++11写的,首先直接全局搜索关键字一下关键字:
管道操作相关:
pipe(
write(
套接字相关:
send(
write(
(结合sockfd
或套接字变量名)SOCK_STREAM
(TCP 套接字,更可能触发 SIGPIPE)
最后,一无所获
没办法,看了一下代码,代码中确实没有用到套接字或者管道通讯,那我真是奇了怪了,还有一种可能就是使用到的库文件中有用到这些,那就没办法了,排查终止,但是并不意味着没有解决办法。
解决办法,简单粗暴:
在main() 函数中,加一行
signal(SIGPIPE, SIG_IGN); //忽略 SIGPIPE
信号
观察了两个星期,没有再复现问题,至此,解决。