一次 K8s 故障诊断:从 CPU 高负载到存储挂载泄露根源揭示

一、背景

现代软件部署中,容器技术已成为不可或缺的一环,在云计算和微服务架构中发挥着核心作用。随着容器化应用的普及,确保容器环境的可靠性成为了一个至关重要的任务。这就是容器SRE(Site Reliability Engineering,站点可靠性工程)的职责所在。容器SRE工程师不仅要保证系统的高可用性,还需要优化运行效率,确保系统在各种压力和突发情况下的韧性。

然而,容器SRE的工作常常是背后默默的付出,通常涉及着大量看似琐碎却极其关键的维护任务。例如某一天,你可能发现K8s集群中的Kubelet进程CPU使用异常飙高,这就需要容器SRE工程师立即介入,进行深入的诊断和问题排查,避免类似问题成为生产环境中的隐患。这种排查过程往往涉及复杂且难以预测的环境,通常需要SRE工程师具备高度的专业知识和快速应变能力。因此,虽然容器SRE工程师的努力可能不为大众所见,但对于现代依赖软件和云服务的任何系统来说,这些工作显得尤为严谨和重要。

通过本文,我们将深入探讨容器SRE在日常工作中面临的挑战和如何通过专业技能和创新技术方案来定位和解决问题,确保技术平台的稳健运行。这些看似“摸不着头脑”的琐碎事务,实际上是确保企业技术架构弹性和可靠性的关键所在。

2024.4.19日,一条普通的宿主机Node CPU告警引起了我们的关注,自此开始了排查的旅程......

图片

二、问题现象

容器单机上容器管理组件Kubelet CPU和内存过高,Kubelet进程的资源使用在top命令中一直处于遥遥领先的位置,CPU占用2022%(为正常实例200倍),内存占用8.6G,这里我们以机器43.113为例排查分析。

图片

我们从集群中随机抽取多台配置相同的机器进行对比分析:正常的Kubelet CPU占用26.7%,内存占用仅在700M左右,K8s单机的Kubelet进程作为单机的管控程序,资源占用不会出现如此大的波动。

图片

经过单机和多台主机对比分析,我们可以确定主机43.113的Kubelet进程出现了异常,那么是什么原因导致的CPU和内存使用飙升呢?

首先我们想到的是从宿主机43.113整体状况和Kubelet进程两个方向进行分析,从宿主机维度分析为了确定是否单机负载或者进程异常导致Kubelet异常,从进程维度排查是为了定位Kubelet资源异常使用具体原因。当然,这两个维度的分析也并不是独立进行,中间分析过程中可能会涉及到多次的交替验证过程。

三、问题分析

    1. 单机整体分析

图片

首先,我们整体交代一下43.113整体环境信息:

  • 硬件规格及资源:vCPU为48核、内存310GiB;

  • 操作系统内核:操作系统为云厂商提供的操作系统,内核版本4.19.91-26.6.al7.x86_64;

  • 近期负载:1分钟、5分钟、15分钟负载分别为48.03、43.91和42.94,与单机的48核vCPU来讲,负载正常(一般的排查经验是运行负载小于<1.5vCPU,则表明机器负载并不过高,但是高负载并完全对等CPU饱和)。

通过在主机上运行top命令,我们可以发现尽管单机负载在合理范围内,但是单机的进程数量存在过大的情况,48个vCPU单机运行的进程总量有20155个(Linux内核中一般称作Task任务),运行中的进程仅有10个,处于睡眠状态(Sleeping)的进程有13265个。为了定位进程的数量异常,我们继续使用“ps | wc -l”命令进行了再次确认,系统中的确存在2万多个进程。

$ ps aux|wc -l20135

基于ps详情进行进一步确认分析,我们可发现数量众多的“[jbd2/vdnx-y]/[jbd2-ckpt/vdx]”格式的进程,“[xxx]”格式的任务属于内核线程,由内核进行管理和分配,比如我们常见的用于管理内核软中断管理的[ksoftirqd/7]。内核中的线程一般都是针对某类资源进行管理,前缀一般为会表明内核作用,比如“ksoftirqd”就代表内核软中断处理,7表示为系统CPU#7上运行。通过查询资料,确认了“[jbd2/vdx-y]”格式中的jbd2代表的是:Journaling Block Device2,jbd2是Ext4文件系统中实现日志文件系统的组件,其工作原理是通过记录对文件系统所做的更改来提高数据的完整性和恢复能力。在系统崩溃或非正常关机的情况下,日志可以用来恢复文件系统到早期一致的状态,减少数据损坏的风险。

通过内核线程数量确认,内核线程总量为19798,为以[jbd2/vdx-y]开头的内核线程有12769个,[ext4-rsv-conver]内核线程的数量为6385个,两者总和为19154个,占内核线程的97%。同时在进程详情中,还有个明显的特征基本上3个内核线程为一组,比如[jbd2/vdfiw-8]、[jbd2-ckpt/vdfiw]和[ext4-rsv-conver],后续类似基本上都有这种特征,初步判断这一组内核线程是针对设备vdfiw(/dev/vdfiw-8)在内核中的进行管理的一组内核线程。


