k8s pod被驱逐问题分析及解决
1、问题现象及分析
环境说明
环境说明:
-
centos7.3 -
Kubernetes1.14 -
docker 1.18.9
异常信息:kubectl get pod
发现服务被驱逐,然后在调度到其它节点过程中出现问题,之所以出现问题是因为编排文件中添加了污点,已经标注该Pod不能被调度到其它节点。但是为什么会出现Pod被驱逐,这倒是个问题?查看/var/log/messages
中日志,发现大量镜像无法被拉取的错误,如下所示:
镜像被删除问题
Nov 7 06:20:49 k8work2 kubelet: E1107 06:20:49.829886 13241 remote_image.go:113] PullImage "k8s.gcr.io/kube-proxy:v1.14.2" from image service failed: rpc error: code = Unknown desc = Error response from daemon: Get https://k8s.gcr.io/v2/: dial tcp 74.125.204.82:443: connect: connection timed out
Nov 7 06:20:49 k8work2 kubelet: E1107 06:20:49.866132 13241 pod_workers.go:190] Error syncing pod 4fedf7b3-207e-11eb-90a3-2c534a095a16 ("kube-proxy-pqvvb_kube-system(4fedf7b3-207e-11eb-90a3-2c534a095a16)"), skipping: failed to "StartContainer" for "kube-proxy" with ErrImagePull: "rpc error: code = Unknown desc = Error response from daemon: Get https://k8s.gcr.io/v2/: dial tcp 74.125.204.82:443: connect: connection timed out"
这段日志的意思是因为镜像无法拉取,所以启动出现启动失败问题,除此之外还有coredns、Controller
等,也出现此类镜像无法拉取问题。
出现这个问题,很容易理解,内网集群,在集群安装过程中,镜像是通过复制过来的,但是执行docker images|grep k8s
发现k8s的镜像全不在了,难道有人为删除,要不然镜像为什么会无缘无故消失呢?
于是又开始查看日志,又发现日志中存在此类信息,确认不是人为删除,而是kubelet回收掉了,具体日志如下所示:
Nov 7 05:44:51 k8work2 kubelet: I1107 05:44:51.041315 13241 image_gc_manager.go:317] attempting to delete unused images
Nov 7 05:44:51 k8work2 kubelet: I1107 05:44:51.083785 13241 image_gc_manager.go:371] [imageGCManager]: Removing image "sha256:6858809bf669cc5da7cb6af83d0fae838284d12e1be0182f92f6bd96559873e3" to free 1231725 bytes
为什么要把k8s自身运行需要的镜像回收掉呢?这里先不过多解释,具体原因,且看下文。
找不到manifests问题
Nov 7 06:20:47 k8work2 kubelet: E1107 06:20:47.943073 13241 file_linux.go:61] Unable to read config path "/etc/kubernetes/manifests": path does not exist, ignoring
其实看了下网上这个问题,也挺多的,因为是计算节点,不包含manifests,但是日志中一直在提示这个错误,这种噪音日志看着就难受,我是直接在/etc/kubernetes/
创建了manifests文件夹,问题直接解决。此错误跟本文中的Pod驱逐应该没什么关系,看了看其它计算接单存在同样问题。
孤儿Volume问题
Nov 7 09:32:03 k8work2 kubelet: E1107 09:32:03.431224 13241 kubelet_volumes.go:154] Orphaned pod "f6a977f4-2098-11eb-90a3-2c534a095a16" found, but volume paths are still present on disk : There were a total of 1 errors similar to this. Turn up verbosity to see them.
进入到/var/lib/kubelet/pods/
,通过id号,进入kubelet的目录,可以发现里面还存在容器的数据,etc-hosts文件中还保留着pod名称等信息。
从错误信息可以推测,这台计算节点存在一个孤儿Pod,并且该Pod挂载了数据卷(volume),阻碍了Kubelet对孤儿Pod正常的回收清理。所以一直在提示上面错误信息,我在确认该Pod确认该Pod确实已经不在运行,并且没有数据丢失的风险,直接执行了rm -rf f6a977f4-2098-11eb-90a3-2c534a095a16
,删除过后,不在刷此类错误。
驱逐问题
Nov 7 07:21:19 k8work2 kubelet: E1107 07:21:19.021705 13241 eviction_manager.go:576] eviction manager: pod es-0_log(aa41dd4c-2085-11eb-90a3-2c534a095a16) failed to evict timeout waiting to kill pod
Nov 7 07:21:22 k8work2 kubelet: I1107 07:21:22.883681 13241 image_gc_manager.go:300] [imageGCManager]: Disk usage on image filesystem is at 86% which is over the high threshold (85%). Trying to free 21849563955 bytes down to the low threshold (80%).
Nov 7 07:21:22 k8work2 kubelet: E1107 07:21:22.890923 13241 kubelet.go:1278] Image garbage collection failed multiple times in a row: failed to garbage collect required amount of images. Wanted to free 21849563955 bytes, but freed 0 bytes
日志大概提示意思是磁盘压力过大,已经超过阈值,于是df -h
查看了下磁盘,果然这台机器服务产生了大量日志,导致磁盘占用过高,但是磁盘虽然占用过高,为什么要回收镜像呢?在官网查询了下,大概是这样介绍的:
垃圾回收是
kubelet
的一个有用功能,它将清理未使用的镜像和容器。kubelet
将每分钟对容器执行一次垃圾回收,每五分钟对镜像执行一次垃圾回收。
镜像垃圾回收策略只考虑两个因素:
HighThresholdPercent
和LowThresholdPercent
。磁盘使用率超过上限阈值(HighThresholdPercent
)将触发垃圾回收。垃圾回收将删除最近最少使用的镜像,直到磁盘使用率满足下限阈值(LowThresholdPercent
)。
容器垃圾回收策略考虑三个用户定义变量。
MinAge
是容器可以被执行垃圾回收的最小生命周期。MaxPerPodContainer
是每个pod
内允许存在的死亡容器的最大数量。MaxContainers
是全部死亡容器的最大数量。可以分别独立地通过将MinAge
设置为0,以及将MaxPerPodContainer
和MaxContainers
设置为小于0来禁用这些变量。kubelet
将处理无法辨识的、已删除的以及超出前面提到的参数所设置范围的容器。最老的容器通常会先被移除。
对于k8s用户来说上述kubelet参数都是可以调整的,具体调整方式请参考:https://kubernetes.io/zh/docs/concepts/cluster-administration/kubelet-garbage-collection/
这里不在过多赘述。
说到这里大概已经找到原因,之所以出现Pod被驱逐,原因是因为磁盘压力超过阈值,在k8s看来,这个计算节点已经不正常,所以开启垃圾回收机制,按照默认回收策略首先删除了自身的镜像信息,然后导致内网镜像拉取失败问题,然后开始重新调度Pod,但是因为该Pod中添加了污点,不能被调度到其它节点,最后导致启动失败。
2、问题解决
解决过程
于是找到占用磁盘数据所在文件夹,是一个以pod PVC命名的文件,确认里面的数据可以删除之后,我直接把PVC文件夹以及内容,全部都给删掉了,再次启动Pod,一直处于init状态,event事件提示无法找到PVC,仔细看了下该Pod所在编排文件内容,发现该Pod是有状态应用,以sts进行编排,我们知道sts以特定顺序启动,并且拥有稳定网络身份标识、写入固定的存储,现在我把存储名称都给干掉了,所以导致无法启动,大家引以为戒。
但是之所以会出现上面有状态Pod无法启动的问题,究其原因是因为复用了过去的PVC,我只要把PVC、PV删除了,重新创建,一切万事大吉,于是我开始使用kubectl delete pvc pvc_name -n log
,有趣的一幕又发生了,PVC一直卡在Terminating无法删除。
网上查了查解决方式,大概两种:
直接到etcd中删除
使用kubectl patch
kubectl delete pvc pvc_name -n log
kubectl patch pvc pvc_name -p '{"metadata":{"finalizers":null}}' -n log
之所以需要强制执行,因为原生k8s不允许执行删除后的回滚动作。这大概就是k8s最终一致性原则的体现。
再次重新启动Pod,启动成功,已经重新创建PVC和PV。
3、总结
通过本文可以看出两点:
-
当k8s集群出现问题时一定要仔细查看日志,先看k8s本身事件信息,如果不能找到线索,紧接着查看内核日志,出现问题之后,正常情况下一定能够找到问题日志。 -
不要盲目删除数据,一定搞明白东西的原理之后再做删除操作,否则会带来不必要的麻烦。
当然要彻底解决此类问题,还是需要监控巡逻系统,出现磁盘告警之后能够立马通知到系统管理员或者自动做出进一步数据处理,不至于服务挂掉。如有问题,请关注公众号,加我微信,一起讨论!
推荐
压测nginx出现no live upstreams while connecting to upstream的问题分析
原创不易,随手关注或者”在看“,诚挚感谢!
本文分享自微信公众号 - 云原生技术爱好者社区(programmer_java)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Hive|如何避免数据倾斜
1. hive中桶的概述 对于每一个表(table)或者分区, Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分。Hive也是 针对某一列进行桶的组织。Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。 把表(或者分区)组织成桶(Bucket)有两个理由: (1)获得更高的查询处理效率。 桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用 Map 端连接 (Map-side join)高效的实现。比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大较少JOIN的数据量。 (2)使取样(sampling)更高效。 在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便。 创建带桶的 table createtablebucketed_user(idint,namestring)clusteredby(id)sortedby(na...
- 下一篇
6张图循序渐进讲透Kubernetes Ingress资源对象
Kubernetes Ingress 只是 Kubernetes 中的一个普通资源对象,需要一个对应的 Ingress 控制器来解析 Ingress 的规则,暴露服务到外部,比如 ingress-nginx,本质上来说它只是一个 Nginx Pod,然后将请求重定向到其他内部(ClusterIP)服务去,这个 Pod 本身也是通过 Kubernetes 服务暴露出去,最常见的方式是通过 LoadBalancer 来实现的。同样本文我们希望用一个简单清晰的概述,让你来了解 Kubernetes Ingress 背后的东西,让你更容易理解使用的 Ingress。 我们可以使用 Ingress 来使内部服务暴露到集群外部去,它为你节省了宝贵的静态 IP,因为你不需要声明多个 LoadBalancer 服务了,此次,它还可以进行更多的额外配置。下面我们通过一个简单的示例来对 Ingress 进行一些说明吧。 简单 HTTP server 首先,我们先回到容器、Kubernetes 之前的时代。 之前我们更多会使用一个(Nginx)HTTP server 来托管我们的服务,它可以通过 HTTP ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS8编译安装MySQL8.0.19
- CentOS关闭SELinux安全模块
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题