云原生存储实战:Ceph vs Rook vs 云厂商对象存储,持久化存储怎么选?

6 阅读5分钟

上 Kubernetes 之前,很多团队忽略了一个关键问题:容器是无状态的,但数据库、文件系统是有状态的。选错存储方案,要么数据丢失,要么运维噩梦。

这篇文章从真实踩坑经历出发,帮你搞清楚云原生存储三大路线的选择逻辑。


1. 云原生存储的 3 种路线

在 Kubernetes 上做持久化存储,主要有三条路可走:

路线代表方案适合谁核心优势核心痛点
自建分布式存储Ceph大型企业/私有云完全自主可控运维极复杂
K8s 原生存储编排Rook云原生团队与 K8s 深度集成依赖底层存储
云厂商托管存储COS/OSS/S3中小团队/上云零运维厂商锁定
CSI 存储插件NFS/Longhorn小团队快速上线简单易用性能有限

一句话选型原则

  • 预算充足 + 上云 → 直接用云厂商托管存储
  • 私有化部署 + 有运维能力 → Rook + Ceph
  • 快速上线 + 小规模 → Longhorn 或 NFS

2. Ceph 是什么?能做什么?

Ceph 是一个统一的分布式存储系统,同时支持对象存储、块存储、文件系统。

Ceph 核心架构

                    ┌─────────────────────────────────┐
                    │          RADOS 存储池            │
    ┌───────────┐   │  ┌──────┐ ┌──────┐ ┌──────┐   │
    │ 客户端     │──▶│  │ OSD  │ │ OSD  │ │ OSD  │   │
    └───────────┘   │  │(磁盘)│ │(磁盘)│ │(磁盘)│  │
         │          │  └──────┘ └──────┘ └──────┘   │
         ▼          │  ┌──────────────────────────┐  │
    ┌──────────┐    │  │  Monitor(集群状态管理)   │  │
    │ RGW/RBD/ │    │  └──────────────────────────┘  │
    │  CephFS  │    └─────────────────────────────────┘
    └──────────┘
    对象/块/文件存储

快速部署 Ceph 集群(测试环境)

# 最快的方式:使用 cephadm(Ceph 官方推荐)
# 需要至少 3 个节点,每节点至少 1 块空白磁盘

# 1. 在首节点安装 cephadm
curl --silent --remote-name --location \
  https://github.com/ceph/ceph/raw/quincy/src/cephadm/cephadm
chmod +x cephadm
./cephadm install

# 2. 引导集群(首节点)
cephadm bootstrap --mon-ip 192.168.1.10

# 3. 添加其他节点
ceph orch host add node2 192.168.1.11
ceph orch host add node3 192.168.1.12

# 4. 部署 OSD(自动发现所有空白磁盘)
ceph orch apply osd --all-available-devices

# 5. 查看集群状态
ceph status
# 期望输出:HEALTH_OK

Ceph 性能调优关键参数

# 创建存储池时设置副本数(生产建议3副本)
ceph osd pool create mypool 128 128
ceph osd pool set mypool size 3

# 针对 SSD 优化 OSD
ceph config set osd osd_journal_size 1024
ceph config set osd bluestore_block_size 322122547200

# 查看性能
ceph osd perf

3. Rook:让 Ceph 在 K8s 里"原生"运行

Rook 是 Kubernetes 的存储编排器,最常见的用法是在 K8s 内部署和管理 Ceph。

3.1 用 Rook 在 K8s 部署 Ceph

# 克隆 Rook 仓库
git clone --single-branch --branch v1.14.0 \
  https://github.com/rook/rook.git
cd rook/deploy/examples

# 部署 Rook Operator
kubectl create -f crds.yaml -f common.yaml -f operator.yaml

# 等待 Operator 就绪
kubectl -n rook-ceph rollout status deploy/rook-ceph-operator

# 部署 Ceph 集群(cluster.yaml 需根据实际环境修改)
kubectl create -f cluster.yaml

# 查看集群状态
kubectl -n rook-ceph get cephcluster
# NAME        DATADIRHOSTPATH   MONCOUNT   AGE   PHASE   MESSAGE   HEALTH
# rook-ceph   /var/lib/rook     3          5m    Ready   Cluster   HEALTH_OK

3.2 创建存储类(StorageClass)

# ceph-storageclass.yaml
apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
  name: replicapool
  namespace: rook-ceph
spec:
  failureDomain: host
  replicated:
    size: 3        # 3副本,容忍1节点故障
---
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
  csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
  csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
  csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner
  csi.storage.k8s.io/controller-expand-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
