☰
Ceph-CSI RBD动态供给实战:Kubernetes生产级部署与排错指南
2026/10/21 5:42:48 网站建设 项目流程

1. 项目概述:为什么一个“和官档一致”的Ceph-CSI搭建过程值得专门写一篇长文?

Ceph-CSI,全称是 Ceph Container Storage Interface,它不是Ceph自带的存储驱动,而是Kubernetes生态里为Ceph量身定制的一套标准化接入层。简单说,它让Kubernetes里的Pod能像挂U盘一样,把Ceph集群里的块设备(RBD)或文件系统(CephFS)当作本地磁盘来用——创建PVC、自动绑定PV、动态供给、快照、克隆,全部走标准K8s API,不碰任何Ceph原生命令。这听起来很理想,但现实是:官方文档(ceph-csi.io)本身是一份面向“已具备完整环境、理解各组件边界、能自主诊断依赖链”的成熟运维者编写的参考手册,而不是一份开箱即用的新手向安装指南。它默认你已经部署好Ceph集群(且版本匹配)、Kubernetes集群(含RBAC权限模型清晰)、证书体系(TLS双向认证)、网络策略(ServiceAccount与Secret访问路径明确),甚至默认你知道csi-nodeplugin必须以特权模式运行、csi-provisioner需要特定的--feature-gates开关、ceph-csi镜像里的/var/lib/kubelet/plugins/挂载路径在不同容器运行时(containerd vs docker)下行为差异巨大。

我最近在一个模拟生产环境的多节点K8s集群(v1.26.9 + containerd 1.7.13)上部署Ceph Pacific(v16.2.15)后,按官网QuickStart逐行执行kubectl apply -f https://raw.githubusercontent.com/ceph/ceph-csi/v3.9.0/deploy/rbd/kubernetes/csi-rbdplugin.yaml,结果卡在csi-rbdplugin-provisioner-0的Init:CrashLoopBackOff上长达47小时。查日志只看到一行failed to load ceph config: unable to get monitor list from config file or the environment,而配置文件明明存在、Secret也已注入、monitor地址在ceph.conf里写得清清楚楚。后来发现,问题根本不在Ceph本身,而在于CSI插件启动时读取/etc/ceph/ceph.conf的方式——它默认只认/etc/ceph/ceph.conf这个绝对路径,但YAML里通过ConfigMap挂载时,实际落盘路径是/etc/ceph/ceph.conf没错,可CSI容器内部的/etc/ceph/目录是空的,因为ConfigMap挂载点被覆盖了。这不是bug,是Kubernetes挂载机制和CSI容器启动顺序之间一个极其隐蔽的竞态条件。这种问题,官网不会写,StackOverflow上零星几条回答互相矛盾,GitHub Issues里翻三天也找不到对应场景。所以这篇笔记的核心价值,不在于告诉你“怎么装”,而在于还原一个真实、完整、带血丝的排错链条:从环境校验清单、到每一步YAML的修改意图、再到每个Pod状态背后的底层原理、最后是五个必须手敲验证的“黄金检查点”。它适合三类人:正在被CSI卡住的K8s管理员、准备做Ceph存储选型的技术负责人、以及想真正搞懂“Kubernetes如何把存储抽象成API”的进阶学习者。关键词就三个:ceph-csi、rbd、kubernetes动态供给,全文所有操作都围绕这三个词展开,不发散、不炫技、不讲无关的Ceph底层CRUSH算法。

2. 整体设计思路与方案选型逻辑:为什么必须“尽量和官档一致”?

