痛点
Kubernetes 集群跑有状态服务(数据库、消息队列、对象存储)时,存储始终是最大的痛点:
- 云厂商 EBS/EFS 成本高:大规模集群每月存储账单轻松破万美元,且 IOPS 按量计费让预算不可控
- hostPath/local PV 无高可用:节点宕机数据丢失,运维半夜被 PagerDuty 叫醒
- 外置 Ceph 集群运维复杂:独立于 K8s 的 Ceph 集群需要单独的运维团队,升级和扩容都是噩梦
Rook 把 Ceph 变成 Kubernetes 的一等公民——用 Operator 模式管理分布式存储,让存储和计算在同一个控制平面内声明式管理。
方案
Rook 是 CNCF 毕业项目,作为 Kubernetes 存储编排层,将 Ceph 的部署、扩容、升级、自愈全部 CRD 化。核心架构:
┌─────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌───────────┐ ┌──────────────────┐ │
│ │ Rook │ │ Ceph Cluster │ │
│ │ Operator │───▶│ MON / OSD / MDS │ │
│ └───────────┘ └──────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌───────────┐ ┌──────────────────┐ │
│ │ CRDs │ │ CSI Driver │ │
│ │ (Cluster, │ │ (RBD/CephFS/ │ │
│ │ Pool, │ │ Object Store) │ │
│ │ Object) │ └──────────────────┘ │
│ └───────────┘ │
└─────────────────────────────────────────┘
适用场景: - 裸金属 / 自建 K8s 集群需要高可用块存储 - 需要同时提供 Block(RBD)、File(CephFS)、Object(S3 兼容) 三种存储 - 希望存储运维纳入 GitOps 流程
实操步骤
第一步:部署 Rook Operator
# 添加 Helm 仓库
helm repo add rook-release https://charts.rook.io/release
helm repo update
# 部署 Operator(建议独立 namespace)
helm install --create-namespace --namespace rook-ceph \
rook-ceph rook-release/rook-ceph \
--set csi.enableRbdDriver=true \
--set csi.enableCephfsDriver=true \
--set monitoring.enabled=true
# 确认 Operator Running
kubectl -n rook-ceph get pods -l app=rook-ceph-operator
第二步:创建 Ceph 集群
# cluster.yaml
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
cephVersion:
image: quay.io/ceph/ceph:v18.2 # Reef LTS
dataDirHostPath: /var/lib/rook
mon:
count: 3
allowMultiplePerNode: false
mgr:
count: 2
modules:
- name: prometheus
enabled: true
storage:
useAllNodes: true
useAllDevices: false
devices:
- name: "nvme1n1" # 指定裸盘,不要用系统盘
- name: "nvme2n1"
config:
osdsPerDevice: "1"
resources:
osd:
requests:
cpu: "2"
memory: "4Gi"
limits:
cpu: "4"
memory: "8Gi"
network:
provider: host # 生产环境推荐 host 网络,减少网络开销
kubectl apply -f cluster.yaml
# 等待集群 Ready(约 3-5 分钟)
kubectl -n rook-ceph get cephcluster -w
第三步:创建存储池 + StorageClass
# pool.yaml
apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
name: replicapool
namespace: rook-ceph
spec:
failureDomain: host # 按 host 级别做副本分散
replicated:
size: 3 # 三副本
requireSafeReplicaSize: true
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: rook-ceph-block
provisioner: rook-ceph.rbd.csi.ceph.com
parameters:
clusterID: rook-ceph
pool: replicapool
imageFormat: "2"
imageFeatures: layering,fast-diff,object-map,deep-flatten
csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
csi.storage.k8s.io/fstype: ext4
reclaimPolicy: Retain
allowVolumeExpansion: true
kubectl apply -f pool.yaml
# 验证:创建一个测试 PVC
kubectl apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-rbd-pvc
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: rook-ceph-block
resources:
requests:
storage: 10Gi
EOF
kubectl get pvc test-rbd-pvc # 应为 Bound 状态
第四步:监控与运维工具箱
# 部署 Ceph Toolbox(集群内调试)
kubectl apply -f https://raw.githubusercontent.com/rook/rook/release-1.14/deploy/examples/toolbox.yaml
# 进入 Toolbox 检查集群状态
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph status
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph osd tree
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph df
# Prometheus 指标(Operator 自动暴露 ServiceMonitor)
kubectl -n rook-ceph get servicemonitor
避坑指南
1. 裸盘选择:绝不使用已分区/已挂载的磁盘
Rook OSD 需要未格式化的裸设备。如果磁盘上有分区表或文件系统,OSD 创建会静默失败:
# 检查磁盘是否干净
lsblk -f /dev/nvme1n1
# 输出中 FSTYPE 应为空
# 清理磁盘(危险操作,确认无数据)
wipefs -a /dev/nvme1n1
sgdisk --zap-all /dev/nvme1n1
2. Mon 数量必须为奇数,且分散到不同节点
Mon 是 Ceph 的大脑,使用 Paxos 协议。偶数个 Mon 会导致脑裂风险。生产环境固定 3 或 5 个,并用 allowMultiplePerNode: false 强制分散:
# 确保集群至少 3 个节点有 mon 标签
kubectl label node node1 node2 node3 ceph-mon=enabled
3. 网络带宽是存储性能瓶颈
Ceph 副本复制走网络,10Gbps 是最低要求。25Gbps+ 生产推荐。部署前务必用 iperf3 验证节点间带宽:
# 节点 A
iperf3 -s
# 节点 B
iperf3 -c <node-A-IP> -t 30 -P 4
# 期望:单流 > 9Gbps(10G网卡)或 > 20Gbps(25G网卡)
如果用 Pod 网络(Calico/Cilium),务必开启 eBPF datapath 并设置 MTU 9000(Jumbo Frame)。
总结
| 维度 | Rook-Ceph | 云厂商 EBS | 外置 Ceph |
|---|---|---|---|
| 运维复杂度 | 中(CRD 声明式) | 低 | 高 |
| 成本(100TB) | ~$3k/月(硬件摊销) | ~$10k+/月 | ~$3k/月 |
| 高可用 | 三副本 + 自动恢复 | 跨 AZ | 依赖手动配置 |
| 存储类型 | Block/File/Object | Block/File | Block/File/Object |
| GitOps 友好 | ✅ 原生 CRD | ❌ | ❌ |
落地建议:
- 小规模试水:先在 3 节点测试集群验证,每节点 1 块 NVMe 即可
- 生产配置:至少 3 节点 × 2 NVMe,网络 25Gbps+,Mon/OSD 分开调度
- 监控先行:部署前先确保 Prometheus + Grafana 就绪,导入 Ceph Dashboard
- 备份兜底:Rook-Ceph 解决的是高可用,不是备份——关键数据仍需 Velero 定期快照到对象存储
存储是 Kubernetes 有状态负载的地基,Rook-Ceph 让这个地基可以用 kubectl apply 管理,这才是云原生存储该有的样子。