一、技术选型

1.为什么不用ceph?

1.1 k8s cephfs (removed)

https://kubernetes.io/docs/concepts/storage/volumes/#cephfs

Kubernetes 1.32 does not include a cephfs volume type.

The cephfs in-tree storage driver was deprecated in the Kubernetes v1.28 release and then removed entirely in the v1.31 release.

1.2 Minio VS Ceph

https://blog.csdn.net/Moolight_shadow/article/details/123204412

只使用对象存储功能,且不做调用开发和二次开发,Minio好用不折腾。
如果有Iaas平台、块存储、文件系统需求,需要做商业化的存储产品、团队处于初期,则Ceph无可比拟。

1.3 JuiceFS VS CephFS

https://juicefs.com/docs/zh/community/comparison/juicefs_vs_cephfs

https://juicefs.com/zh-cn/blog/user-stories/cephfs-vs-juicefs-draco-travel-file-storage

CephFS JuiceFS
文件分块 [1]
元数据事务
强一致性
Kubernetes CSI Driver
Hadoop 兼容
数据压缩 [2]
数据加密 [3]
快照
客户端数据缓存
Hadoop 数据本地性
S3 兼容
配额 目录级配额 目录级配额
开发语言 C++ Go
开源协议 LGPLv2.1 & LGPLv3 Apache License 2.0

2.为什么不用NFS?

https://www.kubesphere.io/zh/docs/v4.1/03-installation-and-upgrade/01-preparations/04-configure-external-persistent-storage/05-configure-nfs/

NFS 与部分应用不兼容(例如 Prometheus),可能会导致容器组创建失败。

3.传统VS现代

https://juicefs.com/zh-cn/product/cloud-service/
传统

VS

现代

二、JuiceFS

1.JuiceFS 简介

JuiceFS 是一款面向云原生设计的高性能分布式文件系统,在 Apache 2.0 开源协议下发布。提供完备的 POSIX 兼容性,可将几乎所有对象存储接入本地作为海量本地磁盘使用,亦可同时在跨平台、跨地区的不同主机上挂载读写。

JuiceFS 采用 「数据」「元数据」 分离存储的架构,从而实现文件系统的分布式设计。文件数据本身会被切分保存在对象存储(例如 Amazon S3),而元数据则可以保存在 Redis、MySQL、TiKV、SQLite 等多种数据库中,你可以根据场景与性能要求进行选择。

JuiceFS 提供了丰富的 API,适用于各种形式数据的管理、分析、归档、备份,可以在不修改代码的前提下无缝对接大数据、机器学习、人工智能等应用平台,为其提供海量、弹性、低价的高性能存储。运维人员不用再为可用性、灾难恢复、监控、扩容等工作烦恼,专注于业务开发,提升研发效率。同时运维细节的简化,对 DevOps 极其友好。

2.核心特性

云原生:通过 Kubernetes CSI 驱动 轻松地在 Kubernetes 中使用 JuiceFS;

POSIX 兼容:像本地文件系统一样使用,无缝对接已有应用,无业务侵入性;
HDFS 兼容:完整兼容 HDFS API,提供更强的元数据性能;
S3 兼容:提供 S3 网关 实现 S3 协议兼容的访问接口;

分布式设计:同一文件系统可在上千台服务器同时挂载,高性能并发读写,共享数据;
强一致性:确认的文件修改会在所有服务器上立即可见,保证强一致性;
强悍性能:毫秒级延迟,近乎无限的吞吐量(取决于对象存储规模),查看性能测试结果;
数据安全:支持传输中加密(encryption in transit)和静态加密(encryption at rest),查看详情;
文件锁:支持 BSD 锁(flock)和 POSIX 锁(fcntl);
数据压缩:支持 LZ4 和 Zstandard 压缩算法,节省存储空间。

3.架构

技术架构 | JuiceFS Document Center
在这里插入图片描述

4.安装

安装 | JuiceFS Document Center

# 默认安装到 /usr/local/bin
curl -sSL https://d.juicefs.com/install | sh -

sudo add-apt-repository ppa:juicefs/ppa
sudo apt-get update
sudo apt-get install juicefs

5.FUSE:挂载

分布式模式 | JuiceFS Document Center

MinIO安装参见之前我的博文:在Linux Debian和k8s上部署MinIO集群部署MinIO Operator:在k8s上多节点多驱动器(热储存) 部分

5.1 创建bucket:k8s-csi

在这里插入图片描述

5.2 创建access-key

在这里插入图片描述

5.3 格式化与挂载

Linux版

