🏷 概述
本文介绍公有云容器服务(ACK,EKS, …)或自建K8S集群多场景下可能发生的磁盘高负载问题。并且给出相应的排查思路,解决措施,以及事后的规避策略
📋 问题现
现象 | 状态返回值 |
---|---|
节点状态显示node.kubernetes.io/disk-pressure | NoSchedule |
创建Pod失败 | ContainerCreating |
删除Pod失败 | Terminating |
无法通过kubectl exec操作进入容器 | UnexpectedAdmissionError |
📋 可能原因
Kubelet 支持 gc 和驱逐机制,每五分钟对未使用的镜像执行一次垃圾收集, 每分钟对未使用的容器执行一次垃圾收集。当(自建kubelet)配置不正确,或者节点上有其它非 K8S 管理的进程在不断写数据到磁盘,将会占用大量空间导致磁盘满载。对于kubelet参数的详细配置见官方文档
磁盘满载将影响 K8S 运行,主要涉及 kubelet 和容器运行时两个关键组件
📋 问题排查
判断容器路径是否被写满:
公有云容器服务(如ACK)创建节点时一般会推荐容器数据单独挂载数据盘。
具体路径可通过docker info
确认:
$ docker info|grep Dir
...
Docker Root Dir: /var/lib/docker
...
如果没有单独挂数据盘,则会使用系统盘存储。判断是否被写满:
$ df -h
Filesystem Size Used Avail Use% Mounted on
...
/dev/vda1 200G 200G 0 100% /
...
overlay 200G 200G 0 100% /var/lib/docker/overlay2/...
🔨 解决方法
处理步骤
- 当docker作为容器运行时,所属的CLI(dockerd)也会因此丢失响应无法正常重启来释放空间。因此需要先手动清理一些docker的日志或可写层文件。
通常会优先删除日志文件,再重启dockerd
cd /var/lib/docker/containers
# 找到比较大的容器目录
du -sh *
cd 506605a176678f87cbc4f61185eb72f68441836844eb56d5080f1c306282f412
# 删除log文件
cat /dev/null > 506605a176678f87cbc4f61185eb72f68441836844eb56d5080f1c306282f412-json.log
- 将该 node 标记不可调度,并将其已有的 pod 驱逐到其它节点,这样重启 dockerd 就会让该节点的 pod 对应的容器删掉,容器相关的日志(标准输出)与容器内产生的数据文件(可写层)也会被清理
#驱逐异常node,同时不可调度
kubectl drain {Node_Name}
#重启docker
systemctl restart dockerd
#节点恢复
kubectl uncordon {Node_Name}
🔨 如何规避此类事故
- 通过对节点的监控(列如使用观测云,Prometheus等)做磁盘使用率的自动化报警
- 根据监控检查节点上非容器的进程是否存在占用空间过多的现象
- 根据业务实际情况,优化限制Pod的
**<font style="color:rgb(51, 51, 51);">ephemeral-storage</font>**
- 建议避免使用
HostPath
,选择公有云的存储产品(如阿里云NAS)或自建的NFS等 - 节点挂载容器的数据磁盘扩容
- 日志尽量不落地存在Pod内