解决自研CSI启动后无法使用且CSINode无驱动信息的问题

环境信息

此处对一些信息做了模糊处理,不想因此导致一些信息泄露。

A环境:跑在kata容器中的 OS;

B环境:跑在虚拟机中的Ubuntu系统;

X CSI:开发中的 CSI,目标是跑在 A 环境的 Kubernetes 中。

问题描述

当 X CSI 的服务在 A 环境中启动后,在宿主机的 /var/lib/kubelet/plugins和 /var/lib/kubelet/plugins_registry目录中,生成对应的 sock 文件后,CSINode 中 driver 栏没有刚启动的 X CSI。结果如下:

image-20230227111029825

问题影响

无法使用 X CSI 来挂载 PV

WorkAround

  1. kill kubelet 进程
1
kill `ps -ef | grep -v grep | grep "/usr/bin/kubelet" | awk '{print $2}'`
  1. kubelet 重启后,会填充 CSINode 信息,如下

image-20230227111318080

可能的原因

  1. kubelet 命令是否存在对应的配置参数,来对控制扫描 /var/lib/kubelet/plugins_registry目录?

  2. 是否由于文件系统的原因导致?

排查过程

排查 X CSI 的配置问题

找了这张图来看 /var/lib/kubelet/plugins_registry/var/lib/kubelet/csi-plugins/xxx.sock 目录有啥命名规范,会不会是命名不规范,导致 PluginWwatcher watch 不到对应的 sock 文件,从而引起 X CSI 无法顺利注册。

修改成上图中的规范之后,问题依然存在。

对比 B 环境中kubelet参数

A 环境中

kubelet 启动参数为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/usr/bin/kubelet 
--hostname-override=<hostname>
--bootstrap-kubeconfig=/etc/k8s/cfg/kubelet-bootstrap.kubeconfig
--kubeconfig=/etc/k8s/cfg/kubelet.kubeconfig
--cert-dir=/etc/k8s/kubelet
--config=/etc/k8s/cfg/kubelet.config
--container-runtime=remote
--runtime-request-timeout=15m
--container-runtime-endpoint=unix:///run/containerd/containerd.sock
--pod-infra-container-image=k8s.gcr.io/pause:3.2
--feature-gates=RotateKubeletServerCertificate=true
--feature-gates=RotateKubeletClientCertificate=true
--rotate-certificates=false
--v=6

其中 kubelet.config 中的配置信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
port: 10250
readOnlyPort: 10255
cgroupDriver: cgroupfs
clusterDNS: [x.x.x.x]
clusterDomain: cluster.local
failSwapOn: false
serverTLSBootstrap: true
authentication:
anonymous:
enabled: true
webhook:
cacheTTL: 2m0s
enabled: true
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 5m0s
cacheUnauthorizedTTL: 30s
evictionHard:
memory.available: "10%"

在 B 环境中用 kubeadm 自建 Kubernetes 集群

kubelet 启动参数:

1
2
3
4
5
6
7
/usr/bin/kubelet 
--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf
--kubeconfig=/etc/kubernetes/kubelet.conf
--config=/var/lib/kubelet/config.yaml
--container-runtime=remote
--container-runtime-endpoint=unix:///run/containerd/containerd.sock
--pod-infra-container-image=registry.k8s.io/pause:3.8

其中 kubelet.config 配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 0s
cacheUnauthorizedTTL: 0s
cgroupDriver: systemd
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMinimumGCAge: 0s
kind: KubeletConfiguration
logging:
flushFrequency: 0
options:
json:
infoBufferSize: "0"
verbosity: 0
memorySwap: {}
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
resolvConf: /run/systemd/resolve/resolv.conf
rotateCertificates: true
runtimeRequestTimeout: 0s
shutdownGracePeriod: 0s
shutdownGracePeriodCriticalPods: 0s
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s

没有明显的配置差异,跳过对这方面的怀疑。

在 A 环境中部署其他CSI

将官方的 nfs-csi 部署 A 环境的 K8s 中,发现在部署完成后,无法立即使用;

极大可能是 A 的环境问题

将 X CSI 部署到 B 环境的 K8s 中

发现部署完成后,可立即使用(CSIDriver 显示正常,说明被 kubelet 正确加载了);

排除 X CSI 配置问题

阅读 kubelet 加载 CSI 定义的代码

经过前面的尝试与分析,初步确定是 kubelet 加载 CSI 时,出现了问题,但具体是哪里的问题,需要先了解 kubelet 是如何加载 CSI 的,从其中寻找答案。

  1. 初步了解 CSI Driver 注册流程,在关键点添加日志、修改 kubelet 的日志级别,看日志,未发现文件监听相关的日志;

  2. 修改 kubelet 源码(添加 & 修改 kubelet 中相关的日志级别)后,发现当 /var/lib/kubelet/plugins_registry目录下新增 sock 文件、删除 sock 文件后,没有相应日志打印,即监听文件系统的事件出现异常。

定位到问题为 kubelet 监听本地文件变更存在问题后,单独将 kubelet 使用的相关库提出,并单独验证。

  1. 将 kubelet 中用于监听文件变更的库单拎出来,写一个监听某文件夹下文件变更的二进制
  2. 经过测试发现,在 A 环境的 /var/lib/kubelet/plugins_registry 目录下,就是极大概率无法监听到文件变更;更换目录,一些已存在的目录可以、一些新增的目录不行,讲道理,这不是一个正常的表现。
  3. 将二进制移到 B 环境中,监听相同目录,表现正常,进一步判定为 A 环境问题。

查看挂载信息

1
2
3
4
root@<hostname>:/# df -h | grep -i katashared
kataShared 392G 314G 78G 81% /
Filesystem 1K-blocks Used Available Use% Mounted on
kataShared 410239272 329066648 81172624 81% /

所以问题是否会跟这个 kataSahred 文件系统有关?

问题的原因

kata 容器中默认的文件系统为 kataShare,在这种文件系统下,监听某个目录下的文件变更时,会有一定的概率收不到 CREATEDELETEUPDATE 事件。因为收不到变更事件,从而无法触发 kubelet 注册 CSI Driver 的后续流程,导致部署完 CSI 后,不能立即使用。

解决方案

将 /var/lib/kubelet 目录挂载成其他文件系统后,安装 CSI 后,可立即使用,即可纵享丝滑。

1
2
root@<hostname>:/# df -h | grep -i /var/lib/kubelet
/dev/loop1 2.0G 6.5M 1.8G 1% /var/lib/kubelet

One More Question

  • 为什么重启 kubelet 能 workaround?

kubelet 启动时,会主动扫描 plugins_registry 目录下所有的文件,当扫描到文件后,会立即手动触发 CREATE 事件,从而完成 CSI Driver 的注册,达到 CSI 可用的目的。

Reference

解决自研CSI启动后无法使用且CSINode无驱动信息的问题

https://eucham.me/2023/02/27/acd4740af8a6.html

作者

遇寻

发布于

2023-02-27

更新于

2023-02-27

许可协议

评论