juicefs format \
    --storage s3 \
    --bucket http://pve-node5:9000/k8s-csi \
    --access-key CzrsezeekHXSEbsGh4q7 \
    --secret-key qxvUp3Bae9hR8s3gR5XJUc0ZZn5Rx2EwIRnRiK7j \
    redis://:redis_P6B5Pb@192.168.255.254:6379/13 \
    k8s-csi
    
# 开机自动挂载 --update-fstab
# 后台运行 --background 
# 调大缓存提升性能 --cache-size 512000
# 关闭用量上报 --no-usage-report
# samba --enable-xattr
juicefs mount \
--background \
--enable-xattr \
--no-usage-report \
--update-fstab \
redis://:redis_P6B5Pb@192.168.255.254:6379/13 /mnt/k8s-csi

juicefs umount dir

k8s版
找到容器组juicefs-csi-controller执行下面代码

juicefs format \
    --storage s3 \
    --bucket http://@minio-hl.minio.svc.cluster.local:9000/k8s-csi \
    --access-key TVp7KrrpScyAkciC \
    --secret-key BG2ArDOPJ4HJek6HPIFYKjc5ACGnc8L1 \
    redis://:JsMNvJ78ok@redis-master.db.svc.cluster.local:6379/0    \
    k8s-csi

6.CSI: StorageClass-动态配置

https://juicefs.com/docs/zh/csi/getting_started/

6.1 概念

https://kubernetes.io/zh-cn/docs/concepts/storage/persistent-volumes/

持久卷(PersistentVolume,PV) 是集群中的一块存储,可以由管理员事先制备, 或者使用存储类(Storage Class)来动态制备。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样, 也是使用卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。

持久卷申领(PersistentVolumeClaim,PVC) 表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存)。同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以挂载为 ReadWriteOnce、ReadOnlyMany、ReadWriteMany 或 ReadWriteOncePod, 请参阅访问模式)。

6.2 架构

JuiceFS CSI 驱动遵循 CSI 规范,实现了容器编排系统与 JuiceFS 文件系统之间的接口。在 Kubernetes 下,JuiceFS 可以用持久卷(PersistentVolume)的形式提供给 Pod 使用。
在这里插入图片描述

6.3 安装

helm repo add juicefs https://juicedata.github.io/charts/
helm repo update
# 不论是初次安装还是后续的配置变更,都可以运行这一行命令达到效果
helm upgrade --install juicefs-csi-driver juicefs/juicefs-csi-driver -n kube-system

6.4 部署

kubectl apply -f juicefs-app.yaml

Linux版

apiVersion: v1
kind: Secret
metadata:
  name: juicefs-secret
  namespace: default
type: Opaque
stringData:
  name: juicefs-vol              # The JuiceFS file system name
  access-key: CzrsezeekHXSEbsGh4q7       # Object storage credentials
  secret-key: qxvUp3Bae9hR8s3gR5XJUc0ZZn5Rx2EwIRnRiK7j       # Object storage credentials
  # follows are for JuiceFS enterprise
  #token: ${JUICEFS_TOKEN}        # Token used to authenticate against JuiceFS Volume
  # follows are for JuiceFS community
  metaurl: redis://:redis_P6B5Pb@192.168.255.254:6379/13            # Connection URL for metadata engine.
  storage: s3                    # Object storage type, such as s3, gs, oss.
  bucket: k8s-csi               # Bucket URL of object storage.
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: juicefs-sc
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
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: juicefs-pvc
  namespace: default
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 10Pi
  storageClassName: juicefs-sc
---
apiVersion: v1
kind: Pod
metadata:
  name: juicefs-app
  namespace: default
spec:
  containers:
  - args:
    - -c
    - while true; do echo $(date -u) >> /data/out.txt; sleep 5; done
    command:
    - /bin/sh
    image: busybox
    name: app
    volumeMounts:
    - mountPath: /data
      name: juicefs-pv
  volumes:
  - name: juicefs-pv
    persistentVolumeClaim:
      claimName: juicefs-pvc

k8s版

apiVersion: v1
kind: Secret
metadata:
  name: juicefs-secret
  namespace: default
