Featured image of post MinIO / JuiceFS / OpenEBS:K8s 对象存储与本地 PV 全方案

MinIO / JuiceFS / OpenEBS:K8s 对象存储与本地 PV 全方案

MinIO S3 CSI 接入、JuiceFS 元数据引擎架构、OpenEBS iSCSI 本地 PV 部署

三种 K8s 存储的"非主流"路线

主流 K8s 存储是 NFS + Ceph,但有些场景它们都力不从心:

  • S3 兼容对象存储(备份、日志、镜像)→ MinIO
  • 海量小文件 + 多云(AI 训练、媒资)→ JuiceFS
  • 本地磁盘池化(DB 性能、StatefulSet)→ OpenEBS

本文一次讲清这三套方案。

适用版本:MinIO 2024.x / JuiceFS 1.x / OpenEBS 3.4


1. MinIO 作为 PV 存储

1.1 思路

通过 k8s-csi-s3 这个 CSI 驱动,让 S3(MinIO)作为 K8s 的 PV 后端——申请 PVC 时自动创建 S3 bucket,Pod 内能像本地目录一样访问。

警告:源码明确写"不建议生产环境使用"。原因是 S3 不是真正的文件系统,POSIX 兼容有限(特别是 append 写)。但作为 静态资源 / 备份 场景的 PV 非常合适。

1.2 要求

  • Kubernetes 1.16+(CSI v1.0.0)
  • kubelet 允许特权容器
  • Docker daemon MountFlags=shared(新增分区无需重启 Docker)
1
2
3
4
5
6
# /etc/systemd/system/docker.service
[Service]
MountFlags=shared
Type=notify
ExecStart=/usr/local/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
...

1.3 创建 Secret

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
apiVersion: v1
kind: Secret
metadata:
  name: csi-driver-s3-secret
  namespace: kube-system
stringData:
  accessKeyID: "{{MINIO_ACCESS_KEY}}"
  secretAccessKey: "{{MINIO_SECRET_KEY}}"
  endpoint: https://<minio-endpoint>
  region: ""

实际访问密钥用占位符 {{MINIO_ACCESS_KEY}} {{MINIO_SECRET_KEY}} 替代。

1.4 安装 CSI 驱动

按 yandex-cloud/k8s-csi-s3 仓库的 provisioner.yaml / attacher.yaml / csi-driver-s3.yaml / psp.yaml 部署。

1.5 mounter 选择

驱动支持 4 种 mount 工具:

mounter兼容性性能适用
rclone几乎完全 POSIX通用
s3fs较大子集通用,不支持 append
goofys最高只读/大批量,不支持 append
s3backer实验性-块设备,但卷损坏风险大
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: csi-driver-s3
provisioner: s3.csi.metal-stack.io
parameters:
  mounter: s3fs
  csi.storage.k8s.io/provisioner-secret-name: csi-driver-s3-secret
  csi.storage.k8s.io/provisioner-secret-namespace: kube-system
  csi.storage.k8s.io/controller-publish-secret-name: csi-driver-s3-secret
  csi.storage.k8s.io/controller-publish-secret-namespace: kube-system
  csi.storage.k8s.io/node-stage-secret-name: csi-driver-s3-secret
  csi.storage.k8s.io/node-stage-secret-namespace: kube-system
  csi.storage.k8s.io/node-publish-secret-name: csi-driver-s3-secret
  csi.storage.k8s.io/node-publish-secret-namespace: kube-system

1.6 使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: csi-s3-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: csi-s3
---
apiVersion: v1
kind: Pod
metadata:
  name: csi-s3-test-nginx
spec:
  containers:
    - name: csi-s3-test-nginx
      image: nginx
      volumeMounts:
        - mountPath: /var/lib/www/html
          name: webroot
  volumes:
    - name: webroot
      persistentVolumeClaim:
        claimName: csi-s3-pvc
        readOnly: false
1
2
3
4
5
kubectl exec -it csi-s3-test-nginx -- bash
cd /var/lib/www/html/
touch 2024-12-15.txt
ls
# 2024-12-15.txt

MinIO 上能看到自动创建的 bucket 里有这个文件。


2. JuiceFS 架构

2.1 三大组件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
┌─────────────────────────────────────────────────────────┐
│                    JuiceFS 文件系统                      │
│                                                         │
│  ┌────────────┐  ┌────────────┐  ┌──────────────────┐  │
│  │  JuiceFS   │  │   数据存储  │  │    元数据引擎     │  │
│  │  Client    │  │  (对象存储) │  │ (Redis/TiKV/MySQL│  │
│  │  (FUSE)    │  │  S3/MinIO  │  │  /PostgreSQL/    │  │
│  │            │  │  Ceph/OSS  │  │  SQLite)         │  │
│  └─────┬──────┘  └─────┬──────┘  └────────┬─────────┘  │
│        │               │                  │             │
│        └───────────────┴──────────────────┘             │
│                    POSIX 兼容挂载                        │
└─────────────────────────────────────────────────────────┘
  • Client:所有文件读写都在客户端,通过 FUSE 暴露 POSIX 接口
  • 数据存储:文件切分上传到 S3/MinIO/Ceph
  • 元数据引擎:文件名、权限、目录树、文件锁、引用计数等

2.2 5 种接入方式