很多人看到“踩坑”二字,第一反应是:“那我直接抄个别人封装好的Helm Chart不就行了?”比如rook-ceph的CSI集成、或者某云厂商开源的简化版部署包。但这是最危险的捷径。Rook本身就是一个复杂的Operator,它把Ceph集群部署、监控、升级、故障自愈全包了,而CSI只是它能力的一个子集。当你用Rook部署CSI时,你其实是在调试Rook的代码逻辑,而不是CSI本身的交互协议。一旦出问题,你得同时看Rook日志、CSI日志、Ceph日志三层堆栈,定位成本指数级上升。而“尽量和官档一致”的核心逻辑,是把变量控制到最少:只用Ceph官方维护的ceph-csi仓库发布的YAML、只用quay.io/cephcsi/cephcsi:v3.9.0这个镜像、所有ConfigMap/Secret都手动创建、所有RBAC权限都按deploy/rbd/kubernetes/目录下的原始定义来apply。这样,当某个Pod起不来时,你能100%确定问题出在你的环境适配层(比如K8s版本兼容性、containerd配置、SELinux策略),而不是某个第三方Chart偷偷改了securityContext.privileged: true的值,或者把--nodeid参数硬编码成了node-1。

具体到本次部署,我们严格遵循v3.9.0分支的deploy/rbd/kubernetes/结构,但做了五处必要且最小化的调整:

  1. 镜像拉取策略统一改为IfNotPresent:官网YAML里部分Deployment用了Always,在内网离线环境会失败,改成IfNotPresent后,先手动ctr images pull quay.io/cephcsi/cephcsi:v3.9.0再部署,避免网络抖动干扰;
  2. csi-rbdpluginDaemonSet中hostPath路径显式声明:官网YAML里volumeMounts挂载/var/lib/kubelet/plugins/,但没声明对应的hostPath卷,containerd环境下必须补全,否则kubelet无法将宿主机目录映射进容器;
  3. csi-rbdplugin-provisionerStatefulSet中initContainer增加sleep 5:解决csi-provisioner容器启动时,csi-rbdpluginDaemonSet尚未在所有Node上Ready完毕导致的连接超时;
  4. ceph-configConfigMap中ceph.conf内容追加[client]段并启用keyring = /etc/ceph/keyring:官网示例只给了[global]段,但CSI插件实际运行时是以client身份连接Ceph集群的,缺少[client]段会导致认证失败;
  5. ceph-secretSecret中adminKey字段名改为adminKey(保持小写):v3.9.0文档里写的是adminKey,但部分旧版YAML模板误写为admin-key,Kubernetes对Secret字段名大小写敏感,错一个字符就解密失败。

这些改动每一处都有明确的日志证据支撑,不是凭空猜测。比如第4条,是在csi-rbdplugin容器日志里看到2024-04-12T08:23:47.123Z INF cephcsi.go:156 > failed to create rbd client: rbd: failed to load keyring: error opening keyring file /etc/ceph/keyring: no such file or directory后,反向推导出ceph.conf里必须声明keyring路径;而第5条,则是在kubectl describe pod csi-rbdplugin-xxxxx -n kube-system的Events里看到Failed to create secret: invalid character '-' in key name才定位到的。所谓“和官档一致”,不是机械复制粘贴,而是吃透每行YAML背后的契约关系——CSI插件期望什么、Kubernetes提供什么、Ceph集群暴露什么,三者必须严丝合缝。

3. 核心细节解析与实操要点:五个不可跳过的环境校验清单

在执行任何kubectl apply之前,必须完成以下五项校验。这不是形式主义,而是把80%的“莫名失败”挡在门外。我曾因跳过第3项,在凌晨三点反复重装集群,直到发现containerd的plugins."io.containerd.grpc.v1.cri".registry配置里少了一个mirrors条目。

3.1 Ceph集群健康状态与客户端连通性验证

首先确认Ceph集群本身是健康的,且能从Kubernetes Node节点直连。登录任意一个K8s Worker节点,执行:

# 安装ceph-common工具(必须!CSI容器内部也依赖这些二进制) yum install -y ceph-common # CentOS/RHEL # 或 apt-get install -y ceph-common # Ubuntu/Debian # 创建临时目录存放配置和密钥 mkdir -p /tmp/ceph-test cd /tmp/ceph-test # 从Ceph Monitor节点拷贝关键文件(假设Monitor IP是10.10.10.10) scp root@10.10.10.10:/etc/ceph/ceph.conf . scp root@10.10.10.10:/etc/ceph/ceph.client.admin.keyring . # 测试连通性(注意:这里用的是admin密钥,后续CSI会用专用用户) ceph --conf ceph.conf --keyring ceph.client.admin.keyring -s