type: Opaque
stringData:
  name: juicefs-vol              # The JuiceFS file system name
  access-key: TVp7KrrpScyAkciC       # Object storage credentials
  secret-key: BG2ArDOPJ4HJek6HPIFYKjc5ACGnc8L1       # Object storage credentials
  # follows are for JuiceFS enterprise
  #token: ${JUICEFS_TOKEN}        # Token used to authenticate against JuiceFS Volume
  # follows are for JuiceFS community
  metaurl: redis://:JsMNvJ78ok@redis-master.db.svc.cluster.local:6379/0            # Connection URL for metadata engine.
  storage: s3                    # Object storage type, such as s3, gs, oss.
  bucket: k8s-csi               # Bucket URL of object storage.
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: juicefs-sc
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
  # https://juicefs.com/docs/zh/csi/guide/configurations/#using-path-pattern
  pathPattern: "${.pvc.namespace}-${.pvc.name}"
  # https://juicefs.com/docs/zh/csi/guide/configurations/#pv-expansion
  csi.storage.k8s.io/controller-expand-secret-name: juicefs-secret   # 与 provisioner-secret-name 相同即可
  csi.storage.k8s.io/controller-expand-secret-namespace: default     # 与 provisioner-secret-namespace 相同即可
allowVolumeExpansion: true         # 表示支持扩容
# https://juicefs.com/docs/zh/csi/guide/cache/#%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AE
#juicefs/clean-cache: "true"
reclaimPolicy: Retain

# ---
# apiVersion: v1
# kind: PersistentVolumeClaim
# metadata:
#   name: juicefs-pvc
#   namespace: default
# spec:
#   accessModes:
#   - ReadWriteMany
#   resources:
#     requests:
#       storage: 10Pi
#   storageClassName: juicefs-sc
# ---
# apiVersion: v1
# kind: Pod
# metadata:
#   name: juicefs-app
#   namespace: default
# spec:
#   containers:
#   - args:
#     - -c
#     - while true; do echo $(date -u) >> /data/out.txt; sleep 5; done
#     command:
#     - /bin/sh
#     image: busybox
#     name: app
#     volumeMounts:
#     - mountPath: /data
#       name: juicefs-pv
#   volumes:
#   - name: juicefs-pv
#     persistentVolumeClaim:
#       claimName: juicefs-pvc

6.5 KubeSphere验证

存储类StorageClass: juicefs-sc
在这里插入图片描述

持久卷声明PersistentVolumeClaim: juicefs-pvc
在这里插入图片描述
持久卷PersistentVolume: juicefs-pv
在这里插入图片描述

6.6 设置默认存储类

https://www.kubesphere.io/zh/docs/v4.1/07-cluster-management/08-storage/02-storage-classes/04-set-a-default-storage-class/
在这里插入图片描述

6.7 测试

进入终端
在这里插入图片描述
查看是否有文件系统:JuiceFS:k8s-csi
在这里插入图片描述
pod内查看
在这里插入图片描述
挂载后,找到pvc文件夹查看
在这里插入图片描述

7.备份与恢复

元数据备份和恢复 | JuiceFS Document Center

juicefs load redis://:redis_P6B5Pb@192.168.255.254:6379/13 

juicefs config --secret-key qxvUp3Bae9hR8s3gR5XJUc0ZZn5Rx2EwIRnRiK7j redis://:redis_P6B5Pb@192.168.255.254:6379/13

8.预热

对于LLM和大数据集非常友好
https://juicefs.com/docs/zh/community/guide/cache/#client-read-cache

https://juicefs.com/docs/zh/community/command_reference/#warmup

juicefs warmup [command options] [PATH ...]

9.元数据基准测试

https://juicefs.com/docs/zh/cloud/benchmark/metadata_engines_benchmark/

官方基准测试
在这里插入图片描述
HDD 单服务 5盘
在这里插入图片描述
在这里插入图片描述

SSD 四服务 单固态
在这里插入图片描述

三、相关问题

1.默认的配置资源请求和约束,快速吃掉了我的CPU和Memory资源

JuiceFS Mount Pod 的 requests 默认为 1 CPU1GiB Memory,limits 默认为 5 CPU 和 5GiB Memory
实际场景下用量极低,比如 Mount Pod 只使用了 0.1 CPU、100MiB Memory,避免过大的 requests 造成资源闲置,甚至导致容器拒绝启动,或者抢占其他应用容器(Preemption)。对于 limits,你也可以根据实际监控数据,调整为一个大于 requests 的数值,允许突发瞬时的资源占用上升;
values.yaml 如下:

globalConfig:
  mountPodPatch:
    # https://juicefs.com/docs/zh/csi/guide/resource-optimization/#resources-configmap
    - resources:
        requests:
          cpu: 1m
          memory: 4Mi

更新配置:

helm upgrade --install juicefs-csi-driver juicefs/juicefs-csi-driver -n kube-system -f values.yaml

2.默认的缓存路径,快速吃掉了我的磁盘空间