reclaimPolicy: Delete
allowVolumeExpansion: true
kubectl apply -f ceph-storageclass.yaml

# 验证 StorageClass
kubectl get storageclass rook-ceph-block

3.3 在 Pod 中使用持久化存储

# mysql-with-ceph.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: rook-ceph-block
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "your-password"
        volumeMounts:
        - name: mysql-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-storage
        persistentVolumeClaim:
          claimName: mysql-pvc

4. 云厂商对象存储:最省心的选择

如果你的业务已经在云上,对象存储(COS/OSS/S3)往往是最优解。

4.1 在 K8s 中使用腾讯云 COS(通过 S3 兼容接口)

# 用 Python 访问腾讯云 COS(S3 兼容)
import boto3

# 腾讯云 COS S3 兼容配置
s3 = boto3.client(
    's3',
    endpoint_url='https://cos.ap-guangzhou.myqcloud.com',
    aws_access_key_id='your-secret-id',
    aws_secret_access_key='your-secret-key',
    region_name='ap-guangzhou'
)

# 上传文件
def upload_file(local_path: str, bucket: str, cos_key: str):
    s3.upload_file(local_path, bucket, cos_key)
    print(f"✅ 上传成功: {cos_key}")

# 下载文件
def download_file(bucket: str, cos_key: str, local_path: str):
    s3.download_file(bucket, cos_key, local_path)
    print(f"✅ 下载成功: {local_path}")

# 生成预签名 URL(临时访问链接,有效期1小时)
def get_presigned_url(bucket: str, cos_key: str, expires: int = 3600) -> str:
    url = s3.generate_presigned_url(
        'get_object',
        Params={'Bucket': bucket, 'Key': cos_key},
        ExpiresIn=expires
    )
    return url

4.2 用 CSI 驱动挂载 COS 到 K8s Pod

# 安装腾讯云 COS CSI 驱动
kubectl apply -f https://raw.githubusercontent.com/TencentCloud/kubernetes-csi-tencentcloud/master/deploy/cos/kubernetes/csi-cos.yaml

# 创建 Secret(存储访问密钥)
kubectl create secret generic cos-secret \
  --from-literal=SecretId=your-secret-id \
  --from-literal=SecretKey=your-secret-key
# cos-pv.yaml:将 COS Bucket 挂载为 PV
apiVersion: v1
kind: PersistentVolume
metadata:
  name: cos-pv
spec:
  capacity:
    storage: 100Gi
  accessModes:
    - ReadWriteMany    # 多 Pod 同时读写
  persistentVolumeReclaimPolicy: Retain
  csi:
    driver: com.tencent.cloud.csi.cos
    volumeHandle: cos-pv
    volumeAttributes:
      url: "https://your-bucket.cos.ap-guangzhou.myqcloud.com"
      bucket: "your-bucket"
      region: "ap-guangzhou"
    nodePublishSecretRef:
      name: cos-secret
      namespace: default

5. Longhorn:小团队的最佳起步方案

如果你是中小团队,不想运维 Ceph,Longhorn 是 CNCF 孵化项目中最容易落地的选择。

# 一条命令安装 Longhorn
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.6.0/deploy/longhorn.yaml

# 访问 Longhorn UI(了解集群存储状态)
kubectl -n longhorn-system port-forward svc/longhorn-frontend 8080:80

# 设置为默认 StorageClass
kubectl patch storageclass longhorn -p \
  '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

6. 三方案综合对比

对比维度Ceph(自建)Rook+Ceph(K8s内)云厂商存储Longhorn
部署难度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
运维成本极高
性能上限最高中(受网络影响)
数据安全自主可控自主可控厂商保障自主可控
扩展性PB级PB级无限TB级
适合规模大型企业中大型任意规模小中型
月费用(10TB)硬件成本硬件成本~200元硬件成本

总结:怎么选?

4个维度快速决策

  1. 已在云上 → 直接用云厂商 COS/OSS,省心省事
  2. 私有化+数据敏感+有运维团队 → Rook + Ceph
  3. K8s 新手+快速起步 → Longhorn,以后再迁移不迟
  4. 超大规模+极致性能 → 独立 Ceph 集群(要有专职存储工程师)

踩过最大的坑:把 Ceph 部署在虚拟机上,OSD 用的是 NFS 虚拟磁盘,结果 IOPS 拉满后整个集群降速。Ceph 的 OSD 一定要用物理裸盘或高性能 SSD,这是铁律。


👤 作者简介

一枚在大中原腹地(河南)卖公有云的女/男士,主营腾讯云/阿里云/华为云,曾踩坑无数,现专注AI大模型应用落地。关注公众号「公有云cloud」,围观AI前沿动态~