如上图,今天测试环境的K8S平台出现了一个问题,其中的一个容器报错:Free disk space below threshold. Available: 3223552 bytes (threshold: 10485760B),意思服务器硬盘空间不够了。这个问题怎么产生的,又怎么解决的呢?
一、问题分析
这个容器是部署在k8s集群的一个工作节点,该工作节点的磁盘使用率已经达到了99%,但是Kubernetes的垃圾回收机制似乎没有生效,可能有以下几个原因:
1、镜像垃圾回收阈值设置过高
- 默认情况下,
--image-gc-high-threshold
的值为85,表示只有当磁盘使用率达到85%时才会触发镜像垃圾回收。 - 如果你的节点磁盘使用率在达到85%之前就已经接近满载,那么垃圾回收机制可能无法及时释放足够的空间。
2、死亡容器和未使用镜像占用空间较小
- Kubernetes的垃圾回收机制主要针对已停止的容器(dead containers)和未使用的镜像。
- 如果你的节点上运行的大部分容器都是活动的,并且镜像都在被使用,那么垃圾回收可能无法释放太多空间。
3、其他非容器相关的文件占用了大量磁盘空间
- Kubernetes的垃圾回收只会清理停止的容器和未使用的镜像,但不会删除其他文件。
- 如果你的节点上有大量非容器相关的文件(如日志文件、数据文件等)占用了磁盘空间,垃圾回收机制无法处理这些文件。
4、垃圾回收机制的执行频率不足
- Kubernetes的垃圾回收机制是周期性运行的,默认情况下每分钟运行一次。
- 如果你的节点磁盘使用率增长非常快,垃圾回收的执行频率可能跟不上磁盘空间的消耗速度。
二、解决问题
为了解决这个问题,可以尝试以下几种方法:
1、手动清理
- 你可以使用
docker container prune
命令删除所有停止的容器。 - 使用
docker image prune
命令删除所有悬空(dangling)镜像,即没有被任何容器引用的镜像。
2、调整参数
将--image-gc-high-threshold
和--image-gc-low-threshold两个参数的值进行调整
,使其更接近实际的磁盘使用情况。例如,你可以将--image-gc-high-threshold
设置为75,将--image-gc-low-threshold
设置为70,以便在磁盘使用率较高时更积极地进行垃圾回收。
3、定期清理
识别并清理节点上占用大量磁盘空间的非容器相关文件,如日志文件、临时文件等。
4、扩容
考虑增加节点的磁盘容量或向集群中添加更多节点,以分散工作负载和存储压力。
5、优化应用
如果可能,尝试优化应用程序和工作负载,减少不必要的磁盘空间使用。
本次问题处理中,我们先用手动删除所有停止的容器和镜像,然后调整了--image-gc-high-threshold和--image-gc-low-threshold参数的值,改为75,最后配置了一个监控任务,磁盘空间超过80%就提示告警。
请注意,在对生产环境进行任何更改之前,务必仔细评估可能的影响并制定合适的策略。根据你的具体情况和需求,选择最适合的方法来解决节点磁盘空间不足的问题。
三、相关知识
除了上面使用的方法,我们要在Kubernetes中自动清理过期的容器和镜像,还可可以利用Kubernetes的内置机制和一些第三方工具。下面是几种方法:
1、配置容器的 restartPolicy
和 terminationGracePeriodSeconds
- 对于一次性任务或短期任务,可以将Pod的
restartPolicy
设置为Never
或OnFailure
,确保容器退出后不会自动重启。 - 设置合适的
terminationGracePeriodSeconds
值,控制容器优雅终止的宽限期,超过该时间后Kubernetes会强制删除容器。
2、使用 TTL Controller
自动清理已完成的Job
- Kubernetes的
TTL Controller
可以自动清理已完成的Job及其关联的Pod。 - 在Job的spec中设置
.spec.ttlSecondsAfterFinished
字段,指定Job完成后的TTL时间,超过该时间Job和Pod会被自动删除。
3、利用第三方工具如 kube-janitor
或 descheduler
kube-janitor
是一个自动清理Kubernetes资源的工具,可以根据配置的规则定期清理过期的资源,包括Pod、Job、ConfigMap等。descheduler
可以根据策略驱逐Pod,释放节点资源,可以用于清理长时间运行的Pod。
4、使用自定义脚本或控制器
- 可以编写自定义脚本或控制器,定期查询和清理过期的容器和镜像。
- 可以利用Kubernetes API或客户端库如
client-go
来实现自定义逻辑。
以上是一些常见的方法,可以根据具体需求选择合适的方案。同时,也要注意配置适当的资源限制和请求,避免不必要的资源浪费。定期监控集群的资源使用情况,及时调整和优化。