您的位置:首页 > 其它

K8S实战——SIG PIPE问题造成kubernetes集群工作不正常的分析

2016-06-05 22:30 706 查看

前言

上家公司的微服务主要使用K8S部署和管理,由于创业公司资源有限,开发环境的所有K8S的节点都是虚拟机。在实际使用过程中,经常碰到集群节点运行一段时间在集群中显示为“NotReady”状态,然后由于K8S的高容错性,会将运行在该节点上的所有pod重新调度到其他“Ready”的节点上。如果遇上集群中同时有几个节点在集群中状态不正常,就会造成过多的pod发生漂移,然后到其他节点上与其他service产生资源竞争,进一步因为资源竞争造成节点挂点,集群进入恶性循环,可用的资源越来越少,造成能正常工作的service副本越来越少,最后造成服务不能正常提供。本文简单介绍了这个问题的发现过程,关于问题的解决需要借助集群pod状态,节点状态以及服务进程监控解决。后续会另写一篇博客介绍我们开发的一套集群监控。

一、 表象

最开始的时候集群监控、报警做得并不完善,过分依赖K8S的高可用,服务部署后,只要服务能正常提供则很少会主动检查集群运行状态。公司开发环境主要部署在内部虚拟机中,测试环境部署在阿里云上。

开发环境中,从上集群后,多次出现运行一段时间后K8S集群宕机的情况。最开始以为是因为集群节点台少(只有9个work node),而且work node和master都是跑在同一台物理机上的虚拟机,同时集群中已经跑了20来个services(都是双副本),资源过度使用造成。所以通过扩机器,同时开发环境所有service的副本数降为1。

改进后情况稍有好转,但是一段时间后还是会遇到集群大面积宕机的情况。这次仔细查看了集群状态,使用kubectl get po查看所有容器状态为pending或error等状态。查看容器描述,pending状态的容器提示“未找到匹配的selector”,error或crash off的容器提示“OOM killer”杀掉了容器进程,进而容器进入error,crash,restart状态。针对这两个问题表面上可能的原因有两个:

调度器工作不正常,或者打有相应lable的节点kebelet不正常(我们所有的service通过label分组调度)

资源过度使用,资源竞争造成一些service被OOM kill。

所以进一步检查集群状态“kubectl get nodes”,发现大部分节点已经处于”NotReady“状态。这样上面两个原因就都能说通了。首先,因为我们所有服务都是通过分组调度,打指定label的service被调度到同样label的节点上,如果所有相同label的节点都处于“notReady”状态,则会造成节点无法被调度的问题,即前面第一个问题。继续第二个问题,因为我们开发环境节点有限,所以会有多个service同时对应到相同的机器上,所以如果同一组的机器挂掉一台,则所以的service就就会被调度到剩下的机器上。当service负载较重时,所有services之间就会产生资源竞争,最终导致资源过度使用。资源过度使用目前主要集中在CPU,memory,Disk IO,以及网络IO上。目前会导致进程被kill的主要就是memory的过度使用上。所以看到大部分的容器都是因为OOM被kill掉的。

二、深入分析

从上面看,表面上已经找到了问题的原因,但是任然无法解释在负载没有大的变化下,刚开始工作正常,工作一段时间后就会出现宕机的问题,而且所有集群显示”NotReady“的节点都正常运行。

节点状态为”NotReady“主要是kubelet工作不正常造成,所以登录到节点上查找原因。

1. 首先查看相应进程状态,kubelet,docker,flannels。如下图,节点yinnut-node-240为“NotReady”状态,kube-proxy, docker,flanneld都没有正常运行,kubelet是因为已经做过一次恢复,所以处于运行状态。



2. 查看kubelet状态,显示是在2016-03-20 10:58:28秒的时候起来的,这个是发现集群问题并做恢复的时间,前面kubelet已经挂掉。



3. 查看docker状态,可以看到docker在恢复kubelet的相同时间同样执行了一次恢复,但是并未成功,docker在前面已经挂掉。



4. 查看flanneld状态,可以看到flanneld在2016-03-18 23:12:05的时候就已经进入inactive状态。



5. 查看kube-proxy状态,发现kube-proxy是在2016-03-19 23:00:03的时候进入的inactive状态。



6. 这些log信息验证了前面对于问题的分析。进一步分析造成这些进程宕掉的原因,发现这些进程被kill的原因都是”signal=PIPE“,查看service的PIPE属性,发现IgnoreSIGPIPE都是yes状态,说明service的不应该因为SIGPIPE信号被停止。



7. 查找原因,最后定位到这个是Go模块的问题,如果在同一个PIPE有有10次failures则会直接退出程序,这个才是根源所在,所以Docker,flanneld和kube-proxy都显示这个问题。至于什么原因造成连续10次的failure需要后续继续查找原因(可能跟虚拟机的使用有关,因为当时测试环境中并没有遇到过这个问题)。参考链接:Golang社区关于 10次SIG PIPI failure的讨论Docker gets killed by SIGPIPE

三、解决

截止本文发表的时间,Golang已经已经加入这个fix一段时间了,所以升级相应的软件到最新版本应该不会再有这个问题了,或者使用最新的Go源码编译安装应该也行。

我们发现这个问题时候,并没有去研究是否升级到最新版本就能解决问题(复现需要相当长一段时间)。而是意识到集群监控、报警系统的不足,以及集群在异常情况下,带自恢复功能的高容错、高可用在依赖K8S集群自身的功能之外还需要做进一步扩展,这就是谁来负责管理K8S集群的问题。所以基于这个问题,将监控、报警,以及管理K8S集群的优先级往上提了。后续自己开发了一套监控、报警系统,在监测到集群状态不正常时,首先尝试自动恢复集群功能,然后根据恢复情况进行不同等级报警。关于集群监控,后续开文详说。

另外,针对进程挂掉的情况,我们集群进程是以service方式运行的,依赖systemd的restart on failure机制自动重启。但是遇上这种进程自己退出的情况,systemd不会自动重启进程。所有由systemd来监测、恢复进程不能cover这种情况。同样需要额外的集群监控来做。

参考链接:

Golang社区关于 10次SIG PIPI failure的讨论:https://github.com/golang/go/issues/11845

Docker gets killed by SIGPIPE:https://github.com/docker/docker/issues/7087
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  K8S kubernetes SIG-PIPE