4

k8s中磁盘空间清理以及垃圾回收机制_年轻人,少吐槽,多搬砖的技术博客_51CTO博客

 2 years ago
source link: https://blog.51cto.com/u_11555417/5680563
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

k8s中磁盘空间清理以及垃圾回收机制

推荐 原创

老版本的kubernetes集群,容器运行时使用的是docker,经常会出现集群运行很久后节点的硬盘快跑满了,大文件主要集中在:/var/lib/dokcer/ovlery2,该目录下文件有块70G,/var/log/或者/var/log/journal下也有大日志文件占用空间。此时需要及时清理,不然会导致集群异常。

容器运行时使用的目录所在磁盘爆满

如果容器运行时使用的目录所在空间爆满,极有可能导致容器运行时无响应,例如docker相关命令会hang住,kubelet 日志也将看到 PLEG unhealthy,而 CRI 调用 timeout 也将导致容器无法创建或销毁,外在现象通常表现为 Pod 一直 ContainerCreating 或一直 Terminating。

docker 默认使用的目录

  • /var/run/docker:用于存储容器运行状态,通过 dockerd 的--exec-root 参数指定。
  • /var/lib/docker:用于持久化容器相关的数据。例如,容器镜像、容器可写层数据、容器标准日志输出及通过 docker 创建的 volume 等。

Pod 在启动过程中,可能会出现以下类似事件

#pod启动过程事件
Warning FailedCreatePodSandBox 53m kubelet, 172.22.0.44 Failed create pod sandbox: rpc error: code = DeadlineExceeded desc = context deadline exceeded
Warning FailedCreatePodSandBox 2m (x4307 over 16h) kubelet, 10.179.80.31 (combined from similar events): Failed create pod sandbox: rpc error: code = Unknown desc = failed to create a sandbox for pod "apigateway-6dc48bf8b6-l8xrw": Error response from daemon: mkdir /var/lib/docker/aufs/mnt/1f09d6c1c9f24e8daaea5bf33a4230de7dbc758e3b22785e8ee21e3e3d921214-init: no space left on device
Warning Failed 5m1s (x3397 over 17h) kubelet, ip-10-0-151-35.us-west-2.compute.internal (combined from similar events): Error: container create failed: container_linux.go:336: starting container process caused "process_linux.go:399: container init caused \"rootfs_linux.go:58: mounting \\\"/sys\\\" to rootfs \\\"/var/lib/dockerd/storage/overlay/051e985771cc69f3f699895a1dada9ef6483e912b46a99e004af7bb4852183eb/merged\\\" at \\\"/var/lib/dockerd/storage/overlay/051e985771cc69f3f699895a1dada9ef6483e912b46a99e004af7bb4852183eb/merged/sys\\\" caused \\\"no space left on device\\\"\""
#pod删除过程事件
Normal Killing 39s (x735 over 15h) kubelet, 10.179.80.31 Killing container with id docker://apigateway:Need to kill Pod

kubelet使用的目录爆满

默认的kubelet的目录为/var/lib/kubelet,通过 kubelet 的 --root-dir 参数指定,用于存储插件信息、Pod 相关的状态以及挂载的 volume

Kubelet 使用的目录所在磁盘空间爆满(通常是系统盘),新建 Pod 时无法成功进行 mkdir,导致 Sandbox 也无法创建成功,Pod 通常会出现以下类似事件:

​Warning UnexpectedAdmissionError 44m kubelet, 172.22.0.44 Update plugin resources failed due to failed to write checkpoint file "kubelet_internal_checkpoint": write /var/lib/kubelet/device-plugins/.728425055: no space left on device, which is unexpected.

当容器运行时为 docker 时发生磁盘爆满问题,dockerd 也会因此无法正常响应,在停止时会卡住,从而导致无法直接重启 dockerd 来释放空间。需要先手动清理部分文件腾出空间以确保 dockerd 能够停止并重启。恢复步骤如下:

  1. 手动删除 docker 的部分 log 文件或可写层文件。通常删除 log 文件,示例如下:
$ cd /var/lib/docker/containers
$ du -sh * # 找到比较大的目录
$ cd dda02c9a7491fa797ab730c1568ba06cba74cecd4e4a82e9d90d00fa11de743c
$ cat /dev/null > dda02c9a7491fa797ab730c1568ba06cba74cecd4e4a82e9d90d00fa11de743c-json.log.9 # 删除log文件
  • 删除文件时,建议使用cat /dev/null > 方式进行删除,不建议使用rm。使用rm 方式删除的文件,不能够被 docker 进程释放掉,该文件所占用的空间也就不会被释放。
  • log 的后缀数字越大表示时间越久远,建议优先删除旧日志。

2 执行以下命令,将该 Node 标记为不可调度,并将其已有的 Pod 驱逐到其它节点。

kubectl drain <node-name>

