Skip to main content

在 Fluid 中使用 JuiceFS

Fluid 是一个 Kubernetes 原生的分布式数据集编排和加速引擎,本文介绍如何在 Fluid 中使用 JuiceFS。更多关于 Fluid 使用方式,请参考 Fluid 官方文档

背景介绍

Fluid 使用 CRD 的方式来管理资源,分别提供了如下自定义资源:

  • Dataset:用于描述一组数据集。
  • JuiceFSRuntime:承载 JuiceFS 的运行时组件,为应用提供 Dataset 的访问能力。
  • DataLoad:用于描述数据预热任务。
  • DataMigrate:用于描述数据迁移任务。

安装

Fluid 提供 Helm Chart 的安装方式,如下:

helm repo add fluid https://fluid-cloudnative.github.io/charts
helm repo update
helm install fluid fluid/fluid

运行 JuiceFS

在 Fluid 中运行 JuiceFS 只需要 3 步,创建 Secret、Dataset 和 JuiceFSRuntime,其中 Dataset 和 JuiceFSRuntime 需要同名。

文件系统认证信息

操作之前,请先在 JuiceFS 云服务中创建文件系统。

apiVersion: v1
kind: Secret
metadata:
name: jfs-secret
type: Opaque
stringData:
token: ${JUICEFS_TOKEN}
access-key: ${ACCESS_KEY}
secret-key: ${SECRET_KEY}

创建 Dataset

apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: jfsdemo
spec:
mounts:
- name: <vol-name> # JuiceFS Volume 名称
mountPoint: "juicefs:///"
encryptOptions:
- name: token
valueFrom:
secretKeyRef:
name: jfs-secret
key: token
- name: access-key
valueFrom:
secretKeyRef:
name: jfs-secret
key: access-key
- name: secret-key
valueFrom:
secretKeyRef:
name: jfs-secret
key: secret-key

其中:

  • name:需要与在 JuiceFS 控制台创建的 volume 名一致。
  • mountPoint:指的是 JuiceFS 的子目录,是用户在 JuiceFS 文件系统中存储数据的目录,以 juicefs:// 开头;如 juicefs:///demo 为 JuiceFS 文件系统的 /demo 子目录;如 juicefs:/// 为 JuiceFS 文件系统的根目录。
  • encryptOptions:用于指定 JuiceFS 认证信息,需要与上一步创建的 Secret 中的 key 一致。

创建 JuiceFSRuntime

Fluid 中 Runtime 和 Dataset 是一对一的关系,一个 runtime 只能绑定一个 Dataset,且二者通过同名来绑定。JuiceFSRuntime 的创建示例如下:

apiVersion: data.fluid.io/v1alpha1
kind: JuiceFSRuntime
metadata:
name: jfsdemo # 与 Dataset 同名
spec:
replicas: 1
tieredstore:
levels:
- mediumtype: MEM
path: /dev/shm
quota: 40Gi
low: "0.1"

其中 tieredstore 代表缓存的配置,由于 JuiceFS 目前不支持多级存储,因此只需要配置一个 level 即可。level 中的配置含义如下:

  • path:缓存目录,多盘缓存用 : 分割多个目录;
  • mediumtype:用于指明缓存目录所使用的存储设备类型,取值为 "MEM"、"SSD" 或 "HDD";
  • quota:最大缓存容量;
  • low:缓存目录的最小剩余空间占比,默认 0.2;

JuiceFSRuntime 和 Dataset 创建好后,二者会自动绑定(status.phaseBound),绑定后,Fluid 会创建 JuiceFS 的 worker 组件,其个数为 replicas 指定的值,worker 组件会组成一个 JuiceFS 的分布式缓存集群,如下:

$ kubectl get po |grep jfs
jfsdemo-worker-0 1/1 Running 0 4m2s

企业版(私有部署)

JuiceFS Web 控制台负责着客户端的挂载认证、配置文件下发等工作。而在私有部署环境中,控制台的地址不再是 https://juicefs.com/console,需要在 JuiceFSRuntime 中指定控制台的地址,示例如下:

apiVersion: data.fluid.io/v1alpha1
kind: JuiceFSRuntime
metadata:
name: jfsdemo
spec:
worker:
env:
- name: "BASE_URL"
# 将 <CONSOLE_URL> 替换为私有部署控制台地址,例如 http://console.juicefs.com:8080
value: "<CONSOLE_URL>/static"
fuse:
env:
- name: "BASE_URL"
# 将 <CONSOLE_URL> 替换为私有部署控制台地址,例如 http://console.juicefs.com:8080
value: "<CONSOLE_URL>/static"