默认情况下,CSI 驱动的缓存路径就是标准的 JuiceFS 客户端缓存路径 /var/jfsCache,考虑到 Kubernetes 节点往往采用单独的数据盘作为缓存盘,因此一定要注意正确设置缓存路径,否则使用根分区的 /var/jfsCache 目录来缓存数据,容易耗尽系统盘空间。
新增Hard Disk,一定不要选Backup,否则虚拟机备份时会很大。
在这里插入图片描述

# 格式化
lsblk -f
mkfs.ext4  /dev/sdb

# 临时挂载
mkdir /jfsCache
mount /dev/sdb /jfsCache

# 永久挂载
nano /etc/fstab
/dev/disk/by-uuid/2fdee3c1-f104-498d-8939-32cd513ab422 /jfsCache ext4 defaults 0 1

values.yaml 如下:

globalConfig:
  mountPodPatch:
    # https://juicefs.com/docs/zh/csi/guide/resource-optimization/#resources-configmap
    - resources:
        requests:
          cpu: 1m
          memory: 4Mi
    # https://juicefs.com/docs/zh/csi/guide/cache#cache-settings
    - mountOptions:
      - cache-dir=/jfsCache
      - cache-size=100G

更新配置:

helm upgrade --install juicefs-csi-driver juicefs/juicefs-csi-driver -n kube-system -f values.yaml

3.关闭用量上报

JuiceFS 默认会收集并上报 「匿名」 的使用数据。这些数据仅仅包含核心指标(如版本号、文件系统大小),不会包含任何用户信息或者敏感数据。你可以查看这里检查相关代码。

这些数据帮助我们理解社区如何使用这个项目。

values.yaml 如下:

globalConfig:
  mountPodPatch:
    # https://juicefs.com/docs/zh/csi/guide/resource-optimization/#resources-configmap
    - resources:
        requests:
          cpu: 1m
          memory: 4Mi
    # https://juicefs.com/docs/zh/csi/guide/cache#cache-settings
    - mountOptions:
      - cache-dir=/jfsCache
      - cache-size=100G
      # https://juicefs.com/docs/zh/community/community/usage_tracking/
      - no-usage-report

更新配置:

helm upgrade --install juicefs-csi-driver juicefs/juicefs-csi-driver -n kube-system -f values.yaml

4.StorageClass若干最佳实践

4.1 配置更加易读的 PV 目录名称

在「动态配置」方式下,CSI 驱动在 JuiceFS 创建的子目录名称形如 pvc-234bb954-dfa3-4251-9ebe-8727fb3ad6fd,如果有众多应用同时使用 CSI 驱动,更会造成 JuiceFS 文件系统中创建大量此类 PV 目录,让人难以辨别:

$ ls /jfs
pvc-76d2afa7-d1c1-419a-b971-b99da0b2b89c  pvc-a8c59d73-0c27-48ac-ba2c-53de34d31944  pvc-d88a5e2e-7597-467a-bf42-0ed6fa783a6b

JuiceFS CSI 驱动支持通过 pathPattern 这个配置来定义其不同 PV 的子目录格式,让目录名称更容易阅读、查找:

$ ls /jfs
default-dummy-juicefs-pvc  default-example-juicefs-pvc ...

4.2 PV 扩容

在 JuiceFS CSI 驱动 0.21.0 及以上版本,支持动态扩展 PersistentVolume 的容量(仅支持动态配置)。需要在 StorageClass 中指定 allowVolumeExpansion: true,同时指定扩容时所需使用的 Secret,主要提供文件系统的认证信息。

4.3 清理缓存

在大规模场景下,已建立的缓存是宝贵的,因此 JuiceFS CSI 驱动默认并不会在 Mount Pod 退出时清理缓存。如果这对你的场景不适用,可以对 PV 进行配置,令 Mount Pod 退出时直接清理自己的缓存。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: juicefs-sc
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
  # https://juicefs.com/docs/zh/csi/guide/configurations/#using-path-pattern
  pathPattern: "${.pvc.namespace}-${.pvc.name}"
  # https://juicefs.com/docs/zh/csi/guide/configurations/#pv-expansion
  csi.storage.k8s.io/controller-expand-secret-name: juicefs-secret   # 与 provisioner-secret-name 相同即可
  csi.storage.k8s.io/controller-expand-secret-namespace: default     # 与 provisioner-secret-namespace 相同即可
allowVolumeExpansion: true         # 表示支持扩容
# https://juicefs.com/docs/zh/csi/guide/cache/#%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AE
juicefs/clean-cache: "true"
reclaimPolicy: Retain
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