☰

在 Kubernetes 上给数据库、消息队列和分布式多实例应用选存储,是每个规模化集群都绕不开的问题。我的场景是 15 个节点、每节点 12 块 8TB NVMe,总裸容量 1.44PB,需要同时提供 RWO 块存储和 RWX 共享文件存储。本文完整记录从方案调研、选型决策,到 Rook-Ceph 生产级部署与 NVMe 专项调优的全过程。

一、调研过程与最终结论

1.1 方案对比

方案存储类型核心优势数据高可用运维复杂度推荐场景
Rook-Ceph块/文件/对象统一平台,功能全面✅ 集群级自愈高通用生产环境,多存储需求
OpenEBS Mayastor块存储极致低延迟,NVMe-oF✅ 卷级副本中高性能数据库、消息队列
Longhorn块存储简单易用,运维轻松✅ 卷级副本低中小集群,运维资源有限
TopoLVM本地块存储拓扑感知,动态本地卷❌ 依赖应用层中自带复制的高性能应用
本地 PV 直通本地块存储性能无损,实现简单❌ 无极高(大规模)临时数据,性能基准

1.2 最终结论:Rook-Ceph

选择 Rook-Ceph 的核心理由:

  • 规模匹配:15 节点正好是 Ceph 的舒适区,可以构建功能完整的存储平台。
  • 统一存储:一套集群同时提供块存储(RBD,RWO)、文件存储(CephFS,RWX)和对象存储(S3/Swift),一次部署满足所有需求。
  • 高可用与弹性:数据默认 3 副本,节点故障时数据自动重建,Pod 可漂移,业务不中断。
  • NVMe 性能可充分释放:通过 osdsPerDevice 参数在单块盘上创建多个 OSD,充分利用 NVMe 内部并行性。对于 8TB 大容量 NVMe,建议设置 osdsPerDevice 为 4。
  • RWX 需求覆盖:CephFS 提供原生 RWX 共享文件存储,不像 Longhorn 的 RWX 需要经过 NFS 协议转换导致性能大幅下降。

1.3 关键硬件规划

15 节点 × 12 块 8TB NVMe,总裸容量 1,440 TB(约 1.44PB),规划如下:

项目配置
总裸容量1,440 TB
OSD 总数15 节点 × 12 盘 × 4 OSD/盘 = 720 OSD
数据保护3 副本,可用容量约 480 TB
MON 节点3 个(分布在不同节点)
MGR 节点2 个(Active/Standby)
OSD 内存需求每 OSD 约 1-4 GiB,单节点 48 OSD 约需 48-192 GiB RAM
OSD CPU 需求单节点建议 16-32 Core

⚠️ 注意:每 OSD 进程消耗约 1-4 GiB RAM(取决于缓存配置),每节点 12 盘 × 4 OSD = 48 OSD,请确保每节点内存充足。

二、部署前提条件

2.1 集群要求

  • Kubernetes 集群(v1.23+),至少 3 个 worker 节点
  • kubectl 和 helm 已配置管理员权限
  • 容器运行时推荐 containerd

2.2 节点准备(在每个 worker 节点执行)

加载内核模块:

1modprobe rbd
2modprobe ceph
3
4# 持久化配置
5echo "rbd" >> /etc/modules-load.d/rook.conf
6echo "ceph" >> /etc/modules-load.d/rook.conf

擦除目标 NVMe 磁盘(以 /dev/nvme0n1 为例,所有 12 块盘都需执行):

1# 确认磁盘无分区、无 LVM 状态
2wipefs -a /dev/nvme0n1
3dd if=/dev/zero of=/dev/nvme0n1 bs=1M count=100

对所有 12 块 NVMe 盘重复上述操作,依次为 /dev/nvme0n1 到 /dev/nvme11n1。

NVMe 内核调优(在每个 worker 节点执行):

1# 设置 I/O 调度器为 none(NVMe 无旋转延迟)
2for dev in /dev/nvme*n1; do
3  echo none > /sys/block/$(basename $dev)/queue/scheduler
4done
5
6# 增大 NVMe 队列深度
7echo 1024 > /sys/block/nvme0n1/queue/nr_requests

