Kubernetes Node 磁盘爆满问题排查
原因分析
kubelet
有gc
和驱逐
机制,通过 --image-gc-high-threshold
, --image-gc-low-threshold
, --eviction-hard
, --eviction-soft
, --eviction-minimum-reclaim
等参数控制 kubelet
的 gc
和驱逐策略
来释放磁盘空间,如果配置正确的情况下,磁盘一般不会爆满。
通常导致爆满的原因可能是 配置不正确或者节点上有其它非 K8S 管理的进程在不断写数据到磁盘
占用大量空间导致磁盘爆满。
影响面
Node节点的影响面:kubelet
和 容器运行时
这两个最关键的组件
kubelet
一般不会单独挂盘,直接使用系统磁盘,因为通常占用空间不会很大.容器运行时
单独挂盘的场景比较多
当磁盘爆满的时候我们也要看 kubelet
和 容器运行时
使用的目录是否在这个磁盘,通过 df
命令可以查看磁盘挂载点。
容器运行时
目录磁盘爆满
容器运行时
使用的目录磁盘空间爆满,可能会造成容器运行时无响应
,比如 docker,执行 docker 相关的命令一直 hang 住; kubelet 日志也可以看到 PLEG unhealthy
,因为 CRI
调用 timeout
,当然也就无法创建或销毁容器,通常表现是 Pod 一直 ContainerCreating
或 一直 Terminating
docker 默认使用的目录主要有:
/var/run/docker
: 用于存储容器运行状态,通过dockerd
的--exec-root
参数指定。/var/lib/docker
: 用于持久化容器相关的数据,比如容器镜像、容器可写层数据、容器标准日志输出、通过 docker 创建的 volume 等
kubelet
目录磁盘爆满
kubelet
目录磁盘空间爆满(通常是系统盘),新建 Pod
时连 Sandbox
都无法创建成功,因为 mkdir
将会失败.
kubelet 默认使用的目录是 /var/lib/kubelet
, 用于存储插件信息、Pod 相关的状态以及挂载的 volume (比如 emptyDir, ConfigMap, Secret),通过 kubelet 的 --root-dir
参数指定。
清理数据盘
- 容器运行时使用的 Docker,我们无法直接重启 dockerd 来释放一些空间,因为磁盘爆满后 dockerd 无法正常响应,停止的时候也会卡住。我们需要先手动清理一点文件腾出空间好让 dockerd 能够停止并重启。
手动清理一些 docker 的 log 文件
或可写层文件
, 通常删除 log:
$ cd /var/lib/docker/containers
$ du -sh * # 找到比较大的目录
$ cd 730c1568ba06cba74xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
$ cat /dev/null > 730c1568ba06cba74xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-json.log.9 # 删除log文件
注意: 使用 cat /dev/null > file
方式删除而不用 rm
,因为用 rm
删除的文件,docker 进程可能不会立刻释放文件,空间也就不会释放;log 的后缀数字越大表示越久远
,先删除旧日志。
- 将该 node 标记不可调度,并将其已有的 pod 驱逐到其它节点,这样重启 dockerd 就会让该节点的 pod 对应的容器删掉,容器相关的日志(标准输出)与容器内产生的数据文件(没有挂载 volume, 可写层)也会被清理:
$ kubectl cordon <node-name>
$ kubectl drain <node-name>
$ systemctl restart dockerd
等重启恢复,pod 调度到其它节点,排查磁盘爆满原因并清理和规避,然后取消节点不可调度标记:
$ kubectl uncordon <node-name>
「如果这篇文章对你有用,请随意打赏」