$ ps aux|grep '\['|wc -l   # 内核线程总量
19798$ ps aux|grep '\[jbd2'|wc -l # 内核线程以 jbd2 开头的总量
12769$ ps aux|grep -v '\[jbd2'|grep ext4-rsv-conver |wc -l  # 内核中 ext4-rsv-conver 的线程数量
6385$ ps aux|grep '\['|more
...
root        1951  0.0  0.0      0     0 ?        S    Feb01   0:00 [jbd2/vdfiw-8]
root        1952  0.0  0.0      0     0 ?        S    Feb01   0:00 [jbd2-ckpt/vdfiw]
root        1953  0.0  0.0      0     0 ?        I<   Feb01   0:00 [ext4-rsv-conver]root        2078  0.0  0.0      0     0 ?        I<    2023   4:26 [kworker/6:1H-kb]root        3009  0.0  0.0      0     0 ?        S    Feb01   0:00 [jbd2/vdfjp-8]
root        3010  0.0  0.0      0     0 ?        S    Feb01   0:00 [jbd2-ckpt/vdfjp]
root        3011  0.0  0.0      0     0 ?        I<   Feb01   0:00 [ext4-rsv-conver]
...

以设备vdfiw为例:

  • jbd2/vdfiw-8是一个与jbd2(Journaling Block Device version 2)内核文件操作日志系统存储的的内核线程;

  • jbd2-ckpt/vdfiw是一个特定于jbd2的内核线程,其中ckpt代表“checkpoint”(检查点)。在jbd2和使用它的文件系统(如ext4)中,检查点是一种机制,用于定期将日志中的信息转移到文件系统本身,以减少在系统崩溃后恢复所需的时间;

  • ext4-rsv-conver则是ext4由实现用于处理来自写回的转换工作,即“需要未写入的扩展处理并保留事务的已完成IO”。

文件系统是否启用日志文件功能,可通过dumpe2fs命令进程检查确认:

dumpe2fs /dev/vdc | grep has_journal

dumpe2fs 1.43.5 (04-Aug-2017)

Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize

通过“df”命令查看设备vdfiw的详情:

df |grep vdfiw/dev/vdfiw                                                                                  308521792    56841364     251664044  19% /var/lib/kubelet/plugins/kubernetes.io/csi/pv/d-bp1iau7367wkpf6xqdpv/globalmount

本机磁盘/dev/vdfiw为通过K8s存储机制动态挂载的磁盘设备,在K8s持久化存储通过PV/PVC机制进行管理,由单机负责管理存储的进程负责磁盘的创建和挂载(这里的场景为ESSD远端云盘)。简单一点讲,在K8s中,持久卷(PV)是集群中预先配置的一块存储空间,而持久卷申领(PVC)则像是存储空间的“订票”,用户通过PVC来请求使用特定大小和特性的存储空间。通过PV/PVC机制就可实现使用存储的业务实例,不再用关心存储空间的创建,只需要声明所需存储空间即可,整个存储空间分配、挂载和释放的过程都是有K8s系统中的存储插件负责(存储一般为云厂商提供)。

图片

经过和单机上运行任务的业务方确认,这台机器上运行的Job任务实例(并非长期运行的任务)会在运行的时候声明存储空间,在Job任务运行完成后释放存储空间。

排查到此,我们可确定众多的内核线程与单机频繁的云盘挂载和释放有关。以jbd2-ckpt/vdfiw为例,vdfiw为本地挂载的磁盘的编号,设备挂载在路径/dev/vdfiw中,在K8s系中使用,会将设备目录挂载到:

/var/lib/kubelet/plugins/kubernetes.io/csi/pv/d-bp1iau7367wkpf6xqdpv/globalmount,

但同时,K8s中挂载的文件也被该挂载到某个容器的根目录:

/var/lib/container/docker/overlay2/9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be/merged/var/lib/container/kubelet/plugins/kubernetes.io/csi/pv/d-bp1iau7367wkpf6xqdpv/globalmount。

请记住这个特殊目录,后续我们的突破口也将在这里。

单机中/var/lib/container/docker通过挂载bind的方式到/var/lib/docker中,两者可以认为是同一个目录,/var/lib/kubelt类型。

挂载关系如下图所示:

图片

命令行详情: 

$mount|grep vdfiw
/dev/vdfiw on /var/lib/kubelet/plugins/kubernetes.io/csi/pv/d-bp1iau7367wkpf6xqdpv/globalmount type ext4 (ro,relatime)/dev/vdfiw on /var/lib/container/docker/overlay2/9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be/merged/logxxx_host/var/lib/container/kubelet/plugins/kubernetes.io/csi/pv/d-bp1iau7367wkpf6xqdpv/globalmount type ext4 (ro,relatime)

在确定了磁盘/dev/vdfiw挂载情况后,经过排查发现在系统存在6385个类似于/dev/vdfiw场景的磁盘设备,也就是意味着本地挂载的远程磁盘数量有6385 个。而本地真正挂载的磁盘却非常少,这是属于磁盘挂载异常导致。