方式适用场景
FUSE通用,Linux 服务器当本地盘用
Hadoop Java SDK替代 HDFS
Kubernetes CSIK8s 集群直接挂载
S3 网关用 AWS CLI / s3cmd 访问 JuiceFS
WebDAVHTTP 协议

2.3 K8s 部署

JuiceFS 官方 CSI 文档:https://juicefs.com/docs/zh/community/getting-started/for_distributed

1
2
helm repo add juicefs https://juicedata.github.io/charts
helm install juicefs juicefs/juicefs-csi-driver -n juicefs --create-namespace

创建 Secret 提供元数据引擎与对象存储凭据:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
apiVersion: v1
kind: Secret
metadata:
  name: juicefs-secret
type: Opaque
stringData:
  name: <filesystem-name>
  metaurl: redis://:<redis-password>@<redis-host>:6379/1
  bucket: http://<minio-host>:9000/<bucket>
  access-key: {{MINIO_ACCESS_KEY}}
  secret-key: {{MINIO_SECRET_KEY}}
  storage-class: STANDARD
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: juicefs
provisioner: csi.juicefs.com
parameters:
  csi.storage.k8s.io/provisioner-secret-name: juicefs-secret
  csi.storage.k8s.io/provisioner-secret-namespace: default
  csi.storage.k8s.io/node-publish-secret-name: juicefs-secret
  csi.storage.k8s.io/node-publish-secret-namespace: default
reclaimPolicy: Retain

2.4 适用场景

  • AI 训练数据集(海量小文件 + POSIX)
  • 媒资管理(图片、视频)
  • 跨云数据共享

3. OpenEBS 本地 PV

3.1 简介

传统 K8s LocalPV 受限于"单节点单盘",OpenEBS 通过 iSCSI 协议把"工作节点本地盘"池化:

  • 本地卷(LocalPV):单节点本地盘,性能最高,DB 推荐
  • 复制卷(cStor):跨节点复制,有冗余(3 副本)

3.2 内核要求

OpenEBS 走 iSCSI,所有节点装客户端:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# CentOS
yum install iscsi-initiator-utils -y

# Ubuntu
apt install -y open-iscsi

# 启动
systemctl enable --now iscsid
systemctl start iscsid.service

# 可选:开启 nvme_tcp
modprobe iscsi_tcp
echo iscsi_tcp >/etc/modules-load.d/iscsi-tcp.conf
echo "nvme_tcp" | sudo tee /etc/modules-load.d/openebs.conf

3.3 部署 Operator

1
2
3
4
5
6
7
8
# OpenEBS 官方源
helm repo add openebs https://openebs.github.io/openebs
helm repo update

helm install openebs \
  --namespace openebs \
  openebs/openebs \
  --create-namespace

或者 yaml 方式:

1
kubectl apply -f https://openebs.github.io/charts/openebs-operator.yaml

3.4 默认存储路径

1
2
- name: BasePath
  value: "/var/openebs/local/"

OpenEBS 在每个节点上 /var/openebs/local/ 下创建 PV。

3.5 使用

OpenEBS 装好后自动创建几个 StorageClass:

1
2
3
4
5
kubectl get sc
# openebs-hostpath           默认
# openebs-device
# openebs-jiva-csi-default
# openebs-zfspv

直接引用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  storageClassName: openebs-hostpath
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

3.6 备份

OpenEBS 推荐用 Velero 做备份,原理是 K8s 资源 + PV 数据快照到对象存储。

1
2
3
4
5
6
velero install \
  --provider aws \
  --bucket <bucket-name> \
  --secret-file ./credentials-velero \
  --backup-location-config region=minio \
  --use-restic

4. 三种方案对比

方案类型性能容量上限多 Pod 共享适用
MinIO CSI对象中(小文件慢)无限否(RWO)静态资源、备份
JuiceFS分布式文件中-高无限是(RWX)AI 数据、媒资
OpenEBS LocalPV本地盘最高单机DB、StatefulSet
OpenEBS cStor分布式块通用数据库

5. 排错速查

5.1 MinIO CSI Pod 一直 Pending

通常是 RBAC / ServiceAccount 权限问题:

1
2
kubectl describe pod csi-provisioner-s3 -n kube-system
# 查 Events

5.2 JuiceFS 挂载失败

  • 元数据引擎(Redis/MySQL)网络可达?
  • 对象存储 endpoint 正确?
  • Secret 里的 access-key / secret-key 权限够?

5.3 OpenEBS Node Disk Manager 没起来

1
2
kubectl get pods -n openebs
# openebs-ndm DaemonSet 没起 = iscsi 没装

5.4 OpenEBS PVC 一直 Pending

1
2
3
kubectl describe pvc my-pvc
# 找"没有可用节点满足 volume node affinity"
# 解决:调度到打了 openebs.io/localpv 标签的节点

6. 小结

K8s 存储选型不是"一刀切":

  1. MinIO CSI 解决"对象存储当 PV 用"的备份场景
  2. JuiceFS 是"国内开源 + 兼容 S3 + POSIX"的分布式文件
  3. OpenEBS 把"工作节点本地盘"统一管理,性能和 Ceph RBD 不相上下

下一步:K8s PVC 备份恢复:CSI Snapshot / Velero / rsync 三方案

使用 Hugo 构建
主题 StackJimmy 设计