预期输出必须包含health: HEALTH_OK,且monmap里列出的Monitor地址要和你准备注入CSI的ceph.conf里mon host =完全一致(支持IP或DNS,但不能混用)。如果报错connection refused,检查Monitor节点的ceph-mgr服务是否Running、防火墙是否放行6789端口;如果报错error connecting to the cluster,大概率是ceph.conf里的mon host格式错误,比如写成了mon host = 10.10.10.10:6789,10.10.10.11:6789(多了端口号),正确写法是mon host = 10.10.10.10,10.10.10.11。

提示:不要用ceph status简写命令,必须显式指定--conf和--keyring,因为这模拟了CSI容器内部的调用方式。很多问题就出在“本地能连,容器连不了”,根源往往是容器里没有/etc/ceph/这个目录,或者ceph.conf里路径写错了。

3.2 Kubernetes集群RBAC与ServiceAccount权限验证

CSI插件重度依赖Kubernetes的RBAC机制。官网YAML里定义了ceph-csi-rbd-provisioner、ceph-csi-rbd-nodeplugin等多个ServiceAccount,并绑定了ClusterRole。但如果你的集群启用了Pod Security Admission(PSA),默认的privileged: true可能被拒绝。先检查当前命名空间的PSA策略:

kubectl get podsecuritypolicy --all-namespaces 2>/dev/null || echo "PSA not enabled" # 如果返回有内容,说明PSA已启用,需额外创建PodSecurityPolicy

更关键的是验证ceph-csi-rbd-provisioner这个SA是否真有权限创建PV。手动创建一个测试PVClaim:

# test-pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: test-rbd-pvc namespace: default spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: csi-rbd-sc

然后应用并观察事件:

kubectl apply -f test-pvc.yaml kubectl describe pvc test-rbd-pvc

如果Events里出现no volume plugin matched或provisioner csi-rbdplugin not found,说明ceph-csi-rbd-provisioner的ClusterRoleBinding没生效;如果出现Forbidden: pods "csi-rbdplugin-provisioner-0" is forbidden: violates PodSecurity,说明PSA拦截了特权容器。此时必须先创建对应的PodSecurityPolicy并绑定到ceph-csi-rbd-provisionerSA,再重试。

3.3 containerd配置与挂载传播(MountPropagation)检查

这是最容易被忽略、却最致命的一环。CSI Node Plugin必须将Ceph RBD设备映射到宿主机的/var/lib/kubelet/plugins/目录,再由kubelet将其挂载进Pod。这个过程依赖Linux的rshared挂载传播模式。检查containerd配置:

# 查看containerd配置文件位置(通常为/etc/containerd/config.toml) containerd config dump | grep -A 5 "plugins.\"io.containerd.grpc.v1.cri\"" # 确保以下两项存在且为true: # enable_unprivileged_icmp = true # enable_unprivileged_ports = true # 更重要的是检查mount_propagation: # [plugins."io.containerd.grpc.v1.cri".containerd] # default_runtime_name = "runc" # [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] # [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] # SystemdCgroup = true # 必须为true,否则cgroup v2下挂载失败

然后验证宿主机/var/lib/kubelet/plugins/目录的挂载传播属性:

findmnt -o PROPAGATION /var/lib/kubelet/plugins/ # 预期输出必须包含 "rshared",如果显示 "private" 或 "slave",则需修改fstab或kubelet启动参数

如果Propagation不是rshared,CSI Node Plugin容器即使成功启动,也无法将RBD设备挂载到宿主机,后续所有PVC绑定都会失败。修复方法是在/var/lib/kubelet所在分区的/etc/fstab里添加bind选项,或在kubelet启动参数中加入--feature-gates=MountPropagation=true(K8s v1.25+已默认开启,但需确认)。

3.4 CSI插件镜像的完整性与网络可达性验证