$lsblk -f
NAME   FSTYPE LABEL UUID                                 MOUNTPOINT
vdiko  ext4         0442c714-4a4d-4d2b-8771-038edaefcf3f /var/lib/container/docker/overlay2/9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be/merged/logxxx_host/var/lib/kubelet/pods/e2c23872-1f
vdb    ext4         ef9f6dfa-d518-44f9-914f-b141ff423191 /var/lib/container/docker/overlay2/9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be/merged/logxxx_host/opt/hybrid-data
vdiau  ext4         e403a2ef-2e1d-4cb7-9382-8ca33637c381 /var/lib/container/docker/overlay2/9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be/merged/logxxx_host/var/lib/kubelet/pods/da088c11-29
vdc    ext4         34c4dbcf-d514-4948-94fe-81ccf6ae5c90 /var/lib/container/docker/overlay2/9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be/merged/logxxx_host/var/lib/container
vda
└─vda1 ext4         1612a49b-a79d-4e87-819a-a5bad80fe2a9 /var/lib/container/docker/overl

远端磁盘要在K8s和容器中使用必须需要针对设备进行挂载操作,通过排查挂载信息,可以看到有26503条单机磁盘类挂载为Ext4的记录,其中12777条mount记录都齐刷刷挂载到某个特殊目录,/var/lib/container/docker/overlay2/9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be/merged/logxxx_host/目录中。

图片


$ mount |grep '/dev/vd' |awk '{print $1}'|sort|uniq|more
/dev/vda1
/dev/vdaa
/dev/vdaaa
....$mount |grep '/dev/vd' |awk '{print $1}'|sort|uniq|wc -l
6385$ mount |grep "/dev/vd"| wc -l
26503$ mount |grep '/dev/vd' |grep -v 9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be|wc -l
12777

既然所有的本地磁盘都挂载到了这个特殊的容器目录,那么我们就需要看看这个容器目录到底归属于何方神圣?通过检查本地所有容器的挂载目录,我们将线索定位到了 logxxx-ds-hsbv9容器。​​​​​​​

$ docker inspect `docker ps -a | awk '{ print $1}'|grep -v CONTAINER` > /tmp/docker_inspect.log$ grep 9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be /tmp/docker_inspect.log  定位到容器 ID e4261544f8eb
nspect.log  定位到容器 ID e4261544f8eb

通过docker ps -a基于容器ID过滤,可发现这个特殊的容器为k8s_logxxx_logxxx-ds,为云厂商日志采集的单机容器实例logxxx-ds-hsbv9,而该容器实例卡在了一个称之为Removal In Progress的状态。​​​​​​​

$ docker ps -a|grep e4261544f8ebe4261544f8eb        889ceee008bf                                                                 "/usr/local/ilogxxx…"    8 months ago        Removal In Progress                              k8s_logxxx_logxxx-ds-hsbv9_kube-system_93e182b4-ed88-4344-8c8d-e22af0407be8_0

进一步通过docker inspect检查该容器删除的状态信息,可以看到该容器由于自己的根目录清理出错一直卡在被删除阶段,从而导致旧的容器实例异常。​​​​​​​