将调度器配置持久化(在 /etc/udev/rules.d/60-nvme-scheduler.rules 中添加):

ACTION=="add|change", KERNEL=="nvme*n1", ATTR{queue/scheduler}="none"

禁用透明大页(THP)。Ceph 官方建议禁用 THP,因为它在 OSD 节点上会导致延迟尖峰:

1echo never > /sys/kernel/mm/transparent_hugepage/enabled
2echo never > /sys/kernel/mm/transparent_hugepage/defrag
3
4# 持久化到 /etc/rc.local 或 systemd service

三、部署步骤

3.1 安装 Rook Operator

 1helm repo add rook-release https://charts.rook.io/release
 2helm repo update
 3
 4helm install rook-ceph rook-release/rook-ceph \
 5  --namespace rook-ceph \
 6  --create-namespace \
 7  --version 1.18.0 \
 8  --set csi.enableCSIHostNetwork=true \
 9  --set csi.enableRbdDriver=true \
10  --set csi.enableCephfsDriver=true

3.2 部署 Ceph Cluster

创建 cluster.yaml,针对全 NVMe 15 节点集群做了专项优化:

 1apiVersion: ceph.rook.io/v1
 2kind: CephCluster
 3metadata:
 4  name: rook-ceph
 5  namespace: rook-ceph
 6spec:
 7  cephVersion:
 8    image: quay.io/ceph/ceph:v18.2.0  # Reef 版本
 9  dataDirHostPath: /var/lib/rook
10  mon:
11    count: 3
12    allowMultiplePerNode: false
13  mgr:
14    count: 2
15    modules:
16      - name: pg_autoscaler
17        enabled: true
18      - name: dashboard
19        enabled: true
20  dashboard:
21    enabled: true
22    ssl: true
23  network:
24    connections:
25      compression:
26        enabled: false
27      encryption:
28        enabled: false
29  crashCollector:
30    disable: false
31  storage:
32    useAllNodes: false
33    useAllDevices: false
34    # 全局 NVMe 优化配置
35    config:
36      osdsPerDevice: "4"          # 每块 8TB NVMe 创建 4 个 OSD,充分利用并行性
37      deviceClass: "nvme"          # 显式指定设备类型,避免 Rook 自动检测不一致
38      metadataDevice: ""           # 全 NVMe 场景无需独立元数据设备
39    nodes:
40      - name: "worker-01"
41        devices:
42          - name: "nvme0n1"
43          - name: "nvme1n1"
44          - name: "nvme2n1"
45          - name: "nvme3n1"
46          - name: "nvme4n1"
47          - name: "nvme5n1"
48          - name: "nvme6n1"
49          - name: "nvme7n1"
50          - name: "nvme8n1"
51          - name: "nvme9n1"
52          - name: "nvme10n1"
53          - name: "nvme11n1"
54      - name: "worker-02"
55        devices:
56          - name: "nvme0n1"
57          # ... 同样列出 12 块盘
58      # ... 其余 13 个 worker 节点同样列出 12 块盘
59  resources:
60    osd:
61      requests:
62        cpu: "4"
63        memory: "8Gi"
64      limits:
65        cpu: "8"
66        memory: "16Gi"

关键参数说明:

参数值说明
osdsPerDevice"4"8TB NVMe 推荐值,4 个 OSD 分布在独立 LVM 逻辑卷上,减少锁竞争
deviceClass"nvme"显式指定,确保 CRUSH 规则按 NVMe 设备类正确分类
osd.requests.cpu"4"NVMe OSD 需要更多 CPU 线程保持设备繁忙
osd.requests.memory"8Gi"每 OSD 约 2GiB,为 BlueStore 缓存预留空间

应用配置:

1kubectl apply -f cluster.yaml