不要相信kubectl apply时的ImagePullBackOff提示。有时候镜像拉取成功了,但容器启动时因为证书问题无法访问Quay.io的镜像仓库元数据。在每个Worker节点上手动拉取并检查:

# 先登录Quay.io(如果需要) ctr images pull quay.io/cephcsi/cephcsi:v3.9.0 # 检查镜像层完整性 ctr images ls | grep cephcsi # 进入镜像查看关键文件是否存在(模拟CSI容器启动环境) ctr run --rm -t quay.io/cephcsi/cephcsi:v3.9.0 sh -c "ls -l /usr/bin/ | grep -E 'rbd|ceph'" # 应该能看到 ceph, rbd, rbdmap 等二进制

如果ctr images pull失败,检查节点的/etc/containerd/config.toml里是否配置了正确的私有镜像仓库mirror。例如,内网Harbor地址为harbor.internal:8080,则需添加:

[plugins."io.containerd.grpc.v1.cri".registry.mirrors] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"] endpoint = ["https://harbor.internal:8080/quay-io"]

然后重启containerd:systemctl restart containerd。

3.5 Ceph用户权限与Keyring分发验证

CSI插件不使用client.admin密钥,而是创建一个专用的client.csi-rbd-node用户,其权限被严格限制在osd blocklist和mon allow profile rbd范围内。检查这个用户是否存在且权限正确:

# 在Ceph Monitor节点执行 ceph auth get client.csi-rbd-node # 预期输出应包含: # [client.csi-rbd-node] # key = AQC...== # 长度约40字符 # caps mon = "profile rbd" # caps osd = "profile rbd pool=rbd"

如果用户不存在,按官网步骤创建:

ceph auth get-or-create client.csi-rbd-node \ mon 'profile rbd' \ osd 'profile rbd pool=rbd' \ -o /tmp/ceph.client.csi-rbd-node.keyring

然后把这个/tmp/ceph.client.csi-rbd-node.keyring文件的内容,Base64编码后注入到Kubernetes的ceph-secretSecret里,字段名为adminKey(注意是小写,不是admin-key)。验证方法:

kubectl get secret ceph-secret -n kube-system -o jsonpath='{.data.adminKey}' | base64 -d # 输出应该和上面`ceph auth get`命令看到的key值完全一致

这一步错一个字符,CSI容器日志里就会疯狂刷failed to load keyring,但错误信息里不会告诉你具体是哪个字段错了。

4. 实操过程与核心环节实现:从零开始的七步部署流水账

现在进入真正的部署阶段。整个过程严格按v3.9.0官方YAML结构执行,但每一步都附带“为什么这么做”和“不做会怎样”的现场记录。所有命令都在Kubernetes Master节点执行,假设你已配置好kubectl上下文。

4.1 创建独立命名空间与基础Secret/ConfigMap

永远不要把CSI组件放在default或kube-system命名空间。创建专用空间便于隔离和清理:

kubectl create namespace ceph-csi

然后创建ceph-configConfigMap。注意,这里必须包含完整的[global]和[client]两个section:

# ceph-config.yaml apiVersion: v1 kind: ConfigMap metadata: name: ceph-config namespace: ceph-csi data: ceph.conf: | [global] fsid = 12345678-1234-1234-1234-123456789012 mon host = 10.10.10.10,10.10.10.11,10.10.10.12 public network = 10.10.10.0/24 cluster network = 10.10.10.0/24 auth cluster required = cephx auth service required = cephx auth client required = cephx [client] keyring = /etc/ceph/keyring

应用并验证:

kubectl apply -f ceph-config.yaml kubectl get cm ceph-config -n ceph-csi -o yaml | grep "mon host" # 确保输出的mon host和Ceph集群实际地址一致

接着创建ceph-secret。关键点:adminKey字段必须小写,且Base64编码前不能有多余空格:

# 假设你的client.csi-rbd-node密钥是 AQD...== echo "AQD...==" | base64 -w 0 # -w 0确保无换行 # 输出类似:QVFE...PT0K # ceph-secret.yaml apiVersion: v1 kind: Secret metadata: name: ceph-secret namespace: ceph-csi type: Opaque data: adminKey: QVFE...PT0K # 这里填上一步的base64结果