$ docker inspect e4261544f8e
[{"Id": "e4261544f8eb355ee438c61a5c121217d54b54244d2957e495aa234f77444288","Created": "2023-07-25T07:23:28.927382459Z","Path": "/usr/local/ilogxxx/run_logxxx.sh","Args": [],"State": {"Status": "dead","Running": false,"Paused": false,"Restarting": false,"OOMKilled": false,"Dead": true,"Pid": 0,"ExitCode": 137,"Error": "container e4261544f8eb355ee438c61a5c121217d54b54244d2957e495aa234f77444288: driver \"overlay2\" failed to remove root filesystem: unlinkat /var/lib/docker/overlay2/9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be/merged: device or resource busy","StartedAt": "2023-07-25T07:23:29.135183205Z","FinishedAt": "2023-08-15T06:18:44.69693858Z"},

而上述出错的文件目录我们进行查看并没有任何文件:

图片

简单来说就是这个文件目录已经被清空,但是还在被其他地方引用。

看到这里你一定会比较好奇,为什么所有的磁盘记录有会挂载到容器logxxx-ds-hsbv9中?

图片

我们可以通过检查logxxx-ds的YAML文件可以看到端倪:


kubectl get ds  logxxx-ds -o yaml -n kube-system
apiVersion: apps/v1
kind: DaemonSet
spec:spec:containers:...volumeMounts:- mountPath: /var/runname: run- mountPath: /logxxx_hostmountPropagation: HostToContainername: rootreadOnly: truevolumes:- hostPath:path: /var/runtype: Directoryname: run- hostPath:path: /type: Directoryname: root

可以看到logxxx-ds-hsbv9实例会将宿主机的根目录挂载到容器根目录下的 /logxxx_host目录下。

这里会涉及到一些容器文件与宿主机目录文件共享的机制,这里简单基于当前挂载进行介绍。这里的场景是logxxx-ds-hsbv9实例要搜集单机上的日志目录,所以它需要能够在容器里面访问主机上所有主机文件且感知宿主机上的文件的变化能力,但是主机上并需要感知logxxx-ds-hsbv9在该目录下的操作变化,因此这是一个单向的传播关系。

这里的挂载选项mountPropagation: HostToContainer就是实现了个效果:

  • HostToContainer:宿主机上挂载到容器中的目录,宿主机目录中的变化,容器中单向可见。反之,容器中目录的变化对宿主机中的目录不可见。

图片

  • Bidirectional:宿主机上挂载到容器中的目录,无论是在宿主机还是在容器中的变化,宿主机和容器中都可见。

图片

基于上述的整体挂载关系,单个磁盘设备挂载的整体关系可在下图中得到展示:

图片

    
2. 单机分析初步结论

到此,针对单机的分析我们大概有个初步结论:系统中出现了6385个挂载的设备,这些设备在内核中每个启动了3个对应的内核线程,导致整个系统出现了20000多个内核线程,这些出现异常的设备基本都是容器单机通过K8s持久卷的挂载机制挂载到K8s目录,同时由于logxxx-ds-hsbv9容器挂载了整个根目录,所以导致磁盘挂载到 k8s的目录也挂载到了 logxxx的logxxx_host路径下。系统中有将近6385个设备都遵循了这个上述图中的挂载机制,所以导致logxxx-ds-hsbv9的挂载记录众多。容器logxxx-ds-hsbv9实例则在删除merged子设备的时候报错“device or resource busy”卡主了。问题分析到这里单机侧有了一个初步方向,我们将方向再转向CPU和内存都占用异常的Kubelet进程。

 3. Kubelet进程资源占用分析

首先,查看Kubelet日志,通过最近几分钟的日志分析发现了大量的相似报错,短短几分钟内的日志报错就多达4000条Operation for "{volumeName:kubernetes.io/csi/diskplugin.csi.xxx.com^d-bp1dtkaipms3op820vnb podName: nodeName:}" failed。


$ journalctl -u kubelet --no-pager  --since="2024-04-12 15:25"
Apr 12 15:28:39 k8s-prd-standard-43.113 kubelet[3237254]: E0412 15:28:39.437193 3237254 nestedpendingoperations.go:301] Operation for "{volumeName:kubernetes.io/csi/diskplugin.csi.xxx.com^d-bp1dtkaipms3op820vnb podName: nodeName:}" failed. No retries permitted until 2024-04-12 15:30:41.437168443 +0800 CST m=+21254165.582404754 (durationBeforeRetry 2m2s). Error: "GetDeviceMountRefs check failed for volume \"d-bp1dtkaipms3op820vnb\" (UniqueName: \"kubernetes.io/csi/diskplugin.csi.xxx.com^d-bp1dtkaipms3op820vnb\") on node \"k8s-prd-standard-43.113\" : the device mount path \"/var/lib/kubelet/plugins/kubernetes.io/csi/pv/d-bp1dtkaipms3op820vnb/globalmount\" is still mounted by other references [/var/lib/container/docker/overlay2/9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be/merged/logxxx_host/var/lib/kubelet/plugins/kubernetes.io/csi/pv/d-bp1dtkaipms3op820vnb/globalmount /var/lib/container/docker/overlay2/9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be/merged/logxxx_host/var/lib/container/kubelet/plugins/kubernetes.io/csi/pv/d-bp1dtkaipms3op820vnb/globalmount /var/lib/container/kubelet/plugins/kubernetes.io/csi/pv/d-bp1dtkaipms3op820vnb/globalmount]"
...

看日志描述会略微费劲,简单总结一下就是:

“我打算移除这个设备d-bp1dtkaipms3op820vnb,但重试过程中遇到了这个设备仍然被/var/lib/container/docker/overlay2/9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be/merged/logxxx_host/var/lib/kubelet/plugins/kubernetes.io/csi/pv/d-bp1dtkaipms3op820vnb/globalmount这个目录挂载,删除失败,但是我仍然会持续重试”。

我们从K8s的磁盘挂载文件PV中去查询d-bp1dtkaipms3op820vnb这个设备,发现该PV已经被移除,同时通过云厂商产品控制台以该ID查询也发现磁盘已经被释放了。

ID为d-bp1dtkaipms3op820vnb磁盘在2023-08-21号已经被释放。

到这里简单总结异常的整体的关系流程图如下所示:

图片

没有例外,我们前面分析的样例/dev/vdfiw on /var/lib/kubelet/plugins/kubernetes.io/csi/pv/d-bp1iau7367wkpf6xqdpv/globalmount,也在这个错误的日志中。

图片

通过Kubelet的日志报错分析,发现在删除PV挂载的远端云磁盘时,发现磁盘的挂载路径仍然被logxxx-ds-hsbv9的路径挂载,因此删除出错,由于系统长时间运行异常积累了6000多个磁盘设备,因此每个轮训周期中都要进行大量设备的删除重试,而且这个重试是持续进行中。Kubelet的报错日志与我们分析单机挂载设备能够完全匹配。

为了验证Kubelet CPU占用的高的确是由于大量设备卸载报错导致,这里针对Kubelet进行了一次性能数据分析。我们从单机的Kubelet采集了CPU的pprof文件进行分析,结果与预期一致,的确是由于数量众多的删除失败和重试导致了Kubelet CPU使用率异常,80.88%的CPU都在进行挂载点删除的操作(与Kubelet日志报错完全吻合: kubelet[3237254]: E0412 15:36:39.827608 3237254 nestedpendingoperations.go:301] Operation for)。

图片

4. Kubelet分析初步结论

