k8s集群出现Evicted状态的容器的解决办法

896 阅读1分钟

简单粗暴的办法

一把删除k8s集群中default命名空间下所有Evicted状态的容器的命令:

kubectl get pod -n default | grep Evicted | awk '{print $1}' | xargs kubectl delete pod -n default

注意: 此办法治标不治本。


治本的办法

首先要将本地的Docker Desktop的kubernetes context切换到出现问题的k8s集群,当然也可以在命令行终端用命令切换。

然后我们查看一个状态是Evicted的容器到底出了什么问题,在命令行终端执行如下命令:

kubectl describe pods nacos-server-test-78689747c5-26nn7

附上命令行终端的输出:

  ~ kubectl describe pods nacos-server-test-78689747c5-26nn7
Name:           nacos-server-test-78689747c5-26nn7
Namespace:      default
Priority:       0
Node:           cn-beijing.xxx.xx.xx.xx/
Start Time:     Sat, 30 Jul 2022 08:45:43 +0800
Labels:         app=nacos-server
                pod-template-hash=78689747c5
Annotations:    kubernetes.io/psp: ack.privileged
Status:         Failed
Reason:         Evicted
Message:        Pod The node had condition: [DiskPressure]. 
IP:             
IPs:            <none>
Controlled By:  ReplicaSet/nacos-server-test-78689747c5
Containers:
  nacos-server:
    Image:      registry.cn-beijing.aliyuncs.com/xxxxxx/nacos-server:v2.0.3
    Port:       8848/TCP
    Host Port:  0/TCP
    Requests:
      cpu:     500m
      memory:  1Gi
    Environment:
      NACOS_REPLICAS:              1
      MYSQL_SERVICE_DB_NAME:       <set to the key 'mysql.db.name' of config map 'nacos-cm'>  Optional: false
      MYSQL_SERVICE_PORT:          <set to the key 'mysql.port' of config map 'nacos-cm'>     Optional: false
      MYSQL_SERVICE_USER:          <set to the key 'mysql.user' of config map 'nacos-cm'>     Optional: false
      NACOS_SERVER_PORT:           8848
      NACOS_APPLICATION_PORT:      8848
      PREFER_HOST_MODE:            hostname
      MODE:                        standalone
      SPRING_DATASOURCE_PLATFORM:  mysql
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-mg4b2 (ro)
Volumes:
  default-token-mg4b2:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-mg4b2
    Optional:    false
QoS Class:       Burstable
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:          <none>
  ~ 

我们看一下第10~12行可知,当前这个容器的状态是失败,原因是Evicted,具体的失败原因也告诉我们了:Pod The node had condition: [DiskPressure],直译过来就是“这个节点出状况了:磁盘压力”,其实就是该节点的磁盘空间不足了。我们马上能想到的解决方案就是ssh登上节点清理一下垃圾文件。

还有一种可能的错误信息是:The node was low on resource: ephemeral-storage. Container NAME was using 16658224Ki, which exceeds its request of 0。跟上面那种[DiskPressure]的报错的根本原因是一样的,都是磁盘空间不足,但是导致的后果不太一样。上面那种是导致容器启动不了,这种报错是导致容器会在运行中被杀死。

我们通过ssh登录节点以后,输入如下命令,查看一下Docker管理的磁盘空间:

docker system df

截图中的reclaimable列的数据是可回收的空间:容器镜像可以回收3.83G的磁盘空间,容器可以回收29MB的空间。下面我们就是要把这将近4个G的空间回收掉。

回收之前,我们先用df -h命令看一下宿主机的磁盘空间大小,到最后做对比。

可以看到目前宿主机的磁盘空间占用是70%。我们再来重点看一下/var/lib/docker/overlay2这个文件夹的磁盘占用,输入命令du -ch -d 1

这一个文件夹占用了13个G!后面我们做的操作其实都是回收这个文件夹占用的空间。

接下来我们先排空节点,执行命令:

kubectl drain this_node --ignore-daemonsets --delete-local-data

再清空docker占用的磁盘空间:

docker system prune -af --volumes

我们删除了在这台节点上的所有的镜像、容器和volume。我们再执行命令du -ch -d 1看一下/var/lib/docker/overlay2文件夹的磁盘占用。

只剩下2.8G的文件了。我们继续把这些文件都删掉。执行命令rm -rf *之后,还有一些文件夹遗留下来,暂时删除不了,因为还有容器用到,我们先放一下。

然后我们停止并删除所有的容器:

docker stop $(docker ps -q) && docker rm $(docker ps -a -q)

-q的意思是只返回容器id。

此时再看一下/var/lib/docker/overlay2,已经清空了。我们需要再次执行如下命令,把刚才停掉并删除的容器的垃圾清理干净:

docker system prune -af --volumes

我们执行命令df -h看一下现在的效果:

我们成功回收了40%的磁盘空间。

最后重启该节点。等节点恢复运行后,将节点设置为可调度状态,就完成了。