3.3 部署 Toolbox 并验证

 1kubectl apply -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/toolbox.yaml
 2
 3# 等待 toolbox 就绪
 4kubectl -n rook-ceph rollout status deploy/rook-ceph-tools
 5
 6# 检查集群健康状态
 7kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph status
 8
 9# 检查 OSD 树,确认每节点应有 48 个 OSD(12 盘 × 4 osdsPerDevice)
10kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph osd tree

预期结果:每节点应显示 48 个 OSD 条目,设备类为 nvme,总共 720 个 OSD。

四、NVMe 专项性能调优

集群就绪后,通过 Toolbox 执行以下配置,将 NVMe 性能充分释放。

4.1 BlueStore 缓存优化

 1# 增大 BlueStore 缓存至 8GB/OSD(NVMe 高并发随机读场景)
 2kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- \
 3  ceph config set osd bluestore_cache_size_ssd 8589934592
 4
 5# 设置最小分配大小为 4KB(匹配 NVMe 页大小,优化小 I/O)
 6kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- \
 7  ceph config set osd bluestore_min_alloc_size_ssd 4096
 8
 9# 禁用延迟写入(NVMe 直接写设备,避免 WAL 双写开销)
10kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- \
11  ceph config set osd bluestore_prefer_deferred_size_ssd 0

4.2 OSD 线程与 CPU 亲和性

1# 增加 OSD 操作分片和线程数(NVMe 需要更多 CPU 线程)
2kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- \
3  ceph config set osd osd_op_num_shards 16
4kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- \
5  ceph config set osd osd_op_num_threads_per_shard 4
6
7# 启用 NUMA 自动亲和
8kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- \
9  ceph config set osd osd_numa_auto_affinity true

4.3 恢复参数优化(NVMe 可承受更激进的重建)

1kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- \
2  ceph config set osd osd_recovery_max_active_ssd 10
3kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- \
4  ceph config set osd osd_max_backfills 8
5kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- \
6  ceph config set osd osd_recovery_sleep_ssd 0
7kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- \
8  ceph config set osd osd_backfill_scan_max 512

五、创建 StorageClass、PV、PVC 示例

5.1 创建 CephBlockPool(RBD 池)

先创建 NVMe 专用 CRUSH 规则:

1kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- \
2  ceph osd crush rule create-replicated nvme-rule default host nvme

创建 CephBlockPool:

 1apiVersion: ceph.rook.io/v1
 2kind: CephBlockPool
 3metadata:
 4  name: nvme-pool
 5  namespace: rook-ceph
 6spec:
 7  failureDomain: host          # 副本跨主机分布,节点故障不影响数据可用性
 8  replicated:
 9    size: 3                    # 3 副本
10  parameters:
11    crush_rule: nvme-rule      # 使用 NVMe 专用 CRUSH 规则
12  deviceClass: nvme

⚠️ 重要:如果在任何 Pool 上指定了 deviceClass,则必须在该集群的所有 Pool 上一致指定,以避免 CRUSH 根重叠警告和均衡器混乱。

应用:

1kubectl apply -f cephblockpool.yaml

5.2 创建 RBD StorageClass(RWO 块存储)

这是核心存储类,用于数据库等需要 RWO 卷的应用:

 1apiVersion: storage.k8s.io/v1
 2kind: StorageClass
 3metadata:
 4  name: rook-ceph-block
 5  annotations:
 6    storageclass.kubernetes.io/is-default-class: "true"  # 设为默认 StorageClass
 7provisioner: rook-ceph.rbd.csi.ceph.com
 8parameters:
 9  clusterID: rook-ceph
10  pool: nvme-pool
11  imageFormat: "2"
12  imageFeatures: layering,fast-diff,object-map,deep-flatten,exclusive-lock
13  # CSI Secrets
14  csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
15  csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
16  csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner
17  csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
18  csi.storage.k8s.io/controller-publish-secret-name: rook-csi-rbd-provisioner
19  csi.storage.k8s.io/controller-publish-secret-namespace: rook-ceph
20  csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
21  csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
22  # RBD 映射选项——NVMe 队列深度优化
23  mapOptions: "lock_on_read,queue_depth=1024"
24reclaimPolicy: Delete
25allowVolumeExpansion: true
26volumeBindingMode: Immediate