使用 Dataset

Dataset 和 JuiceFSRuntime 创建完成,且二者绑定后,Fluid 会创建一个与 Dataset 同名的 PVC,应用就可以通过 PVC 来使用 JuiceFS 了,示例如下:

apiVersion: v1
kind: Pod
metadata:
name: demo-app
spec:
containers:
- name: demo
image: nginx
volumeMounts:
- mountPath: /data
name: demo
volumes:
- name: demo
persistentVolumeClaim:
claimName: jfsdemo

Fluid 会在应用 pod 所在的节点上创建一个运行 JuiceFS 的客户端 pod,称为 FUSE pod,用以为应用提供数据读写的服务,如下:

$ kubectl get po |grep demo
demo-app 1/1 Running 0 31s
jfsdemo-fuse-fx7np 1/1 Running 0 31s
jfsdemo-worker-0 1/1 Running 0 10m

缓存配置

默认情况下,worker pod 和 FUSE pod 的缓存都在 spec.tiredstore.levels 中设置,也可以单独设置 worker 的缓存路径。

apiVersion: data.fluid.io/v1alpha1
kind: JuiceFSRuntime
metadata:
name: jfsdemo
spec:
worker:
options:
"cache-dir": "/mnt/cache1:/mnt/cache2"
"cache-size": "102400"
tieredstore:
levels:
- mediumtype: MEM
path: /dev/shm
quota: 500Mi
low: "0.1"

其中,spec.worker.options 为 worker 的挂载参数,缓存路径以 cache-dir 为 key,以 : 分隔的多个路径,也可以设置 cache-size 表示 worker 的缓存最大容量。

Dataset 的访问模式

Dataset 的默认访问模式为 ReadOnlyMany,也支持 ReadWriteMany,可以通过 spec.accessModes 来修改,示例如下:

apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: demo
spec:
accessModes:
- ReadWriteMany
...

子目录配额设置

在 Dataset 中可以设置访问 JuiceFS 文件系统的子目录,同时可以为子目录设置配额。以下是一个 Dataset 的示例:

apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: jfsdemo
spec:
mounts:
- name: minio
mountPoint: "juicefs:///demo"
options:
quota: "2Gi"

其中,spec.mounts.options.quota 指定 Dataset 子目录的配额,至少为 1Gi。

商业版 4.9.2 以上支持子目录配额设置。设置子目录配额时,需要确保 JuiceFS 的版本满足要求,在 JuiceFSRuntime 中指定 FUSE 的镜像为 juicedata/juicefs-fuse:v1.0.4-4.9.2,具体镜像参考 JuiceFS 镜像仓库

FUSE pod 的配置

FUSE pod 是运行在应用 pod 所在的节点上,并为其提供数据读写服务的组件。

基础配置

对于 FUSE pod 本身的配置,均在 JuiceFSRuntime 中设置;而对于 FUSE pod 中运行的 JuiceFS 客户端的挂载参数则在 Dataset 中设置。

JuiceFSRuntime 的基础配置如下:

apiVersion: data.fluid.io/v1alpha1
kind: JuiceFSRuntime
metadata:
name: jfsdemo
spec:
fuse:
image: registry.cn-hangzhou.aliyuncs.com/juicefs/juicefs-fuse
imageTag: v1.0.0-4.8.0
imagePullPolicy: IfNotPresent
podMetadata:
labels:
juicefs: "fuse"
annotations:
juicefs: "fuse"
networkMode: ContainerNetwork
env:
- name: "GOOGLE_CLOUD_PROJECT"
value: "xxx"
resources:
limits:
cpu: 2
memory: 5Gi
requests:
cpu: 1
memory: 1Gi

其中:

  • spec.fuse.image:指定 FUSE pod 的镜像;
  • spec.fuse.imageTag:指定 FUSE pod 的镜像标签;
  • spec.fuse.imagePullPolicy:指定 FUSE pod 的镜像拉取策略;
  • spec.fuse.podMetadata:指定 FUSE pod 的元数据,包括 labels 和 annotations;
  • spec.fuse.networkMode:指定 FUSE pod 的网络模式,目前支持 HostNetworkContainerNetwork,默认为 HostNetwork
  • spec.fuse.env:指定 FUSE pod 的环境变量;
  • spec.fuse.resources:指定 FUSE pod 的资源限制。

挂载参数设置:

apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: jfsdemo
spec:
mounts:
- name: minio
mountPoint: "juicefs:///demo"
options:
"max-uploads": "20"

Volume 配置