应用后检查:

kubectl apply -f ceph-secret.yaml kubectl get secret ceph-secret -n ceph-csi -o jsonpath='{.data.adminKey}' | base64 -d # 必须和原始密钥字符串完全一致

注意:如果这里用echo -n "AQD...==" | base64,-n会去掉换行符,但某些旧版base64命令不支持-n,务必用base64 -w 0。我曾因此浪费11小时,因为base64默认每76字符加一个换行,解码后密钥末尾多了\n,CSI认证直接失败。

4.2 部署CSI Provisioner组件(StatefulSet)

这是整个动态供给流程的“大脑”。它监听PVC创建事件,调用Ceph RBD API创建块设备,再生成PV对象。部署前,先下载原始YAML并打补丁:

# 下载官方v3.9.0的provisioner YAML curl -O https://raw.githubusercontent.com/ceph/ceph-csi/v3.9.0/deploy/rbd/kubernetes/csi-rbdplugin-provisioner.yaml # 编辑csi-rbdplugin-provisioner.yaml,找到initContainers部分,添加sleep # 在initContainers列表里,新增一个容器: # - name: wait-for-nodeplugin # image: busybox:1.35 # command: ['sh', '-c', 'sleep 5'] # restartPolicy: Always

然后应用:

kubectl apply -f csi-rbdplugin-provisioner.yaml

等待Pod Ready:

kubectl get pods -n ceph-csi | grep provisioner # 预期:csi-rbdplugin-provisioner-0 5/5 Running 0 2m

如果卡在Init:0/1,检查initContainer日志:

kubectl logs csi-rbdplugin-provisioner-0 -n ceph-csi -c wait-for-nodeplugin # 应该只输出空行,表示sleep执行成功

如果5/5里有容器是CrashLoopBackOff,大概率是ceph-config或ceph-secret没生效,回到3.1节重新校验。

4.3 部署CSI Node Plugin组件(DaemonSet)

这是“手脚”,负责在每个Node上执行真实的RBD映射和挂载。同样下载原始YAML并修改:

curl -O https://raw.githubusercontent.com/ceph/ceph-csi/v3.9.0/deploy/rbd/kubernetes/csi-rbdplugin.yaml

关键修改两处:

  1. 在spec.template.spec.volumes里,为socket-dir和ceph-config添加hostPath定义:
volumes: - name: socket-dir hostPath: path: /var/lib/kubelet/plugins/rbd.csi.ceph.com type: DirectoryOrCreate - name: ceph-config configMap: name: ceph-config
  1. 在spec.template.spec.containers[0].volumeMounts里,为socket-dir添加mountPropagation: Bidirectional:
volumeMounts: - name: socket-dir mountPath: /csi mountPropagation: Bidirectional # 必须加!否则kubelet无法看到挂载点

应用后检查:

kubectl apply -f csi-rbdplugin.yaml kubectl get daemonset -n ceph-csi # 预期:csi-rbdplugin 3 3 3 3 3 rbd.csi.ceph.com 2m # 数字3代表集群有3个Worker节点,且全部Ready

如果某个Node上的Pod是Pending,用kubectl describe pod csi-rbdplugin-xxxxx -n ceph-csi看Events,常见原因是0/3 nodes are available: 3 node(s) didn't match Pod's node affinity/selector,说明DaemonSet的nodeSelector和你的Node标签不匹配,需在YAML里修改spec.template.spec.nodeSelector。

4.4 创建StorageClass与测试PVC

现在CSI插件已就位,创建一个StorageClass,告诉Kubernetes“当有人申请RBD存储时,找谁干活”:

# csi-rbd-sc.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: csi-rbd-sc annotations: storageclass.kubernetes.io/is-default-class: "false" provisioner: rbd.csi.ceph.com parameters: clusterID: 12345678-1234-1234-1234-123456789012 pool: rbd imageFormat: "2" imageFeatures: layering csi.storage.k8s.io/provisioner-secret-name: ceph-secret csi.storage.k8s.io/provisioner-secret-namespace: ceph-csi csi.storage.k8s.io/node-stage-secret-name: ceph-secret csi.storage.k8s.io/node-stage-secret-namespace: ceph-csi reclaimPolicy: Delete allowVolumeExpansion: true volumeBindingMode: Immediate

注意clusterID必须和ceph.conf里的fsid完全一致,pool: rbd必须是Ceph集群里真实存在的RADOS Pool。应用:

kubectl apply -f csi-rbd-sc.yaml kubectl get sc csi-rbd-sc -o wide # 预期:PROVISIONER是 rbd.csi.ceph.com,AGE正常

然后创建测试PVC:

kubectl apply -f test-pvc.yaml

观察PVC状态:

watch kubectl get pvc # 初始:test-rbd-pvc Pending # 几秒后:test-rbd-pvc Bound pvc-xxxxxx 1Gi RWO csi-rbd-sc 10s

如果一直Pending,检查csi-rbdplugin-provisioner-0日志:

kubectl logs csi-rbdplugin-provisioner-0 -n ceph-csi -c csi-provisioner | tail -20 # 正常流程会看到:"GRPC call: /csi.v1.Controller/CreateVolume" # 如果看到"rpc error: code = Internal desc = rbd: create volume failed",说明Ceph RBD池空间不足或权限不够

4.5 验证PV与Pod挂载(黄金检查点一)

PVC Bound后,自动创建PV。查看PV详情:

kubectl get pv # 找到NAME列以pvc-开头的PV,比如pvc-abc123 kubectl get pv pvc-abc123 -o yaml

在输出里重点找spec.csi.volumeHandle字段,它的值应该是一个UUID,比如0001-0009-ceph-csi-0000000000000001-12345678-1234-1234-1234-123456789012。这个UUID就是Ceph RBD Image的名字。登录Ceph Monitor节点验证:

rbd ls -p rbd | grep 12345678-1234-1234-1234-123456789012 # 应该输出:csi-vol-12345678-1234-1234-1234-123456789012

然后创建一个Pod挂载这个PVC:

# nginx-pod.yaml apiVersion: v1 kind: Pod metadata: name: nginx-rbd namespace: default spec: containers: - name: nginx image: nginx:alpine volumeMounts: - name: rbd-storage mountPath: /usr/share/nginx/html volumes: - name: rbd-storage persistentVolumeClaim: claimName: test-rbd-pvc

应用并检查:

kubectl apply -f nginx-pod.yaml kubectl get pod nginx-rbd # 状态必须是Running kubectl exec nginx-rbd -- df -h | grep rbd # 应该看到类似:/dev/rbd0 1014M 37M 978M 4% /usr/share/nginx/html

这才是真正的“黄金检查点”:从Kubernetes API到Ceph RBD Image,全链路打通。

4.6 动态供给全流程复现(黄金检查点二)

删掉测试Pod和PVC,触发完整的“申请-创建-绑定-挂载-释放”循环:

kubectl delete pod nginx-rbd kubectl delete pvc test-rbd-pvc

等待PVC彻底消失后,重新创建:

kubectl apply -f test-pvc.yaml # 等待Bound kubectl apply -f nginx-pod.yaml # 等待Running

这次,打开另一个终端,实时跟踪CSI Provisioner日志:

kubectl logs -f csi-rbdplugin-provisioner-0 -n ceph-csi -c csi-provisioner

你会看到清晰的四步日志流:

  1. GRPC call: /csi.v1.Controller/CreateVolume→ Provisioner收到请求
  2. rbd create rbd/csi-vol-xxx --size 1024 --image-format 2 --image-feature layering→ 调用rbd命令创建Image
  3. GRPC response: /csi.v1.Controller/CreateVolume→ 返回VolumeHandle
  4. GRPC call: /csi.v1.Controller/DeleteVolume→ 当PVC删除时触发

这四步全部出现,证明动态供给引擎100%在线。

4.7 故障注入与恢复测试(黄金检查点三)