关键参数说明:

参数值说明
imageFeatureslayering,fast-diff,object-map,deep-flatten,exclusive-lock完整 RBD 功能集
mapOptionslock_on_read,queue_depth=1024NVMe 队列深度优化,提升并发 I/O 性能
allowVolumeExpansiontrue允许在线扩容

应用:

1kubectl apply -f storageclass-rbd.yaml

5.3 创建 CephFilesystem 和 CephFS StorageClass(RWX 共享存储)

创建 CephFilesystem:

 1apiVersion: ceph.rook.io/v1
 2kind: CephFilesystem
 3metadata:
 4  name: myfs
 5  namespace: rook-ceph
 6spec:
 7  metadataPool:
 8    replicated:
 9      size: 3
10  dataPools:
11    - name: data0
12      replicated:
13        size: 3
14      parameters:
15        crush_rule: nvme-rule
16  preserveFilesystemOnDelete: true
17  metadataServer:
18    activeCount: 1
19    activeStandby: true
20    resources:
21      requests:
22        cpu: "2"
23        memory: "4Gi"
24      limits:
25        cpu: "4"
26        memory: "8Gi"

创建 CephFS StorageClass:

 1apiVersion: storage.k8s.io/v1
 2kind: StorageClass
 3metadata:
 4  name: rook-cephfs
 5provisioner: rook-ceph.cephfs.csi.ceph.com
 6parameters:
 7  clusterID: rook-ceph
 8  fsName: myfs
 9  pool: myfs-data0
10  csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner
11  csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
12  csi.storage.k8s.io/controller-expand-secret-name: rook-csi-cephfs-provisioner
13  csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
14  csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node
15  csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
16reclaimPolicy: Delete
17allowVolumeExpansion: true
18volumeBindingMode: Immediate

应用:

1kubectl apply -f cephfilesystem.yaml
2kubectl apply -f storageclass-cephfs.yaml

5.4 创建 PVC 示例

RWO PVC(用于数据库、单实例应用):

 1apiVersion: v1
 2kind: PersistentVolumeClaim
 3metadata:
 4  name: my-database-pvc
 5  namespace: default
 6spec:
 7  accessModes:
 8    - ReadWriteOnce          # RWO——单节点读写
 9  storageClassName: rook-ceph-block
10  resources:
11    requests:
12      storage: 100Gi

RWX PVC(用于分布式多实例应用):

 1apiVersion: v1
 2kind: PersistentVolumeClaim
 3metadata:
 4  name: my-shared-pvc
 5  namespace: default
 6spec:
 7  accessModes:
 8    - ReadWriteMany          # RWX——多节点同时读写
 9  storageClassName: rook-cephfs
10  resources:
11    requests:
12      storage: 500Gi

应用并验证:

1kubectl apply -f pvc-rwo.yaml
2kubectl apply -f pvc-rwx.yaml
3
4# 验证 PVC 状态
5kubectl get pvc -A
6
7# 验证 PV 自动创建
8kubectl get pv

预期结果:PVC 状态应为 Bound,对应的 PV 由 CSI 驱动自动创建。

5.5 在 Pod 中使用 PVC

RWO 示例(数据库 Pod):

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: database-pod
 5  namespace: default
 6spec:
 7  containers:
 8    - name: mysql
 9      image: mysql:8.0
10      env:
11        - name: MYSQL_ROOT_PASSWORD
12          value: "your-password"
13      volumeMounts:
14        - name: data
15          mountPath: /var/lib/mysql
16  volumes:
17    - name: data
18      persistentVolumeClaim:
19        claimName: my-database-pvc

RWX 示例(多实例共享):

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: shared-app
 5  namespace: default
 6spec:
 7  replicas: 3                # 3 个实例共享同一个 RWX 卷
 8  selector:
 9    matchLabels:
