「Ceph+K8s 中间件实战」系列 · 第 2/15 天
引言:为什么 K8s 需要 Ceph RBD
在「第 1 天」里,我们梳理了 Ceph 分布式存储的整体形态和 K8s 存储体系(PV / PVC / StorageClass / CSI)的脉络。今天开始真正动手——把 Ceph 的 RBD(RADOS Block Device)块存储接入到 Kubernetes 集群中。
RBD 是 Ceph 最经典、也是性能最稳定的一种对外暴露形态:它将 RADOS 对象池切成固定大小的块设备镜像(image),内核通过 krbd 或用户态 nbd 挂载,对外表现就是一块 /dev/rbdX 的块设备。对于 MySQL、Redis、Kafka 这类单实例读写、要求高 IOPS 与低延迟的中间件来说,RBD 是首选——它读写路径短、支持精简置备(thin provisioning)、支持快照与克隆。
本篇会完整演示:在已就绪的 Ceph 集群上,使用官方 ceph-csi-rbd Helm Chart 部署 CSI Driver,创建指向 Ceph pool 的 StorageClass,再用一个 Pod 验证 PVC 动态供给与持久化挂载。整个流程完成后,后续所有中间件篇章都可以复用这个 StorageClass。

一、设计架构:Ceph RBD CSI 全景拓扑
1.1 组件拓扑
Ceph RBD CSI Driver 由两部分组成:Controller(Deployment)负责在控制面创建/删除/扩容/快照 RBD image;Node(DaemonSet)在每个计算节点上负责把 RBD image map 成块设备并挂载到 Pod。
| 组件 | 形态 | 职责 |
|---|---|---|
csi-rbdplugin-controller |
Deployment(副本=2,leader election) | 调用 Ceph API 创建/删除 image、扩容、快照管理 |
csi-rbdplugin |
DaemonSet(每节点一份) | 在节点上 map/unmap RBD image,格式化并 mount 到 Pod |
csi-provisioner |
sidecar | 监听 PVC 事件,触发 CreateVolume/DeleteVolume |
csi-attacher |
sidecar | 管理 VolumeAttachment 对象 |
csi-snapshotter |
sidecar | 处理 VolumeSnapshot 资源 |
csi-resizer |
sidecar | 处理 PVC 扩容 |
csi-rbdplugin-controller / csi-rbdplugin |
主容器 | 真正实现 CSI gRPC 接口(Identity/Controller/Node) |
1.2 数据流向
一条 PVC 的动态供给请求,经历以下路径:
用户提交 PVC (storageClassName=ceph-rbd-sc)
│
▼
StorageClass 触发 csi-provisioner
│
▼
csi-rbdplugin-controller 调用 Ceph 集群
│ rbd create <pool>/csi-vol-<uuid> –size <GiB>
▼
Ceph pool 中生成一个 RBD image
│
▼
Pod 调度到某 Node → kubelet 调用 NodeStageVolume
│
▼
csi-rbdplugin (DaemonSet) 在该节点执行
│ rbd map <pool>/<image> → /dev/rbd0
│ (默认走 krbd 内核模块;内核版本过低时回退 nbd)
▼
格式化为 ext4/xfs → 挂载到 Pod 的 mountPath
│
▼
业务容器看到 /mnt/data,即可读写
1.3 高可用与一致性机制
- Controller 高可用:
csi-rbdplugin-controller副本数为 2,通过 leader-election 锁保证同一时刻只有一个实例执行变更操作,避免双写。 - 数据冗余:RBD image 写入的数据由 Ceph pool 的 CRUSH 副本策略保护,典型配置
size=3, min_size=2,三副本分布在三个 OSD / 三个 host。 - Read-write-once:RBD 本质是块设备,K8s 层 PVC
accessModes必须为ReadWriteOnce(单 Pod 独占)。多 Pod 共享需用 CephFS(第 3 天)。 - 快照与克隆:RBD 支持
rbd snap create与rbd clone,配合VolumeSnapshotClass可做定时备份、测试环境克隆。
1.4 存储规划(示例)
| 项目 | 取值 | 说明 |
|---|---|---|
| Ceph 集群 fsid | a3f4c1b2-... |
ceph fsid 获取,CSI 凭此定位集群 |
| pool 名称 | kube-rbd-pool |
专门给 K8s 用,建议与 CephFS pool 隔离 |
| 副本策略 | size=3 min_size=2 |
跨三个 host |
| image features | layering |
最安全,兼容所有内核;高端内核可加 object-map,exclusive-lock |
| 客户端 | client.kubernetes |
仅授予该 pool 的 mon/rbd 权限 |
| StorageClass | ceph-rbd-sc |
后续中间件统一引用 |
二、部署实战:ceph-csi-rbd Helm Chart 全流程
Ceph CSI 官方维护了 Helm Chart 仓库 https://ceph.github.io/csi-charts,本节全程使用它,避免手写一堆 YAML。
2.1 在 Ceph 侧准备:创建 pool 与客户端
在任一 Ceph monitor / admin 节点上执行:
# 创建专供 K8s 使用的 replicated pool
ceph osd pool create kube-rbd-pool 64
ceph osd pool set kube-rbd-pool size 3
ceph osd pool set kube-rbd-pool min_size 2
# 启用 RBD 应用层
rbd pool init kube-rbd-pool
# 创建专用客户端 client.kubernetes,仅授权该 pool
ceph auth get-or-create client.kubernetes
mon 'profile rbd'
osd 'profile rbd pool=kube-rbd-pool'
-o /etc/ceph/ceph.client.kubernetes.keyring
# 取出后续 CSI 要用的两个值
echo "FSID=$(ceph fsid)"
echo "USER_KEY=$(ceph auth get-key client.kubernetes)"
记下 fsid 和 userKey,下一步写进 K8s Secret。
2.2 helm repo add:添加 Ceph CSI Chart 仓库
# 添加官方 Ceph CSI Helm 仓库
helm repo add ceph-csi https://ceph.github.io/csi-charts
helm repo update
# 确认 chart 可见
helm search repo ceph-csi/ceph-csi-rbd
# 期望输出类似:
# NAME CHART VERSION APP VERSION DESCRIPTION
# ceph-csi/ceph-csi-rbd 3.x.x 3.x CSI RBD Driver for Ceph
2.3 在 K8s 中创建 Ceph 凭据 Secret
CSI 通过 K8s Secret 拿到 Ceph 客户端密钥与集群配置。先准备 namespace 与 Secret:
kubectl create namespace ceph-csi-rbd
# 把上一步取到的值填入(base64 编码 userKey)
kubectl create secret generic ceph-rbd-admin
–namespace ceph-csi-rbd
–type=kubernetes.io/rbd
–from-literal=userID='kubernetes'
–from-literal=userKey='<替换为 ceph auth get-key 输出>'
# 集群连接信息(csi-config ConfigMap,集群可写多个)
cat << 'EOF' | kubectl apply -f –
apiVersion: v1
kind: ConfigMap
metadata:
name: ceph-rbd-config
namespace: ceph-csi-rbd
data:
config.json: |-
[
{
"clusterID": "<替换为 ceph fsid 输出>",
"monitors": [
"192.168.10.11:6789",
"192.168.10.12:6789",
"192.168.10.13:6789"
],
"cephFS": {
"subvolumeGroup": ""
}
}
]
EOF
2.4 编写 values.yaml:storageClass 指向 Ceph
这是本篇的核心配置文件。重点关注 storageClass 段——它声明了 CSI 在 PVC 请求时如何映射到 Ceph pool:
# ceph-rbd-values.yaml
# 对应 chart: ceph-csi/ceph-csi-rbd
csiConfig:
– clusterID: "<替换为 ceph fsid>"
monitors:
– "192.168.10.11:6789"
– "192.168.10.12:6789"
– "192.168.10.13:6789"
provisioner:
name: rbd.csi.ceph.com
replicaCount: 2 # Controller 高可用,leader-election 自动开启
resources:
limits: { cpu: 500m, memory: 512Mi }
requests: { cpu: 100m, memory: 128Mi }
nodeplugin:
resourceRequests: { cpu: 100m, memory: 128Mi }
resourceLimits: { cpu: 500m, memory: 512Mi }
# 关键:StorageClass 自动随 chart 一起创建
storageClass:
create: true
name: ceph-rbd-sc # 后续中间件 values.yaml 都引用这个名字
clusterID: "<替换为 ceph fsid>"
pool: kube-rbd-pool # 对应 Ceph pool
imageFeatures: "layering" # 兼容所有内核版本,最稳
secretName: ceph-rbd-admin # 引用上一步的 Secret
mounter: rbd # 优先用内核 krbd;不兼容时回退 nbd
fsType: ext4
reclaimPolicy: Retain # 删 PVC 时保留数据,防止误删
allowVolumeExpansion: true # 允许 PVC 在线扩容
encrypted: "false"
说明:
reclaimPolicy: Retain比Delete更安全——中间件升级或重建时不会因为 PVC 删除导致数据丢失;如确需自动回收,可改为Delete。
2.5 helm install:部署 CSI Driver
helm install ceph-csi-rbd ceph-csi/ceph-csi-rbd
–namespace ceph-csi-rbd
–create-namespace
–values ceph-rbd-values.yaml
–version 3.x.x # 用 helm search 看到的最新稳定版
# 等待所有 Pod 就绪
kubectl -n ceph-csi-rbd rollout status deploy/csi-rbdplugin-controller
kubectl -n ceph-csi-rbd rollout status ds/csi-rbdplugin
2.6 验证 CSI Driver 与 StorageClass 状态
# 1) Controller + DaemonSet 全部 Running
kubectl -n ceph-csi-rbd get pods -o wide
# 2) StorageClass 已自动创建,provisioner 指向 rbd.csi.ceph.com
kubectl get sc ceph-rbd-sc -o yaml
# 期望看到关键参数:
# provisioner: rbd.csi.ceph.com
# parameters.pool: kube-rbd-pool
# parameters.clusterID: <fsid>
期望输出(节选):
NAME READY STATUS AGE
csi-rbdplugin-controller-xxxx1 6/6 Running 2m
csi-rbdplugin-controller-xxxx2 6/6 Running 2m
csi-rbdplugin-aaaa1 3/3 Running 2m (node1)
csi-rbdplugin-bbbb1 3/3 Running 2m (node2)
三、端到端验证:动态供给一个 PVC
光装好 CSI 不够,必须用一个真实 Pod 跑通「PVC 请求 → Ceph 创建 image → Pod 挂载」全链路。
cat << 'EOF' | kubectl apply -f –
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rbd-test-pvc
namespace: default
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: ceph-rbd-sc
resources:
requests:
storage: 5Gi
—
apiVersion: apps/v1
kind: Deployment
metadata:
name: rbd-test
spec:
replicas: 1
selector:
matchLabels: { app: rbd-test }
template:
metadata:
labels: { app: rbd-test }
spec:
containers:
– name: busybox
image: busybox:1.36
command: ["sh", "-c", "echo hello-rbd > /data/rbd.txt && sleep 3600"]
volumeMounts:
– { name: data, mountPath: /data }
volumes:
– name: data
persistentVolumeClaim:
claimName: rbd-test-pvc
EOF
# PVC 应在数秒内变 Bound
kubectl get pvc rbd-test-pvc
# 期望:rbd-test-pvc Bound pvc-xxx 5Gi RWO ceph-rbd-sc 15s
# 验证 Pod 写入成功
kubectl exec deploy/rbd-test — cat /data/rbd.txt
# 期望:hello-rbd
同时在 Ceph 端可以看到新生成的 image:
rbd ls kube-rbd-pool
# 期望:csi-vol-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
rbd info kube-rbd-pool/csi-vol-xxxxx
# size 5GiB, order 23, features: layering
至此,Ceph RBD 已正式成为 K8s 的一等公民,后续所有中间件只要在 values.yaml 里写 storageClass: ceph-rbd-sc,就能自动拿到一块由 Ceph 三副本保护的持久化块设备。

