如何在Kubernetes集群中玩Fluid + JuiceFS
云之盛 Atlas 团队于 2021 年初开始接触和跟进 JuiceFS 存储,并在早期积累了丰富的 Fluid 使用经验。近期,云语音团队与 jucedata 团队联合开发了 Fluid jucedas 加速引擎,让用户可以在 Kubernetes 环境中更好地使用 jucedas 缓存管理能力。本文讲解如何在 Kubernetes 集群中玩 Fluid + JuiceFS。 背景介绍 流体简介
云之盛 Atlas 团队于 2021 年初开始接触和跟进 JuiceFS 存储,并在早期积累了丰富的 Fluid 使用经验。近期,云语音团队与 jucedata 团队联合开发了 Fluid jucedas 加速引擎,让用户可以在 Kubernetes 环境中更好地使用 jucedas 缓存管理能力。本文讲解如何在 Kubernetes 集群中玩 Fluid + JuiceFS。
背景介绍
流体简介
CNCF Fluid 是一个开源的 Kubernetes 原生分布式数据集编排和加速引擎,主要服务于云原生场景下的数据密集型应用,如大数据应用和 AI 应用。关于 Fluid 的更多信息,可以参考地址。
Fluid 不是全存储加速和管理,而是应用程序使用的数据集加速和管理。 Fluid 提供了一种更加云原生的方式来管理数据集。它通过缓存加速引擎将底层存储系统的数据缓存在计算节点的内存或硬盘中,解决了由于数据传输带宽的限制以及底层存储带宽和IOPS的限制导致IO效率低的问题计算和存储架构分离的能力。 Fluid 提供缓存数据调度能力。缓存被合并到 Kubernetes 扩展资源中。 Kubernetes 在调度任务时可以参考缓存进行调度策略分配。
Fluid 有两个重要的概念:Dataset 和 Runtime
-
数据集:数据集是一组逻辑相关的数据。相同的操作引擎将使用一致的文件特征。
-
Runtime:执行引擎接口,实现数据集安全、版本管理和数据加速等能力,定义了一系列生命周期方法。
Fluid 的 Runtime 定义了标准化的接口。 Cache Runtime Engine 可以与多种缓存引擎对接,为用户提供更灵活的选择。用户可以根据不同的场景和需求,充分利用缓存引擎来加速相应的场景应用。
JuiceFS 简介
JuiceFS 是专为云环境设计的高性能开源分布式文件系统。它与 POSIX、HDFS 和 S3 接口完全兼容。适用于大数据、AI模型训练、Kubernetes共享存储、海量数据归档管理等场景。
使用 JuiceFS 存储数据时,数据本身会被持久化在对象存储中(例如 Amazon S3),数据对应的元数据可以根据需要持久化在 Redis、MySQL、TiKV 等数据库引擎中。情景。 JuiceFS 客户端具有数据缓存能力。通过 JuiceFS 客户端读取数据时,这些数据会被智能缓存到应用程序配置的本地缓存路径(内存或磁盘),元数据也会缓存到客户端节点的本地内存中。
对于AI模型训练场景,第一个epoch完成后,后续计算可以直接从缓存中获取训练数据,大大提高了训练效率。 JuiceFS 还具有预读和并发数据读取的能力。在AI训练场景下,可以保证每个mini batch的生成效率,提前准备好数据。数据预热可以将公有云上的数据提前更改到本地节点。对于AI训练场景,可以保证申请GPU资源后有预热数据可供操作,为宝贵的GPU使用节省时间。
为什么要使用 JuiceFSRuntime
云智升Atlas超算平台作为底层基础设施,支持公司在AI各领域的模型训练和推理服务。云智升早就开始布局和打造业界领先的GPU/CPU异构Atlas计算平台和分布式文件存储系统。计算集群可以为人工智能计算提供高性能计算和海量数据存储和访问能力。云之盛 Atlas 团队于 2021 年初开始接触和跟进 JuiceFS 存储,并进行了一系列 POC 测试,以满足我们当前在数据可靠性和业务场景适配方面的需求。
在训练场景中,我们充分利用 JuiceFS 客户端的缓存能力来加速 AI 模型训练,但是在使用过程中发现了一些问题:
-
训练Pod通过hostpath挂载。 JuiceFS 客户端需要挂载在每个计算节点上。安装需要管理员操作。安装参数固定,不够灵活。
-
用户无法管理计算节点客户端缓存,无法手动清理和扩容缓存。
-
缓存数据集不能像Kubernetes自定义资源一样被Kubernetes调度。
由于我们在生产环境中积累了一定的 Fluid 使用经验,因此我们与 jucedata 团队合作设计开发了 JuiceFSRuntime,将 Fluid 的数据整理和管理能力与 JuiceFS 的缓存能力相结合。
什么是 Fluid + JuiceFS (JuiceFSRuntime)
JuiceFSRuntime 是 Fluid 定制的一个 Runtime,可以在其中指定 JuiceFS 的 worker、fuse image 和对应的缓存参数。构建方式与 Fluid 的其他运行时一致,即通过 CRD 构建。 JuiceFSRuntime Controller 监控 JuiceFSRuntime 资源,实现缓存 Pod 管理。
JuiceFSRuntime 支持 nodeAffinity 调度,选择合适的缓存节点,支持 Fuse pod 的懒启动,支持用户通过 POSIX 接口访问数据。目前只支持一个挂载点。
帧构成如上图所示。 JuiceFSRuntime 由 Fuse pod 和 Worker pod 组成。 Worker Pod主要实现缓存管理,比如Runtime退出时的缓存清理; Fuse pod 主要负责 JuiceFS 客户端的参数设置和挂载。
如何使用juicefsruntime
下面我们来看看如何使用 JuiceFSRuntime 进行缓存加速。
提前准备
要使用 juicefs 运行时,首先需要准备元数据引擎和对象存储。
构建元数据引擎
用户可以在云计算平台上轻松购买各种配置的云Redis数据库。如果用于评估和测试,可以使用 Docker 在服务器上快速运行一个 Redis 数据库实例:
$ sudo docker run -d --name redis \
-v redis-数据:/数据\
-p 6379:6379 \
--restart 除非停止\
redis redis-server --appendonly 是
准备对象存储
和 Redis 数据库一样,几乎所有的公有云计算平台都提供对象存储服务。由于 JuiceFS 在几乎所有主流平台上都支持对象存储服务,用户可以根据自己的情况进行部署。
这是 Dokcer 运行的 minio 实例,应该用于评估测试:
$$ sudo docker run -d --name minio\
-p 9000:9000 \
-p 9900:9900 \
-v $PWD/迷你数据:/数据\
--restart 除非停止\
minio/minio 服务器 /data --console-address ":9900"
对象存储的初始 Access Key 和 Secret Key 是 minioadmin。
下载安装 Fluid
根据文件安装Fluid,在Fluid的安装图values.yaml中设置runtime.juicefs.enable为true,安装Fluid。确保 Fluid 集群正常运行:
kubectl 获取 po -n 流体系统
NAME READY STATUS RESTARTS AGE
csi-nodeplugin-fluid-ctc4l 2/2 运行 0 113s
csi-nodeplugin-fluid-k7cqt 2/2 运行 0 113s
csi-nodeplugin-fluid-x9dfd 2/2 运行 0 113s
数据集控制器 57ddd56b54-9vd86 1/1 运行 0 113s
流体-webhook-84467465f8-t65mr 1/1 运行 0 113s
juicefsruntime-controller-56df96b75f-qzq8x 1/1 运行 0 113s
确保 juicefsruntime 控制器、数据集控制器、fluid webhook 的 pod 和几个 CSI nodeplug pod 运行正常。
创建数据集
在使用 JuiceFS 之前,需要提供元数据服务(如 redis)和对象存储服务(如 minio)的参数,并创建对应的 secret:
kubectl 创建秘密通用 jfs-secret \
--from-literalu003dmetaurlu003dredis://$IP:6379 / 1 \ #redis的IP地址为redis所在节点的IP地址
--from-literalu003daccess-keyu003dminioadmin \ # 对象存储 ak
--from-literalu003dsecret-keyu003dminioadmin #对象存储sk
创建数据集 yaml 文件
猫<<EOF >dataset.yaml
api版本:data.fluid.io/v1alpha1
种类:数据集
元数据:
名称:jfsdemo
规格:
坐骑:
- 在房子里:人群
mountPoint: "juicefs:///demo"
选项:
桶:“<桶>”
商店:“迷你”
加密选项:
- 名称:metaurl
值来自:
秘钥参考:
名称:jfs-secret
键:元网址
- 名称:访问密钥
值来自:
秘钥参考:
名称:jfs-secret
键:访问键
- 名称:密钥
值来自:
秘钥参考:
名称:jfs-secret
密钥:密钥
EOF
因为juicefs采用本地缓存,对应的Dataset只支持一次挂载,而juicefs没有UFS,可以在挂载点中指定要挂载的子目录(“juicefs://”为根路径),会挂载到容器作为根目录。
创建数据集并查看数据集状态
$ kubectl 创建-f dataset.yaml
dataset.data.fluid.io/jfsdemo 创建
$ kubectl 获取数据集 jfsdemo
名称 UFS 总大小 缓存 缓存 容量 缓存 百分比 阶段 年龄
jfsdemo NotBound 44s
如上图,status中的phase属性值为NotBound,表示Dataset资源对象还没有绑定到任何JuiceFSRuntime资源对象。接下来,我们将创建一个 JuiceFSRuntime 资源对象。
创建 JuiceFSRuntime
为 JuiceFSRuntime 创建一个 yaml 文件
$ cat<<EOF >runtime.yaml
api版本:data.fluid.io/v1alpha1
种类:JuiceFSRuntime
元数据:
名称:jfsdemo
规格:
复制品:1
分层商店:
级别:
- 中型:SSD
路径:/缓存
quota: 40960 # JuiceFS中quota的最小单位是MiB,所以这里是40GiB
低:“0.1”
EOF
创建并查看 JuiceFSRuntime
$$ kubectl create -f runtime.yaml
juicefsruntime.data.fluid.io/jfsdemo 创建
$ kubectl 获取 juicefsruntime
NAME WORKER PHASE PHASE PHASE PHASE AGE
jfsdemo 就绪 就绪 72s
查看 JuiceFS 的相关组件 Pod 的状态
$$ kubectl get po |grep jfs
jfsdemo-worker-mjplw 1/1 运行 0 4m2s
JuiceFSRuntime 没有 master 组件,而 Fuse 组件实现了延迟启动,会在使用 pod 时创建。
创建缓存加速作业
创建需要加速的应用程序。 Pod 使用上面创建的 Dataset 来指定一个同名的 PVC
$ 猫<<EOF >sample.yaml
api版本:v1
种类:豆荚
元数据:
名称:演示应用
规格:
容器:
- 名称:演示
图片:nginx
体积安装:
- 挂载路径:/数据
名称:演示
卷:
- 名称:演示
持久量声明:
声明名称:jfsdemo
EOF
创建 Pod
$ kubectl 创建 -f 示例.yaml
pod/demo-app 创建
查看 pod 状态
$cubectl get po |grep 演示
演示应用程序 1/1 运行 0 31s
jfsdemo-fuse-fx7np 1/1 运行 0 31s
jfsdemo-worker-mjplw 1/1 运行 0 10m
可以看到pod创建成功,JuiceFS的Fuse组件启动成功。
进入 Pod 执行 df -hT 查看缓存目录是否挂载:
$ kubectl exec -it demo-app bash -- df -h
Filesystem Size Used Avail Use% Mounted on
叠加 20G 14G 5.9G 71% /
tmpfs 64M 0 64M 0% /dev
tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
JuiceFus:minio 1.0p 7.9m 1.0p 1% /data
可以看到缓存目录已经挂载成功。
接下来,让我们在 demo app pod 中测试 write 函数:
$ kubectl exec -it demo-app bash
[root@demo-app /]# df
Filesystem 1K-blocks Used Available Use% Mounted on
叠加 20751360 14585944 6165416 71% /
tmpfs 65536 0 65536 0% /dev
tmpfs 3995028 0 3995028 0% /sys/fs/cgroup
JuiceFS:minio 1099511627776 8000 1099511619776 1% /data
/dev/sda2 20751360 14585944 6165416 71% /etc/hosts
shm 65536 0 65536 0% /dev/shm
tmpfs 3995028 12 3995016 1% /run/secrets/kubernetes.io/serviceaccount
tmpfs 3995028 0 3995028 0% /proc/acpi
tmpfs 3995028 0 3995028 0% /proc/scsi
tmpfs 3995028 0 3995028 0% /sys/固件
[root@demo-app /]#
[root@demo-app /]# cd /data
[root@demo-app data]# echo "你好流体" > hello.txt
[root@demo-app 数据]# cat hello.txt
你好流体
最后,我们来看看缓存功能。在demo app pod的mount目录/data下创建一个1G的文件,然后cp出来:
$ kubectl exec -it 演示应用程序 bash
root@demo-app:~# dd ifu003d/dev/zero ofu003d/data/test.txt countu003d1024 bsu003d1M
1024+0 条记录
1024+0 条记录
已复制 1073741824 字节(1.1 GB,1.0 GiB),6.55431 秒,164 MB/秒
root@demo-app:~# time cp /data/test.txt ./test.txt
真正的 0m5.014s
用户 0m0.003s
系统 0m0.702s
root@demo-app:~# time cp /data/test.txt ./test.txt
真实0m0.602s
用户 0m0.004s
系统 0m0.584s
从执行结果来看,第一个cp用了5s,第二个cp只用了0.6s,因为缓存已经存在。 JuiceFS 提供的强大缓存能力使得只要一个文件被访问一次,该文件就会被缓存在本地缓存路径中,后续所有的重复访问都会直接从 JuiceFS 获取数据。
跟进计划
目前 JuiceFS Runtime 不支持很多功能,未来我们会继续完善,比如在 Non Root 模式下运行的 Fuse Pod 和 Dataload 数据预热功能。
推荐阅读:知乎 x JuiceFS:使用 JuiceFS 启动和加速 Flink 容器
如果对你有帮助,请关注我们Juicedata/JuiceFS哟! (0ᴗ0✿)
更多推荐
所有评论(0)