apiVersion: data.fluid.io/v1alpha1
kind: JuiceFSRuntime
metadata:
name: jfsdemo
spec:
fuse:
volumeMounts:
- name: "juicefs-cache"
mountPath: "/var/jfsCache"
volumes:
- name: "juicefs-cache"
hostPath:
path: "/var/jfsCache"
type: DirectoryOrCreate

其中:

  • spec.fuse.volumeMounts:指定 FUSE pod 的 volumeMounts,可以指定多个 volumeMounts,其 name 与 spec.volumes 中的对应;
  • spec.volumes:指定 volumes,可以指定多个 volumes。

调度策略配置

FUSE pod 的调度策略目前只支持 nodeSelector,另外 Fluid 会默认给 FUSE pod 加上 operator: Existstolerations,确保节点的 taint 不会影响到 FUSE pod 的调度。

nodeSelector 示例如下:

apiVersion: data.fluid.io/v1alpha1
kind: JuiceFSRuntime
metadata:
name: jfsdemo
spec:
fuse:
nodeSelector:
fluid.io/dataset: jfsdemo

worker pod 的配置

JuiceFSRuntime 会创建 JuiceFS 的缓存 worker,以 StatefulSet 的形式运行在 Kubernetes 集群中。其作用如下:

  • JuiceFS 的 worker pod 组成分布式缓存集群,为 FUSE pod 提供分布式缓存;
  • JuiceFS worker pod 与 FUSE pod 共享本地缓存,以加速数据访问;
  • 应用被调度时,Fluid 会优先将其调度到有缓存 worker 的节点上。

基础配置

worker 的基础配置如下:

apiVersion: data.fluid.io/v1alpha1
kind: JuiceFSRuntime
metadata:
name: jfsdemo
spec:
replicas: 1
juicefsVersion:
image: registry.cn-hangzhou.aliyuncs.com/juicefs/juicefs-fuse
imageTag: v1.0.0-4.8.0
imagePullPolicy: IfNotPresent
worker:
options:
"attr-cache": "10"
podMetadata:
labels:
juicefs: "worker"
annotations:
juicefs: "worker"
networkMode: ContainerNetwork
env:
- name: "GOOGLE_CLOUD_PROJECT"
value: "xxx"
resources:
limits:
cpu: 2
memory: 5Gi
requests:
cpu: 1
memory: 1Gi

其中:

  • spec.replicas:指定 worker pod 的副本数;
  • spec.juicefsVersion:指定 worker pod 的镜像版本;
  • spec.worker.options:指定 worker 的挂载参数,若此处不额外指定,worker pod 将与 FUSE pod 共用一套挂载参数。具体参数请参考 挂载参数
  • spec.worker.podMetadata:指定 worker pod 的元数据,包括 labels 和 annotations;
  • spec.worker.networkMode:指定 worker pod 的网络模式,目前支持 HostNetworkContainerNetwork,默认为 HostNetwork
  • spec.worker.env:指定 worker pod 的环境变量;
  • spec.worker.resources:指定 worker pod 的资源限制。

Volume 配置

apiVersion: data.fluid.io/v1alpha1
kind: JuiceFSRuntime
metadata:
name: jfsdemo
spec:
worker:
networkMode: ContainerNetwork
volumeMounts:
- name: "juicefs-cache"
mountPath: "/var/jfsCache"
volumes:
- name: "juicefs-cache"
hostPath:
path: "/var/jfsCache"
type: DirectoryOrCreate

其中:

  • spec.worker.volumeMounts:指定 JuiceFS worker 的 volumeMounts,可以指定多个 volumeMounts,其 name 与 spec.volumes 中的对应;
  • spec.volumes:指定 volumes,可以指定多个 volumes。

调度策略配置

worker pod 的调度策略有很多种,其中,nodeSelector 在 JuiceFSRuntime 中配置;tolerationsnodeAffinity 需要在 Dataset 中配置;worker pod 之间默认已经配置了 podAntiAffinity,确保每个 worker pod 运行在不同的节点上,不需要额外配置。

nodeSelector 示例如下:

apiVersion: data.fluid.io/v1alpha1
kind: JuiceFSRuntime
metadata:
name: jfsdemo
spec:
worker:
nodeSelector:
fluid.io/dataset: jfsdemo

tolerationsnodeAffinity 示例如下:

apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: jfsdemo
spec:
tolerations:
- key: "fluid.io/dataset"
operator: "Equal"
value: "jfsdemo"
effect: "NoSchedule"
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: "fluid.io/dataset"
operator: "In"
values:
- "jfsdemo"