四、登录验证命令
接入完成后,常用验证命令分两侧:
# —— K8s 侧 ——
kubectl get sc # 列出所有 StorageClass
kubectl describe sc ceph-rbd-sc # 查看参数、provisioner、绑定 Secret
kubectl -n ceph-csi-rbd get pods # CSI 控制器与节点插件健康
kubectl get pv # 已动态分配的 PV
kubectl get pvc -A # 各命名空间的 PVC 绑定状态
# —— Ceph 侧 ——
ceph status # 集群整体健康(HEALTH_OK)
ceph osd pool ls | grep rbd # 确认 pool 存在
ceph osd pool stats kube-rbd-pool # 查看 pool 读写吞吐
rbd ls kube-rbd-pool # 列出所有 RBD image
rbd info kube-rbd-pool/csi-vol-xxxxx # 查看 image 容量与 features
ceph auth get client.kubernetes # 复核客户端权限
一条快速自检脚本,可放进运维工具箱:
cat > /usr/local/bin/ceph-rbd-check.sh << 'EOF'
#!/bin/bash
echo "== StorageClass =="
kubectl get sc ceph-rbd-sc -o jsonpath='{.provisioner}{"n"}'
echo "== CSI Pods =="
kubectl -n ceph-csi-rbd get pods –no-headers | awk '{print $1,$2,$3}'
echo "== Ceph Health =="
ceph health
echo "== RBD images count =="
rbd ls kube-rbd-pool | wc -l
EOF
chmod +x /usr/local/bin/ceph-rbd-check.sh
五、日常巡检基础命令
RBD 接入后,日常巡检聚焦三件事:CSI 进程健康、PVC 容量水位、Ceph pool 性能。
# 1) CSI 进程巡检(Controller 不能掉,DaemonSet 每节点都得有)
kubectl -n ceph-csi-rbd get deploy/csi-rbdplugin-controller
kubectl -n ceph-csi-rbd get ds/csi-rbdplugin
# 若某节点 Pod 异常,先看日志:
kubectl -n ceph-csi-rbd logs <node-pod> -c csi-rbdplugin –tail=100
# 2) PVC 容量水位巡检(找出快满的卷)
kubectl get pvc -A -o json |
python3 -c "import sys,json;
[print(f"{p['metadata']['namespace']}/{p['metadata']['name']}"
f" {p['spec']['resources']['requests']['storage']}"
f" status={p['status'].get('phase')}")
for p in json.load(sys.stdin)['items']]"
# 3) Ceph pool 性能与容量
ceph df | grep -A2 kube-rbd-pool # 已用/可用
ceph osd pool stats kube-rbd-pool # IOPS、字节吞吐
# 4) RBD 镜像级容量与 IO
rbd du kube-rbd-pool # 每个 image 实际占用(thin provision)
rbd perf image iotop kube-rbd-pool # 实时 IO 排行(需 rbd 支持且无活跃 reader 阻塞)
# 5) 节点侧块设备映射状态
lsblk | grep rbd # 当前 map 的 RBD 设备
cat /proc/partitions | grep rbd # 内核 rbd 模块注册的设备
dmesg | grep -i rbd | tail # RBD 相关内核日志(映射失败排查)
建议把前 3 项接入 Prometheus(CSI Driver 自带 metrics 端口 :8080/metrics、Ceph 有 ceph_exporter),统一在 Grafana 看板上展示——这部分会在第 15 天统一总结。
六、常见问题 FAQ
Q1:Pod 一直 ContainerCreating,事件报 rbd: map failed: (6) No such device or address?
绝大多数是 imageFeatures 与内核 krbd 模块不兼容。CentOS 7 / 旧内核不支持 object-map、journaling 等 feature。解决:把 StorageClass 的 imageFeatures 改成只保留 "layering",或临时切 mounter: nbd(用户态,性能略低但兼容性好)。排查命令:modinfo rbd 看 version,rbd feature disable <pool>/<img> object-map fast-diff deep-flatten 可对已建 image 关闭不兼容 feature。
Q2:PVC 一直 Pending,describe 看到 failed to provision: rpc error ... key not found?
通常是 Secret 里的 userID / userKey 写错或没 base64 编码(--type=kubernetes.io/rbd 时部分版本要求明文,部分版本要求 base64)。复核:kubectl -n ceph-csi-rbd get secret ceph-rbd-admin -o yaml,确认 data 里有 userID、userKey,且 userKey 与 ceph auth get-key client.kubernetes 输出一致。
Q3:扩容 PVC 后,Pod 内 df -h 看到旧容量?
RBD 在线扩容需要 csi-resizer sidecar 正常工作且文件系统支持 online resize(ext4/xfs 都支持)。扩容后 Pod 内执行 sudo resize2fs /dev/rbdX(ext4)或 sudo xfs_growfs /data(xfs)即可生效;CSI 通常会自动 resize,但冷挂载的卷需重启 Pod 触发。
七、总结
今天我们完成了 Ceph RBD 块存储接入 K8s 的完整闭环:
- 在 Ceph 侧建好专用 pool 与最小权限客户端
client.kubernetes; - 用官方
ceph-csi-rbdHelm Chart 一键部署 Controller + DaemonSet; - 通过
values.yaml中的storageClass段落把 StorageClass 自动指向 Ceph pool; - 用一个测试 Pod 跑通了动态供给链路,并在 K8s 与 Ceph 双侧验证成功。
得到的 ceph-rbd-sc 这个 StorageClass,将成为后续 MySQL、Redis Cluster、MongoDB、Elasticsearch、Kafka、ClickHouse 等中间件的统一持久化底座。掌握这套接入姿势,意味着你已经把 Ceph 三副本的可靠性”接入了 K8s 的血管”。
下期预告
明天(第 3 天)我们将接入 CephFS 共享文件存储,解决 RBD「单 Pod 独占」的限制——用 ceph-csi-cephfs Chart 部署 CSI,创建支持 ReadWriteMany 的 StorageClass,并讲解多读场景下的性能调优与 subvolume 隔离策略。CMDB、配置中心、Web 静态资源这类多副本共享读写场景会用到它。
系列目录
- ✅ 第 1 天:Ceph 分布式存储回顾与 K8s 存储体系概述
- 📍 第 2 天:K8s 接入 Ceph RBD 块存储(CSI Driver + StorageClass 配置实战)(本文)
- ⏳ 第 3 天:K8s 接入 CephFS 共享文件存储(多读场景与性能调优)
- ⏳ 第 4 天:K8s 部署 MySQL 高可用集群(Ceph RBD 持久化 + 架构设计 + 登录巡检)
- ⏳ 第 5 天:K8s 部署 Redis Cluster 集群(Ceph RBD + 架构设计 + 巡检命令)
- ⏳ 第 6 天:K8s 部署 Redis Sentinel 哨兵模式(高可用架构 + 登录验证)
- ⏳ 第 7 天:K8s 部署 MinIO 对象存储集群(分布式架构 + 运维巡检)
- ⏳ 第 8 天:K8s 部署 MongoDB 副本集集群(Ceph RBD + 架构设计 + 登录)
- ⏳ 第 9 天:K8s 部署 Nacos 注册配置中心(集群架构 + 登录巡检)
- ⏳ 第 10 天:K8s 部署 Zookeeper 集群(分布式协调架构 + 运维命令)
- ⏳ 第 11 天:K8s 部署 Elasticsearch 集群(Ceph RBD + 架构设计 + 巡检)
- ⏳ 第 12 天:K8s 部署 Kafka 集群(Ceph RBD + 消息队列架构 + 运维)
- ⏳ 第 13 天:K8s 部署 GitLab 代码托管平台(Ceph RBD 持久化 + 架构 + 巡检)
- ⏳ 第 14 天:K8s 部署 ClickHouse 列式数据库集群(Ceph RBD + 架构设计)
- ⏳ 第 15 天:K8s 中间件统一监控与运维巡检总结(Prometheus + Grafana 全景)

















暂无评论内容