Ceph+K8s 中间件实战 | 第 2 天:K8s 接入 Ceph RBD 块存储(CSI Driver + StorageClass 配置实战)

「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。

K8s Logo

一、设计架构: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 createrbd 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)"

记下 fsiduserKey,下一步写进 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: RetainDelete 更安全——中间件升级或重建时不会因为 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 Logo

四、登录验证命令

接入完成后,常用验证命令分两侧:

💻 代码示例

# —— 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-mapjournaling 等 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 里有 userIDuserKey,且 userKeyceph 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 的完整闭环:

  1. 在 Ceph 侧建好专用 pool 与最小权限客户端 client.kubernetes
  2. 用官方 ceph-csi-rbd Helm Chart 一键部署 Controller + DaemonSet;
  3. 通过 values.yaml 中的 storageClass 段落把 StorageClass 自动指向 Ceph pool;
  4. 用一个测试 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 全景)
微信二维码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像 - 恒星
欢迎您留下宝贵的见解!
提交
头像 - 恒星

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容