最后一步,模拟真实故障:杀掉一个csi-rbdpluginPod,看DaemonSet是否自动恢复,且不影响已挂载的Pod:

kubectl delete pod -n ceph-csi -l app=csi-rbdplugin # 等待新Pod启动 kubectl get pods -n ceph-csi | grep rbdplugin # 应该看到新Pod Running,旧Pod Terminating

然后检查正在运行的nginx-rbdPod是否受影响:

kubectl exec nginx-rbd -- ls /usr/share/nginx/html # 应该能正常列出文件,说明挂载未中断

再测试PVC删除后RBD Image是否被自动清理:

kubectl delete pvc test-rbd-pvc # 等待PV状态变为Released # 登录Ceph Monitor,执行 rbd ls -p rbd | grep csi-vol- # 应该为空,说明Image已被自动删除

这三个“黄金检查点”全部通过,才算真正完成了Ceph-CSI的生产级部署。

5. 常见问题与排查技巧实录:来自47小时排错的五张速查表

以下是我在实际操作中遇到的、最具迷惑性的五个问题,按发生频率排序,并附上“30秒定位法”和“根治方案”。

5.1 问题一:csi-rbdplugin-provisioner-0卡在Init:CrashLoopBackOff,日志只有failed to load ceph config

现象日志片段30秒定位法根治方案
Pod状态为Init:CrashLoopBackOff,kubectl logs只显示failed to load ceph config: unable to get monitor list from config file or the environmenttime="2024-04-12T08:23:47.123Z" level=error msg="failed to load ceph config: unable to get monitor list from config file or the environment"kubectl describe pod csi-rbdplugin-provisioner-0 -n ceph-csi→ 查看Events里是否有MountVolume.SetUp failed for volume "ceph-config"检查csi-rbdplugin-provisioner.yaml中volumes部分是否正确定义了ceph-configConfigMap卷,且volumeMounts的mountPath是/etc/ceph/,不是/etc/ceph/ceph.conf。ConfigMap挂载时,路径必须是目录,文件名由subPath指定

实操心得:很多人以为subPath: ceph.conf就能把文件挂载到/etc/ceph/ceph.conf,但Kubernetes要求mountPath必须是目录,subPath才是文件名。正确写法是mountPath: /etc/ceph+subPath: ceph.conf。否则/etc/ceph/目录是空的,CSI自然读不到配置。

5.2 问题二:csi-rbdpluginDaemonSet在部分Node上Pending,Events显示0/3 nodes are available: 3 node(s) had taints that the pod didn't tolerate

现象日志片段30秒定位法根治方案
kubectl get ds -n ceph-csi显示DESIRED=3, CURRENT=2,kubectl get nodes显示3个Node都ReadyEvents:<br> Type Reason Age From Message<br> ---- ------ ---- ---- -------<br> Warning FailedScheduling 11s (x2 over 11s) default-scheduler 0/3 nodes are available: 3 node(s) had taints that the pod didn't tolerate.kubectl describe node <node-name>→ 查看Taints字段在csi-rbdplugin.yaml的spec.template.spec里,添加tolerations字段:
yaml<br>tolerations:<br>- key: "node-role.kubernetes.io/control-plane"<br> operator: "Exists"<br> effect: "NoSchedule"<br>- key: "node-role.kubernetes.io/master"<br> operator: "Exists"<br> effect: "NoSchedule"<br>
这样DaemonSet就能容忍control-plane节点的污点

实操心得:很多K8s集群把Master节点也作为Worker使用(--node-labels=node-role.kubernetes.io/worker=),但默认Master节点有node-role.kubernetes.io/control-plane:NoSchedule污点。CSI Node Plugin必须运行在所有能跑Pod的节点上,包括Master,所以必须显式容忍。

5.3 问题三:PVC一直Pending,csi-rbdplugin-provisioner-0日志出现rpc error: code = Internal desc = rbd: create volume failed

现象日志片段30秒定位法根治方案
PVC状态长期Pending,kubectl describe pvc显示`Waiting for a volume to be created

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询