10      app: shared-app
11  template:
12    metadata:
13      labels:
14        app: shared-app
15    spec:
16      containers:
17        - name: app
18          image: your-app:latest
19          volumeMounts:
20            - name: shared-data
21              mountPath: /data
22      volumes:
23        - name: shared-data
24          persistentVolumeClaim:
25            claimName: my-shared-pvc

六、部署后验证与监控

6.1 集群健康检查

 1# 集群整体状态(应显示 HEALTH_OK)
 2kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph status
 3
 4# OSD 树(每节点应有 48 个 OSD)
 5kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph osd tree
 6
 7# 存储池状态
 8kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph df
 9
10# PG 状态(所有 PG 应处于 active+clean)
11kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph pg stat

6.2 性能基准测试

1# RBD 随机写基准(4K 块,60 秒)
2kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- \
3  rados -p nvme-pool bench 60 write -b 4096 --no-cleanup
4
5# RBD 随机读基准
6kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- \
7  rados -p nvme-pool bench 60 rand

6.3 部署 Dashboard

Dashboard 已在 cluster.yaml 中启用(dashboard.enabled: true)。获取访问方式:

1kubectl -n rook-ceph get service rook-ceph-mgr-dashboard

七、生产环境注意事项

7.1 网络规划

  • 建议为 Ceph 配置专用网络(publicNetwork 和 clusterNetwork),将 OSD 复制流量与业务 Pod 网络隔离。1.44PB 的全 NVMe 集群,复制流量巨大,与 Pod 网络共享会导致业务抖动。
  • 建议使用 25GbE+ 网络,NVMe OSD 的吞吐能力远超万兆网络瓶颈。
  • 如果使用 Jumbo Frame(MTU 9000),需要在所有节点和交换机上一致配置。

7.2 MON 和 MGR 节点选择

  • MON 节点应分布在 3 个不同的物理节点上,且这些节点应尽量独立于故障域(如不同机架)。
  • MGR 节点建议与 MON 节点错开部署,避免单节点故障同时影响 MON 和 MGR。

7.3 PG 数量规划

对于 720 个 OSD 的集群,pg_autoscaler 已启用,会自动根据 Pool 容量和使用情况调整 PG 数量。初始阶段 PG 数可能较少,随着数据写入会自动扩展。不要手动设置过大的 pg_num,让自动缩放器管理即可。

7.4 节点故障恢复

  • 单节点故障:720 OSD 中 48 个 OSD 离线(6.7%),3 副本情况下数据仍然可用,Ceph 会自动在其他节点重建数据。
  • NVMe 恢复参数已优化(osd_recovery_max_active_ssd: 10),重建速度会比默认配置快数倍。
  • 建议监控 ceph status 中的 recovery 进度,确保重建在合理时间内完成。

7.5 硬件选型注意事项

不推荐 RAID 控制器:Ceph 自身提供副本,RAID 会降低性能并导致故障定位困难。推荐使用 HBA 直通模式将 NVMe 盘直接暴露给 OSD。

八、完整部署顺序总结

步骤操作命令/文件
1节点准备(内核模块、擦盘、NVMe 调优)各节点执行
2安装 Rook Operatorhelm install rook-ceph
3部署 Ceph Clusterkubectl apply -f cluster.yaml
4部署 Toolbox 并验证集群kubectl apply -f toolbox.yaml
5NVMe 性能调优(BlueStore、线程、恢复)ceph config set 系列命令
6创建 CRUSH 规则ceph osd crush rule create-replicated
7创建 CephBlockPoolkubectl apply -f cephblockpool.yaml
8创建 RBD StorageClasskubectl apply -f storageclass-rbd.yaml
9创建 CephFilesystem 和 CephFS StorageClasskubectl apply -f cephfilesystem.yaml storageclass-cephfs.yaml
10创建 PVC 并测试kubectl apply -f pvc-rwo.yaml pvc-rwx.yaml
11性能基准测试rados bench

按照以上步骤执行,15 节点全 NVMe 的 Rook-Ceph 集群即可投入生产使用,同时提供 RWO 块存储和 RWX 共享文件存储,满足分布式多实例应用的需求。