Home / PostsPost

k8s的一个节点的kubelet 报了这么一个错 GenericPLEG: Unable to retrieve pods: rpc error: code = ResourceExhausted desc = grpc: received message larger than max (4195184 vs. 4194304)

嘟噜聪2020/12/15 13:57:27 [Docker] [Kubernetes] [k8s] [容器] [开普勒] [开普勒云平台] 124人已阅

简介 在开普勒上发现了一个神奇的问题,一个应用只设置启了一个pod,但却显示了两个并且其中一个没有流量,一种假死的状态,删除后就没有不会重新再启一下。既然看到了,那就顺手执行了一下 `journalctl -exf` 发现了一个错误: `"GenericPLEG: Unable to retrieve pods: rpc error: code = ResourceExhausted desc = grpc: received message larger than max (4195184 vs. 419

k8s的一个节点的kubelet 报了这么一个错 GenericPLEG: Unable to retrieve pods: rpc error: code = ResourceExhausted desc = grpc: received message larger than max (4195184 vs. 4194304)

在开普勒上发现了一个神奇的问题,一个应用只设置启了一个pod,但却显示了两个并且其中一个没有流量,一种假死的状态,删除后就没有不会重新再启一下。

既然看到了,那就顺手执行了一下 journalctl -exf 发现了一个错误: "GenericPLEG: Unable to retrieve pods: rpc error: code = ResourceExhausted desc = grpc: received message larger than max (4195184 vs. 4194304)"

顺手就get了一下nodes: kubectl get nodes,发现有一个节点挂掉了。

先说解决方案

  1. 进入master节点执行命令,先把问题节点禁止被调度到
  2. 删除所有引起问题的的Deployment、CronJob等其他类型的资源
  3. 把问题节点上的pods全部清除掉,让其自动飘到其他节点
  4. 清理问题节点的不常使用的容器
  5. 重启动问题节点的 docker 和 kubelet
  6. 恢复问题节点的调度
# 让问题节点不被调度
$ kubectl cordon k8s-node-02 
# 驱逐问题节点上所有的pod,此步可能会卡住 通常情况下还需要单独手动删除,因为此时kubelet已经废了... 做不到没关系进入下一步
$ kubectl drain kpl-k8s-node-02 --ignore-daemonsets --delete-local-data --force
# 进入问题节点
$ ssh k8s-node-02
# 查看节点容器占用,确认没啥大问题
$ docker system df
# 清理不常使用的容器,或是一些没用的
$ docker system prune
# 进入 /var/lib/containers 目录查看是否都清理完
$ ls /var/lib/containers
# 重启Docker及Kueblet
$ systemctl restart docker && systemctl restart kubelet
# 查看是否还有其他报错
$ journalctl -exfu kubelet
# 回到master节点并放开问题节点的调度
$ ssh k8s-master-01
$ kubectl uncordon k8s-node-02

执行完上面操作后,问题解决。

我们这目前生产的版本是 Kubernetes v1.10.x 是存在该问题的: https://github.com/kubernetes/kubernetes/issues/63858

在github上有这个Issue。该问题应该是在 v1.12.7 之后的版本修复了。

为什么会产生这个错误

Dec 14 09:55:55 kpl-k8s-node-02 kubelet[19456]: E1214 09:55:55.210671 19456 generic.go:197] GenericPLEG: Unable to retrieve pods: rpc error: code = ResourceExhausted desc = grpc: received message larger than max (4195184 vs. 4194304)

这次的问题跟上次一样,也是意外之中发现的,然后又偷偷解决掉了。上篇是处理ETCD的问题: 处理一次k8s、无法获取podIP的心路历程,这次遇到问题就淡定多了,至少不是整集群的问题。

这又是一个不能靠重启解决的问题...差评...

从kubelet报的错误来看应该是kubelet与cri-o的通信超过了grpc的最大限制。但为什么会有这么多的数据呢?我们pods数量应该没多少呀。

试着查看一下集群所有的pods状态

$ kubectl get pods --all-namespaces -o wide

似乎有点慢,查出来的结果居然是有上万个pod,并且绝大部分的pod都是失败的。

顺着这个方向继续查。最终确认是因为CronJob创建的pod因连接问题失败了,而CronJob所设置的规则是失败会重新尝试启动,如此循环下去CronJob会无限制的创新pod,那些这pod一直失败,占用资源。

既然问题已找到,那就开始解决问题。

  1. 在能查看到失败pod的日志情况下先查一下,保留现场,这很重要,方便查为什么这个任务会失败
  2. 保留CronJob的yaml,做一个备份
  3. 尝试删除对应用CronJob的副本
  4. 如果依然还在调度任务,尝试删除对应的CronJob

处理好不再产生新的垃圾pod之后,来处理一下遗留的问题。

按上开头所说的步骤以此执行。

把问题节点设置为不被调度之后,将该问题节点上的pod全部驱逐出去,并做好重启服务器的最坏打算。 因为产生的巨量的pod,该节点上的kubelet已经无法正常工作了,也别指望能让kubelet来清理掉无用容器。就算是手动重启动了docker 及kubelet,问题依然会存在。

进入到容器目录后可以看到该目录有巨量的目录,目测(・_・;有超过过1万多个目录,一个目录下最多可以放下65536个目录,应该是没超过这个限制的。

千万别急着使用rm -rf *,咱们应该按正常流程来走。

使用以下Docker命令,查看Docker空间使用量:

$ docker system df
TYPE                TOTAL               ACTIVE              SIZE                RECLAIMABLE
Images              1843                96                  93.31GB             87.74GB (94%)
Containers          291                 268                 715.6MB             5.662MB (0%)
Local Volumes       5                   4                   135.8MB             67.89MB (50%)
Build Cache                                                 0B                  0B

再执行清理命令:

$ docker system prune

稍等片刻之后会完成。再查看目录只剩下几个必须的目录了,我这里只留下了filebeat、calico-node的容器。

清理完成之后,把Docker及kubelet都重启一下:

$ systemctl restart docker && systemctl restart kubelet

尾巴

通过又一次偷偷化解的危机,我们应该好好思考一下,到底是因为监控不够多,还是使用的姿势不对?监控应该要多细致才也避免各种各样的神奇问题?

还是那句话: "没事上去点点,说不定会有您意想不到的惊喜(惊吓)。(苦笑)"

谢谢

很赞哦! (4)

文章评论

站点信息

  • 微信公众号