一、问题现象及分析
环境说明
环境说明:java
-
centos7.3 -
Kubernetes1.14 -
docker 1.18.9
异常信息:kubectl get pod
发现服务被驱逐,而后在调度到其它节点过程当中出现问题,之因此出现问题是由于编排文件中添加了污点,已经标注该Pod不能被调度到其它节点。可是为何会出现Pod被驱逐,这却是个问题?查看/var/log/messages
中日志,发现大量镜像没法被拉取的错误,以下所示:linux
镜像被删除问题
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
等,也出现此类镜像没法拉取问题。nginx
出现这个问题,很容易理解,内网集群,在集群安装过程当中,镜像是经过复制过来的,可是执行docker images|grep k8s
发现k8s的镜像全不在了,难道有人为删除,要否则镜像为何会平白无故消失呢?web
因而又开始查看日志,又发现日志中存在此类信息,确认不是人为删除,而是kubelet回收掉了,具体日志以下所示:docker
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自身运行须要的镜像回收掉呢?这里先不过多解释,具体缘由,且看下文。centos
找不到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
,删除事后,不在刷此类错误。app
驱逐问题
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
查看了下磁盘,果真这台机器服务产生了大量日志,致使磁盘占用太高,可是磁盘虽然占用太高,为何要回收镜像呢?在官网查询了下,大概是这样介绍的:tcp
垃圾回收是
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中添加了污点,不能被调度到其它节点,最后致使启动失败。
二、问题解决
解决过程
因而找到占用磁盘数据所在文件夹,是一个以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。
三、总结
经过本文能够看出两点:
-
当k8s集群出现问题时必定要仔细查看日志,先看k8s自己事件信息,若是不能找到线索,紧接着查看内核日志,出现问题以后,正常状况下必定可以找到问题日志。 -
不要盲目删除数据,必定搞明白东西的原理以后再作删除操做,不然会带来没必要要的麻烦。
固然要完全解决此类问题,仍是须要监控巡逻系统,出现磁盘告警以后可以立马通知到系统管理员或者自动作出进一步数据处理,不至于服务挂掉。若有问题,请关注公众号,加我微信,一块儿讨论!
推荐
压测nginx出现no live upstreams while connecting to upstream的问题分析
原创不易,随手关注或者”在看“,诚挚感谢!
本文分享自微信公众号 - 云原生技术爱好者社区(programmer_java)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。