至此,我们完成了Kubelet单机CPU异常的分析:

  • Kubelet删除挂载设备失败,失败原因是设备目录被logxxx容器占用,锲而不舍的持续删除,接近81%的CPU使用率消耗在了卸载本地大量挂载的云盘记录上;

  • 而删除异常的磁盘设备被云厂商日志产品单机实例logxxx-ds-hsbv9挂载占用,持续重复卸载失败。

  • 挂载设备目录的的logxxx-ds-hsbv9容器,删除过程中卡在了容器目录的删除上。

那么是否解决了logxxx-ds-hsbv9本地容器删除失败的情况,所有非法被占用的设备挂载就可以释放,让Kubelet恢复正常呢?带着这个问题,我们持续往下跟踪分析。

四、根因确定

既然所有的问题都指向了这个卡在“Removal In Progress”状态logxxx-ds-hsbv9容器,相信它就是打开单机异常的钥匙🔑。

该容器卡在删除失败的问题是,删除自己的时候自己的容器挂载根目录“device or resource busy” 。

"Error": "container e4261544f8eb355ee438c61a5c121217d54b54244d2957e495aa234f77444288: driver \"overlay2\" failed to remove root filesystem: unlinkat /var/lib/docker/overlay2/9caa9580e946898718f97e9d205d0ac34048d5242ea30c0bc859627483b664be/merged: device or resource busy",

前面我们提到过,手工查看logxxx-ds-hsbv9容器的merged下面为空,通过查看docker源码发现unlinkat针对目录的操作底层与rmdir删除一致,因此我们可以简单通过rmdir删除目录进行重现分析(unlinkat会尝试以文件删除,如果删除发现是目录则设置函数flag以目录方式递归删除)。

不出意外,使用rmdir删除也是同样报错:

$ rmdir /var/lib/container/docker/overlay2/9caa..64be/merged
rmdir: failed to remove ‘/var/lib/container/docker/overlay2/9caa..64be/merged’: Device or resource busy