该步骤可以确保 dockerd 重启时将原节点上 Pod 对应的容器删掉,同时确保容器相关的日志(标准输出)与容器内产生的数据文件(未挂载 volume 及可写层)也会被清理。

3 重启docker

systemctl restart dockerd
# or systemctl restart docker

4等待 dockerd 重启恢复,Pod 调度到其它节点后,排查磁盘爆满原因并进行数据清理和规避操作。

5执行以下命令,取消节点不可调度标记。

清理docker镜像

在日常运维工作中,为了规避磁盘爆满的情况,需要及时清理docker镜像来时放磁盘空间。

以下是docker原生命令来清理镜像

journalctl --vacuum-size=20M #设置journal 日志最大为20M不保留不必要日志。
docker image prune -a --filter "until=24h" # 清除超过创建时间超过24小时的镜像
docker container prune --filter "until=24h" #清除掉所有停掉的容器,但24内创建的除外
docker volume prune --filter "label!=keep" #除lable=keep外的volume外都清理掉(没有引用的volume)
docker system prune #清理everything:images ,containers,networks一次性清理操作可以通过docker system prune来搞定
k8s中磁盘空间清理以及垃圾回收机制_垃圾回收
k8s中磁盘空间清理以及垃圾回收机制_垃圾回收_02
k8s中磁盘空间清理以及垃圾回收机制_重启_03

k8s垃圾回收机制

Kubelet 垃圾回收(kubelet-garbage-collection)负责自动清理节点上的无用镜像和容器。

Kubernetes 对节点上的所有镜像提供生命周期管理服务,这里的所有镜像是真正意义上的所有镜像,不仅仅是通过 Kubelet 拉取的镜像。当磁盘使用率超过设定上限 HighThresholdPercent​​ 时,Kubelet 就会按照 LRU 清除策略逐个清理掉那些没有被任何 Pod 容器(包括已经死亡的容器)所使用的镜像,直到磁盘使用率降到设定下限 ​LowThresholdPercent​ 或没有空闲镜像可以清理。此外,在进行镜像清理时,会考虑镜像的生存年龄,对于年龄没有达到最短生存年龄 ​MinAge​ 要求的镜像,暂不予以清理。

k8s中磁盘空间清理以及垃圾回收机制_docker_04

影响垃圾回收的关键参数

--image-gc-high-threshold:磁盘使用率上限,有效范围 [0-100],默认 85
--image-gc-low-threshold: 磁盘使用率下限,有效范围 [0-100],默认 80
--minimum-image-ttl-duration:镜像最短应该生存的年龄,默认 2 分钟

k8s版本1.24,主要是更改node节点的kubelet参数

vim /etc/kubernetes kubelet.env
k8s中磁盘空间清理以及垃圾回收机制_重启_05

增加启动参数,然后重启kubelet

systemctl restart kubelet
systemctl status kubelet -fl
k8s中磁盘空间清理以及垃圾回收机制_docker_06

确认参数配置上去

容器在停止运行(比如出错退出或者正常结束)后会残留一系列的垃圾文件,一方面会占据磁盘空间,另一方面也会影响系统运行速度。此时,就需要 Kubelet 容器回收了。要特别注意的是,Kubelet 回收的容器是指那些由其管理的的容器(也就是 Pod 容器),用户手动运行的容器不会被 Kubelet 进行垃圾回收。

  容器回收主要针对三个目标资源:普通容器、sandbox 容器以及容器日志目录。

 MaxPerPodContainer 与 MaxContainers 的设置,按照 LRU 策略,从 Pod 的死亡容器列表删除一定数量的容器,直到满足配置需求;对于 sandbox 容器,按照每个 Pod 保留一个的原则清理多余的死亡 sandbox;对于日志目录,只要没有 Pod 与之关联了就将其删除。Kubelet 的容器垃圾回收只针对 Pod 容器,非 Kubelet Pod 容器(比如通过 docker run 启动的容器)不会被主动清理。

k8s中磁盘空间清理以及垃圾回收机制_重启_07

影响容器垃圾回收的相关控制参数主要有三个:

--minimum-container-ttl-duration:从容器停止运行时起经过设置时间后,该容器标记为已过期将来可以被回收(只是标记,不是回收),默认值为1m0s # 1.22.5 不支持
--maximum-dead-containers-per-container:每个 pod 上可以留下运行结束之后的容器的个数,默认值为 2
--maximum-dead-containers:节点可保留的死亡容器的最大数量,默认值是 -1,这意味着节点没有限制死亡容器数量
k8s中磁盘空间清理以及垃圾回收机制_docker_08
k8s中磁盘空间清理以及垃圾回收机制_垃圾回收_09

关于kubelet的详细参数设置,请查看官方文档。

 ​kubelet | Kubernetes​

同时需要注意,以上参数将会在围栏版本删除。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK