解决 Kubernetes 中节点经常性 DiskPressure(磁盘压力) 的问题
文章目录
!版权声明:本博客内容均为原创,每篇博文作为知识积累,写博不易,转载请注明出处。
系统环境:
- Docker 版本:19.03.8
- Kubernetes 版本:1.20.1
- 操作系统版本:CentOS 7.8
参考地址:
一、问题描述
在日常操作维护 Kubernetes 过程中我们会经常遇到很多问题,其中经常收到的告警信息就是节点磁盘压力,即 DiskPressure
警告。当出现该警告不久后 Pod 会被驱逐,甚至节点机器的 Docker 镜像也被清理。在生产中这些情况是不能忍受的,我们探究一下是什么原因导致的这些,以及如何提前预防并解决相关问题。
二、问题分析
首先提出几个问题,然后分别查找相关资料,对具体的疑问一一查找答案。只有了解这些问题如何产生,才能找到具体解决办法。
提出的问题如下:
① Kubernetes 依靠什么组件对节点磁盘进行监控
根据 Kubernetes 官方文档描述,在 Kubernetes 集群中,节点磁盘使用量的监控是交给 Kubelet 组件完成的,它会对节点资源使用情况进行分析,等达到一定条件后会执行发出内存、磁盘、pid 资源压力警告。
② Kubelet 监控节点的哪些文件系统
在 Kubernetes 节点组件 Kubelet 目前只支持监控两种文件系统分区,分别为:
- nodefs: kubelet 相关的文件系统,里面存储了 Pod 挂载的卷、守护程序日志等。
- imagefs: 容器文件系统,里面存储了容器运行时用于保存镜像和容器可写层。
Kubelet 监控文件系统是通过 Google 的 cAdvisor
组件完成的,该组件专用于监控容器运行环境,当监控到上面列出的文件系统达到一定量后将会发出 DiskPressure
告警,等达到指定阈值,将会对容器及无用镜像相关资源进行清理。
③ Kubelet 根据什么指标对 Pod 执行驱逐的
这个信息在 Kubernetes 官方文档中,Kubelet 会根据以下指标判断是否对 Pod 驱逐进行驱逐:
- nodefs.available: kubelet 相关的文件系统剩余可用存储空间比例。
- nodefs.inodesFree: kubelet 相关文件节点表 inodes 剩余可用存储空间比例。
- imagefs.available: 容器运行时文件系统可用存储空间比例。
- imagefs.inodesFree: 容器运行时 inodes 剩余可用存储空间比例。
④ Kubelet 根据指标达到什么条件才会执行 Pod 驱逐
经过 Kubernetes 文档的介绍,Kubelet 会对下面指标进行判断,当到达设置的条件后,会执行强制驱逐 Pod:
- memory.available<100Mi: 当内存下降到 100Mi 时 kubelet 开始驱逐 Pod。
- nodefs.available<10%: 当 kubelet 相关存储可用的存储不足 10% 时开始驱逐 Pod 及其容器来释放磁盘空间。
- imagefs.available<15%: 当容器运行时文件系统可用存储空间不足 15% 时开始驱逐 Pod,并且删除没有被使用的镜像来释放空间。
- nodefs.inodesFree<5%: (仅 Linux 系统): 当容器运行时 inodes 可用存储空间不足 5% 时开始驱逐 Pod 及其容器来释放磁盘空间。
⑤ Kubernetes 触发 DiskPressure 告警时造成的影响
当触发 DiskPressure
告警时,会产生如下影响:
- 驱逐 Pod
- 删除未使用的容器
- 阻止新创建的 Pod 调度到该节点中
⑥ 什么原因导致经常出现 DiskPressure 警告
推测经常出现这个警告的原因可能是:
- 默认情况下 docker 会将自己的持久化文件存储到
/var/lib/docker
目录下,这个目录占用空间比较大,导致/var
目录挂载的磁盘容易被占满。 - 默认情况下 kubelet 会将自身的 Pod 运行时相关数据存储在
/var/lib/kubelet
目录下,这个目录空间比较大,导致/var
目录挂载的磁盘容易被沾满。 - 默认情况下 Docker、Kubernetes 和系统等相关日志默认都会存储到
/var/log
目录下,日志相关文件占用空间非常大,导致/var
目录挂载的磁盘容易被沾满。
上面三个默认配置,一个是 kubelet,一个是 docker 的,还有就是相关日志配置的,并且发现 var
目录一般分配的空间不是很大,所以 /var
目录挂载的磁盘空间非常容易被日志文件占满。
除此之外,还有一种可能,那就是当发生 DiskPressure
告警时,此时磁盘其实可用存储空间还很充足,例如 1TB
存储空间,使用率 80%
提示 DiskPressure
告警,这时候其实还有 200GB
可用存储空间。所以,这个磁盘告警比例需要根据节点磁盘的真实情况进行调整。
三、解决问题
注意: 下面的操作最好在集群搭建初期修改,如果已经在现网环境文档运行,修改请谨慎!
更改 Docker 存储目录
既然 Docker
目录默认在 /var/lib/docker
目录下,且这个目录所挂载的磁盘容易被占满,所以我们修改 Docker
配置,将存储的数据单独存放到挂载其它大磁盘的目录中。
(1) 查看 Docker 状态,根据显示的信息定位 Docker 存储配置文件的位置
1$ systemctl status -l docker
显示如下信息:
1● docker.service - Docker Application Container Engine
2 Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
3 Active: active (running) since 二 2021-06-15 10:40:07 CST; 3h 20min ago
4 Docs: https://docs.docker.com
5 Main PID: 1676 (dockerd)
6......
可以看到配置文件所在目录是 /usr/lib/systemd/system/
,配置文件是 docker.service
。
(2) 设置 Docker 数据存储目录
打开 Docker 配置文件
1$ vi /usr/lib/systemd/system/docker.service
找到 ExecStartExecStart=/usr/bin/docker
这行,在后台添加 --graph <Docker数据存储目录>
,例如这里目录为 /apps/data/docker
则可以按如下配置:
1...
2ExecStart=/usr/bin/docker --graph /apps/data/docker
3...
更改 kubelet 存储目录与告警阈值
既然 Kubelet
目录默认在 /var/lib/kubelet
目录下,且这个目录所挂载的磁盘容易被占满,所以我们修改 Kubelet
配置,将存储的数据单独存放到挂载其它大磁盘的目录中。并且根据磁盘真实大小,调整 Kubelet
触发 DisPress
告警的比例。
(1) 查看 kubelet 状态,根据显示的信息定位 kubelet 存储配置文件的位置
输入下面命令查看 kubelet 状态信息:
1$ systemctl status -l kubelet
显示如下信息:
1● kubelet.service - kubelet: The Kubernetes Node Agent
2 Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
3 Drop-In: /usr/lib/systemd/system/kubelet.service.d
4 └─10-kubeadm.conf
5 Active: active (running) since 二 2021-06-15 10:40:03 CST; 1h 57min ago
6......
可以观察到配置文件目录所在位置是 /usr/lib/systemd/system/kubelet.service.d/
,配置文件是 10-kubeadm.conf
。
(2) 查看 EnvironmentFile 配置文件所在位置
打开 kubelet 配置,查看 kubelet 配置文件:
1$ cat /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
可以看到如下内容:
1[Service]
2Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
3Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
4EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
5EnvironmentFile=-/etc/sysconfig/kubelet
6ExecStart=
7ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS
可以看到 EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
和 EnvironmentFile=-/etc/sysconfig/kubelet
俩行配置,其中 /var/lib/kubelet/kubeadm-flags.env
是 "kubeadm init" 和 "kubeadm join" 在运行时生成的文件,我们不需要管理该文件。而 /etc/sysconfig/kubelet
文件则是供我们用户添加自定义参数的,所以我们需要在这个配置文件中添加我们自定义配置参数。
(3) 编辑 /etc/sysconfig/kubelet 配置文件
1$ vi /etc/sysconfig/kubelet
然后在 KUBELET_EXTRA_ARGS=
后面添加参数 -root-dir=<新的kubelet存储目录>
:
1KUBELET_EXTRA_ARGS=--root-dir=/apps/data/kubelet --eviction-hard=nodefs.available<5% --eviction-hard=imagefs.available<5%
- --root-dir=/apps/data/kubelet: 设置 kubelet 数据存储在 /apps/data/kubelet 目录下。
- --eviction-hard=nodefs.available<5%: 设置当 kubelet 相关存储可用的存储不足 5% 时开始驱逐 Pod。
- --eviction-hard=imagefs.available<5%: 当容器运行时文件系统可用存储空间不足 5% 时开始驱逐 Pod。
上面的大小限制也可以改成具体的数值,例如
--eviction-hard=imagefs.available<10Gi
,则表示容器运行时存储小于 10Gi 时进行驱逐。
(5) 重启 daemon-reload 和 kubelet
1$ systemctl daemon-reload && systemctl restart kubelet
(6) 再次查看 kubelet 状态,观察上面配置是否生效
再次支持下面命令查看 kubelet 状态:
1$ systemctl status -l kubelet
观察显示的 kubelet 参数是是否存在上面我们配置的参数:
1● kubelet.service - kubelet: The Kubernetes Node Agent
2 Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
3 Drop-In: /usr/lib/systemd/system/kubelet.service.d
4 └─10-kubeadm.conf
5 Active: active (running) since 二 2021-06-15 13:55:29 CST; 1s ago
6 Docs: https://kubernetes.io/docs/
7 Main PID: 130986 (kubelet)
8 Tasks: 14
9 Memory: 26.1M
10 CGroup: /system.slice/kubelet.service
11 └─130986 /usr/bin/kubelet
12 --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf
13 --kubeconfig=/etc/kubernetes/kubelet.conf
14 --config=/var/lib/kubelet/config.yaml
15 --network-plugin=cni
16 --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.2
17 --root-dir=/apps/data/kubelet
18 --eviction-hard=nodefs.available<5%
19 --eviction-hard=imagefs.available<5%
可以观察到上面信息中已经加载了 root-dir
、--eviction-hard
参数,说明配置已经生效。
如果本文对你有帮助,可以关注我的公众号"小豆丁技术栈"了解最新动态,顺便也请帮忙 github 点颗星哦~感谢~
!版权声明:本博客内容均为原创,每篇博文作为知识积累,写博不易,转载请注明出处。