通过分析rmdir的内核代码实现,最终定位到删除失败的函数范围是在目录挂载点的函数判断上(具体分析方式可参见no space left问题定位过程(https://www.ebpf.top/post/no_space_left_on_devices/):


bool __is_local_mountpoint(struct dentry *dentry)
{struct mnt_namespace *ns = current->nsproxy->mnt_ns;struct mount *mnt;bool is_covered = false;if (!d_mountpoint(dentry))goto out;down_read(&namespace_sem);list_for_each_entry(mnt, &ns->list, mnt_list) {is_covered = (mnt->mnt_mountpoint == dentry);if (is_covered)break;}up_read(&namespace_sem);
out:return is_covered;
}

 

简单总结就是尝试删除merged目录时候,这个目录还在系统中存在挂载关系。尝试通过挂载在merged目录下的logxxx_host文件访问,我们发现仍然能够访问,说明尽管merged目录下的内容虽然表面看被删除了,但是其目录下的挂载点仍然存在,导致merged目录不能够被正常删除。

图片

当尝试访问云盘挂载的根目录会出现Input/output error的错误,这是因为K8s中的存储插件已经将该目录对应的  /dev/vdfiw 设备在远端删除所导致。


$ ls -hl /var/lib/container/docker/overlay2/9caa...64be/merged/logxxx_host/var/lib/kubelet/plugins/kubernetes.io/csi/pv/d-bp1iau7367wkpf6xqdpv/globalmount/ls: reading directory /var/lib/container/docker/overlay2/9caa...64be/merged/logxxx_host/var/lib/kubelet/plugins/kubernetes.io/csi/pv/d-bp1iau7367wkpf6xqdpv/globalmount/: Input/output error

继续在内核日志中查找线索(在内核日志中搜索vdfiw):


grep "vdfiw" /tmp/dmsg.log
[Mon Apr  8 10:19:15 2024] EXT4-fs warning (device vdfiw): htree_dirblock_to_tree:995: inode #2: lblock 0: comm find: error -5 reading directory block
[Mon Apr  8 10:19:15 2024] EXT4-fs error (device vdfiw): __ext4_get_inode_loc:4317: inode #2: block 1095: comm find: unable to read itable block
[Mon Apr  8 10:19:15 2024] EXT4-fs error (device vdfiw) in ext4_reserve_inode_write:5543: IO failure
[Mon Apr  8 10:19:21 2024] Aborting journal on device vdfiw-8.
[Mon Apr  8 10:19:21 2024] JBD2: Error -5 detected when updating journal superblock for vdfiw-8.
[Mon Apr  8 11:05:38 2024] EXT4-fs warning (device vdfiw): htree_dirblock_to_tree:995: inode #2: lblock 0: comm find: error -5 reading directory block
[Mon Apr  8 13:29:36 2024] EXT4-fs warning (device vdfiw): htree_dirblock_to_tree:995: inode #2: lblock 0: comm find: error -5 reading directory block
[Tue Apr  9 10:20:55 2024] EXT4-fs (vdfiw): error count since last fsck: 2
[Tue Apr  9 10:20:55 2024] EXT4-fs (vdfiw): initial error at time 1712543485: __ext4_get_inode_loc:4317
[Tue Apr  9 10:20:55 2024] EXT4-fs (vdfiw): last error at time 1712543485: ext4_reserve_inode_write:5543
[Wed Apr 10 10:48:53 2024] EXT4-fs (vdfiw): error count since last fsck: 2
[Wed Apr 10 10:48:53 2024] EXT4-fs (vdfiw): initial error at time 1712543485: __ext4_get_inode_loc:4317
[Wed Apr 10 10:48:53 2024] EXT4-fs (vdfiw): last error at time 1712543485: ext4_reserve_inode_write:5543
[Thu Apr 11 11:16:52 2024] EXT4-fs (vdfiw): error count since last fsck: 2
[Thu Apr 11 11:16:52 2024] EXT4-fs (vdfiw): initial error at time 1712543485: __ext4_get_inode_loc:4317
[Thu Apr 11 11:16:52 2024] EXT4-fs (vdfiw): last error at time 1712543485: ext4_reserve_inode_write:5543
[Fri Apr 12 09:49:08 2024] EXT4-fs warning (device vdfiw): htree_dirblock_to_tree:995: inode #2: lblock 0: comm find: error -5 reading directory block
[Fri Apr 12 09:49:08 2024] EXT4-fs error (device vdfiw): ext4_journal_check_start:61: Detected aborted journal
[Fri Apr 12 09:49:08 2024] EXT4-fs (vdfiw): Remounting filesystem read-only
[Fri Apr 12 09:49:39 2024] EXT4-fs warning (device vdfiw): htree_dirblock_to_tree:995: inode #2: lblock 0: comm find: error -5 reading directory block
[Fri Apr 12 09:56:20 2024] EXT4-fs warning (device vdfiw): htree_dirblock_to_tree:995: inode #2: lblock 0: comm find: error -5 reading directory block
[Fri Apr 12 11:44:50 2024] EXT4-fs (vdfiw): error count since last fsck: 4
[Fri Apr 12 11:44:50 2024] EXT4-fs (vdfiw): initial error at time 1712543485: __ext4_get_inode_loc:4317
[Fri Apr 12 11:44:50 2024] EXT4-fs (vdfiw): last error at time 1712887285: ext4_journal_check_start:61
[Fri Apr 12 14:36:00 2024] EXT4-fs warning (device vdfiw): htree_dirblock_to_tree:995: inode #2: lblock 0: comm ls: error -5 reading directory block
[Fri Apr 12 14:36:44 2024] EXT4-fs warning (device vdfiw): htree_dirblock_to_tree:995: inode #2: lblock 0: comm ls: error -5 reading directory block

 

内核中的针对磁盘/dev/vdfiw磁盘的错误error (device vdfiw): __ext4_get_inode_loc:4317: inode #2: block 1095: comm find: unable to read itable block ,表明查询挂载磁盘失败,内核线程卡在异常场景上。本地系统中对应的/dev/vdfiw所对应的远程云盘已经被移除,而本地的磁盘/dev/vdfiw对应的内核线程jbd2/vdfiw-8和jbd2-ckpt/vdfiw等则出现了异常。经和云厂商工单处理人确认,所对应的磁盘2024-02-01已经在后台被移除。

我们初步推断是由于设备挂载的目录对应云盘提前卸载,在容器清理访问过程中出现 Input/output error异常错误,导致整个清理过程不能够在容器侧通过unlikat操作正常进行。

五、修复验证测试

既然所有的症结是云盘非预期挂载在logxxx-ds-hsbv9容器实例的merged目录下,那么我们只需要手工减掉这个依赖,那么理论上Kubelet删除挂载的PV就会成功,挂载云盘所对应的内核线程也可能会自动退出。我找了一台已经隔离的机器进行验证验证测试,在手动卸载容器实例前,先检查内核线程、磁盘、磁盘挂载记录和内核日志等进行确认。

1. 手动卸载单条记录确认

内核线程确认(这里以/dev/vdmgd为例):

$ ps aux|grep vdmgd
root     1078726  0.0  0.0      0     0 ?        S    20:11   0:00 [jbd2/vdmgd-8]
root     1078727  0.0  0.0      0     0 ?        S    20:11   0:00 [jbd2-ckpt/vdmgd]

 本地磁盘确认:

$ df |grep vdmgd 
/dev/vdmgd 

挂载记录确认:

$ mount |grep d-bp1gr027v6iq2etcfsvk/dev/vdmgd on /var/lib/kubelet/plugins/kubernetes.io/csi/pv/d-bp1gr027v6iq2etcfsvk/globalmount type ext4 (rw,relatime)/dev/vdmgd on /var/lib/container/docker/overlay2/f605aea15446c49d10108264b5f377a022e9c7c041487deb0c70189bf07a49c7/merged/logxxx_host/var/lib/container/kubelet/plugins/kubernetes.io/csi/pv/d-bp1gr027v6iq2etcfsvk/globalmount type ext4 (rw,relatime)

挂载点访问确认:

$ ls -hl /var/lib/container/docker/overlay2/f605aea15446c49d10108264b5f377a022e9c7c041487deb0c70189bf07a49c7/merged/logxxx_host/var/lib/container/kubelet/plugins/kubernetes.io/csi/pv/d-bp1gr027v6iq2etcfsvk/globalmount
ls: reading directory /var/lib/container/docker/overlay2/f605aea15446c49d10108264b5f377a022e9c7c041487deb0c70189bf07a49c7/merged/logxxx_host/var/lib/container/kubelet/plugins/kubernetes.io/csi/pv/d-bp1gr027v6iq2etcfsvk/globalmount: Input/output error

 进行到验证阶段,手动卸载这条泄露的挂载记录:

$ umount /var/lib/container/docker/overlay2/f605aea15446c49d10108264b5f377a022e9c7c041487deb0c70189bf07a49c7/merged/logxxx_host/var/lib/container/kubelet/plugins/kubernetes.io/csi/pv/d-bp1gr027v6iq2etcfsvk/globalmount

手动卸载完成后,经过确认对应的内核线程、本地磁盘、挂载记录都已经消失、挂载点访问也恢复正常

检查内核日志发现,手动释放挂载记录后,内核进程在异常报错后,没有再持续进行报错,逐步退出。

图片

 2. 全部清理确认

动清理泄露挂载记录,清理完成后,发现Kubelet恢复到正常的CPU水位线,CPU性能分析也恢复正常。

图片

图片

随着挂载记录逐步被移除,单机的磁盘挂载记录也被正常卸载。

图片

同时内核线程也开始正常消失,整个机器负载基本恢复正常。

图片

至此整个流程得到了验证,内核进程(任务)数量和kubelet进程已经恢复正常。

六、总结

至此这个问题根因总算水落石出,验证方式也得到了确认,问题的触发会有几个条件同时作用:

  • 日志采集单机容器实例挂载了Linux系统根目录,主机挂载记录全部传递到日志采集单机的容器实例中;

  • 运行的服务使用K8s持久存储挂载远程云盘,挂载到本地的磁盘开启了日志功能;

  • 单机运行的服务频繁申请远程云盘,云厂商提供的存储插件提前卸载远程云盘,使得磁盘挂载记录持续泄露;

  • 设备文件系统日志功能的内核线程,在远端云盘被删除后的异常场景,并不会异常终止,而是持续重试;

上述的这些条件作用在一起,可能导致容器侧在挂载点清理过程异常,导致挂载记录无法清除和对应内核线程无法终止,最终导致大量内核线程遗留和单机Kubelet CPU 使用非预期过高。整个过程的排查和解决需要涉及到云厂商日志采集、存储插件和内核等多个产品在异常场景下的协同流程。

后续我们会加强单机设备挂载和单机残留容器指标的监控,能够在问题早期就能够发现和处理;同时我们也将这个情况反馈到了云厂商侧,希望能够从日志采集产品、存储插件和内核侧进行容错规避。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/22724.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【学习笔记】Windows GDI绘图(十)Graphics详解(中)

文章目录 Graphics的方法AddMetafileComment添加注释BeginContainer和EndContainer新建、还原图形容器不指定指定源与目标矩形指定源与目标矩形 Clear清空并填充指定颜色CopyFromScreen截图CopyPixelOperation DrawImage绘制图像DrawImage的GraphicsDrawImageAbort回调ExcludeC…

初识 peerDependencies

目录 初步认识 peerDependencies semver 介绍 # 摘要 # 简介 # 语义化版本控制规范&#xff08;SemVer&#xff09; # 合法语义化版本的巴科斯范式语法 # 为什么要使用语义化的版本控制&#xff1f; # FAQ 示例讲解&#xff1a;vue-router 插件 # 说明 声明 验证 初…

在Windows11系统上搭建SFTP服务器

利用OpenSSH搭建SFTP服务器 下载安装部署OpenSSH创建一个测试账户测试链接为SFTP用户配置根目录下载安装部署OpenSSH 参考链接 部署完启动服务要使用管理员模式。 net start sshd创建一个测试账户 使用PC的微软账户是访问不了SFTP的。 需要使用被微软账户覆盖掉的系统账户和…

微信自定义小程序源码系统 众多组件随心搭 各行各业都适用的小程序 带完整的安装代码包以及搭建教程

系统概述 微信自定义小程序源码系统是一款基于微信官方开发框架进行深度定制的源码系统。该系统整合了众多优质组件&#xff0c;通过可视化的拖拽式操作&#xff0c;让开发者无需编写复杂的代码&#xff0c;即可快速搭建出符合自己需求的小程序。同时&#xff0c;该系统支持多…

iTerm2 携手 OpenAI,带来命令行的自然语言革新

在技术不断进步的今天&#xff0c;命令行工具的智能化已成为提升效率的关键。iTerm2&#xff0c;macOS 系统上广受欢迎的开源终端工具&#xff0c;通过最新版本 v3.5 的发布&#xff0c;实现了与 OpenAI 的集成&#xff0c;引领了这一变革。 iTerm2 简介 iTerm2 是一款功能强…

qcom 平台系统签名流程

security boot 平台的东东&#xff0c;oem 可定制的功能有限&#xff0c;只能参考平台文档&#xff0c;可以在高通的网站上搜索&#xff1a;Secure Boot Enablement&#xff0c;然后找对应平台的文档xxx-Secure Boot Enablement User Guide, step by step 操作即可 开机校验流…

CodeBlocks官方主题颜色更换及方法

文章目录 一、前言二 、用工具导入配置文件2.1 运行 cb_share_config.exe文件2.2 替换文件2.3 设置主题 三、配置主题3.1 步骤13.2 步骤23.3 步骤3 四、设置光标4.1 配置字体4.2 展示 行号 五、设置左边行号区域部分六、设置完后的效果七、下载地址 一、前言 Codeblocks 默认的…

【Python系列】Python装饰器

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【数据结构】图论中求最短路径——迪杰斯特拉算法(Dijkstra)、弗洛伊德算法(Floyd)

目录 最短路径 (*)迪杰斯特拉算法&#xff08;Dijkstra&#xff09;迪杰斯特拉算法&#xff08;Dijkstra&#xff09;的算法原理&#xff1a; 弗洛伊德算法&#xff08;Floyd&#xff09;弗洛伊德算法&#xff08;Floyd&#xff09;的算法原理&#xff1a;弗洛伊德算法的&#…

哪种价格行为指标对投资者有用?AnzoCapital昂首资本总结6个特征

各位投资者都知道价格行为指标对于交易极具助益&#xff0c;无论是初学者还是专业交易员都能运用。构建外汇交易系统时&#xff0c;这类指标堪称核心且必不可少的工具。 但不是所有的价格行为指标都对投资者有用的&#xff0c;哪种价格行为指标才是对投资者有用的&#xff0c;都…

CogVLM2多模态开源大模型部署与使用

CogVLM2多模态开源大模型部署与使用 项目简介 CogVLM2 是由清华大学团队发布的新一代开源模型系列。2024年5月24日&#xff0c;发布了Int4版本模型&#xff0c;只需16GB显存即可进行推理。2024年5月20日&#xff0c;发布了基于llama3-8b的CogVLM2&#xff0c;性能与GPT-4V相当…

论文AI率过高?掌握这四种技巧轻松降重

随着人工智能技术的突飞猛进&#xff0c;AI生成内容&#xff08;AIGC&#xff09;已被广泛用于学术论文撰写中&#xff0c;提高效率同时也带来了原创性的挑战。面对日益严格的学术审查&#xff0c;一个突出的问题是&#xff1a;使用AI代写的论文能否通过内容检测&#xff1f;因…

Linux 搭建 ZeroTier 的 Moon 服务器

系统&#xff1a;centos 7.6 轻量云服务器&#xff1a;腾讯云 Moon是什么&#xff0c;为什么需要Moon&#xff1f; ZeroTier通过自己的多个根服务器帮助我们建立虚拟的局域网&#xff0c;让虚拟局域网内的各台设备可以打洞直连。这些根服务器的功能有些类似于通过域名查询找到…

SpringCloud Hystrix服务熔断实例总结

SpringCloud Hystrix断路器-服务熔断与降级和HystrixDashboard SpringCloud Hystrix服务降级实例总结 【1】服务熔断 熔断机制概述 熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时&#xff0c;会进行服务的降级&…

WWDC 2024前瞻:苹果如何用AI技术重塑iOS 18和Siri

苹果下周的全球开发者大会有望成为这家 iPhone 制造商历史上的关键时刻。在 WWDC 上&#xff0c;这家库比蒂诺科技巨头将展示如何选择将人工智能技术集成到其设备和软件中&#xff0c;包括通过与 OpenAI 的历史性合作伙伴关系。随着重大事件的临近&#xff0c;有关 iOS 18 及其…

AI大模型时代必须关注的数据库 DuckDB1.0 正式发布

开源数据库DuckDB1.0 经过内部6年的打磨&#xff0c;积累了30万行代码&#xff0c;1.8万star&#xff0c;2024.06.03号正式发布了1.0版本&#xff08;代号 Snow Duck&#xff09;。 我们新一代程序员&#xff0c;没能见证MySQL 1.0、PostgreSQL 1.0、Windows 1.0、Linux 1.0、…

flinksql 回撤流中主键发生变更的影响(group by中的值发生改变)

flinksql 回撤流中,主键发生变更的影响 1 什么是回撤流2 主键变更场景2.2 实践发生3 实践中发现的比较好的的实时数仓架构1 什么是回撤流 这篇文章主要谈论一个场景,简单来说: 首先我们来简单的说一下什么是回撤流,以及回撤流的底层原理,举个例子: 这个说的不是很清晰…

【吊打面试官系列】MySQL 中有哪几种锁?

大家好&#xff0c;我是锋哥。今天分享关于 【MySQL 中有哪几种锁&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; MySQL 中有哪几种锁&#xff1f; 1、表级锁&#xff1a;开销小&#xff0c;加锁快&#xff1b;不会出现死锁&#xff1b;锁定粒度大&#xff0c;…

TypeScript学习(一):开发环境搭建

官方文档搭建参考 https://learn.microsoft.com/zh-cn/training/modules/typescript-get-started/ 1.下载node.js https://nodejs.org/en/download 2.下载vscode https://code.visualstudio.com/ 3.在线ts的测试工具 https://www.typescriptlang.org/play/ 4.下载typescr…

H5即时通讯群聊源码无限建群创群/H5聊天系统聊天网站源码/H5语音聊天系统

源码介绍 支持自助建群 管理群 修改群资料支持自动登录 登陆成功可自助修改资料后台可查看群组聊天消息记录支持表情 动态表情 图片发布支持消息语音提醒