1. Fluid 简介
下面是来源于 https://github.com/fluid-cloudnative/fluid 的 Fluid 的架构图:
Fluid 抽象了两个概念:
- Dataset,数据集合,用户视角的抽象
- Runtime,数据存储、加速等真实服务的抽象
Fluid 主要解决了传统缓存系统在 Kubernetes 上使用的问题:
- 通过 CRD 对数据集合 Dataset 进行描述,提供生命周期管理
- 依赖于 Runtime 后端,通过 PVC 提供给 Kubernetes 集群应用本地化的分布式缓存服务
使用 Fluid 时的工作流程:
- 定义 Dataset,设置好数据的访问凭证、存储位置、读写模式等
- 定义 Runtime,runtime controller 对同名的 Dataset 和 Runtime 进行自动绑定 AddOwner;接着创建 worker 配置 Runtime 相关的资源;创建
${NAMESPACE}-
前缀的 PV 和同名的 PVC
- 当有 Pod 挂载 PVC 时,会先在节点上创建一个 fuse pod 并将
/runtime-mnt/juicefs/xxx
目录挂载到主机上,然后 Fluid 的 CSI Controller 将该目录挂载到 Pod 中。
Dataset 和 Runtime 的生命周期在 Fluid 的代码仓库有描述,参考 https://github.com/fluid-cloudnative/fluid/blob/master/docs/zh/dev/runtime_dev_guide.md
下面是 Dataset 的生命周期
下面是 Runtime 的生命周期
使用时:
Pod 对挂载的文件目录请求都会转给 fuse pod,由 fuse 将文件 io 转为网络 io 访问后端的 runtime 存储。
2. 部署 Fluid
1
| kubectl create ns fluid-system
|
1
2
| helm repo add fluid https://fluid-cloudnative.github.io/charts
helm repo update
|
1
| helm install --namespace fluid-system fluid fluid/fluid --devel
|
由于我 format 使用的 juicefs client 版本为 juicefs version 1.1.1+2023-11-28.437f4e6
,为了 work/fuse pod 中的镜像版本与之匹配(当然也可以配置),这里使用的是 --devel
版本,即目前的 1.0.0 内测版本。
1
2
3
4
| helm list --namespace fluid-system
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
fluid fluid-system 1 2024-01-25 21:48:14.902476965 +0800 CST deployed fluid-1.0.0-alpha.17 1.0.0-719fc87
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| kubectl -n fluid-system get pod
NAME READY STATUS RESTARTS AGE
csi-nodeplugin-fluid-b8k9l 2/2 Running 0 9m33s
csi-nodeplugin-fluid-gzl6w 2/2 Running 0 9m33s
csi-nodeplugin-fluid-p5whc 2/2 Running 0 9m33s
csi-nodeplugin-fluid-pwplp 2/2 Running 0 9m33s
csi-nodeplugin-fluid-xs9kc 2/2 Running 0 9m33s
csi-nodeplugin-fluid-xwwlm 2/2 Running 0 9m33s
dataset-controller-6978c55675-2rtdr 1/1 Running 0 9m33s
fluid-webhook-76d4c5fd45-bbmw7 1/1 Running 0 9m33s
fluidapp-controller-697656949c-487mv 1/1 Running 0 9m33s
juicefsruntime-controller-fbf45c44f-vtlcf 1/1 Running 0 5m17s
|
3. 环境准备
- 启动一个 Redis 实例,提供给 JuiceFS 使用
1
| mkdir -p /data/test/redis-data && cd /data/test
|
1
| nerdctl run -d --name redis --network host -v $PWD/redis-data:/data -e REDIS_PASSWORD=mypassword redis:6
|
1
2
3
4
| export REDIS_IP=x.x.x.x
export REDIS_PORT=6379
export REDIS_USER=default
export REDIS_PASSWORD=mypassword
|
1
2
3
4
5
6
| export ACCESS_KEY=xxx
export SECRET_KEY=xxx
export BUCKET=xxx
export ENDPOINT=xxx
export BUCKET_ENPOINT=$BUCKET.$ENDPOINT
export PROVIDER=xxx
|
1
2
3
4
5
6
| export REDIS_DIRECTSERVER=redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_IP}:${REDIS_PORT}/1
juicefs format \
--storage ${PROVIDER} \
--bucket ${BUCKET_ENPOINT}\
${REDIS_DIRECTSERVER} \
juicefs-direct-demo
|
文件系统需要提前初始化,否则在集群中使用时,会提示找不到 .stats
文件类似错误。
1
| export NAMESPACE=shaowen-test
|
1
| juicefs mount -d --buffer-size 2000 --max-uploads 150 ${REDIS_DIRECTSERVER} ./${NAMESPACE}-direct --cache-dir=/data/jfs-${NAMESPACE}
|
1
2
| cd ${NAMESPACE}-direct
echo "123" > test.txt
|
4. 配置 DatasSet
1
| kubectl create ns ${NAMESPACE}
|
1
2
3
4
5
6
7
8
9
10
11
12
| kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: juicefs-direct-secret
namespace: ${NAMESPACE}
type: Opaque
stringData:
metaurl: redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_IP}:6379/1
access-key: ${ACCESS_KEY}
secret-key: ${SECRET_KEY}
EOF
|
Redis 需要设置用户名,默认是 default,要明文指出。
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
30
31
32
| kubectl apply -f - <<EOF
apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: juicefs-direct-demo
namespace: ${NAMESPACE}
spec:
accessModes:
- ReadWriteMany
mounts:
- name: juicefs-direct-demo
mountPoint: "juicefs:///"
options:
bucket: ${BUCKET_ENPOINT}
storage: ${PROVIDER}
encryptOptions:
- name: metaurl
valueFrom:
secretKeyRef:
name: juicefs-direct-secret
key: metaurl
- name: access-key
valueFrom:
secretKeyRef:
name: juicefs-direct-secret
key: access-key
- name: secret-key
valueFrom:
secretKeyRef:
name: juicefs-direct-secret
key: secret-key
EOF
|
bucket
应该是 Bucket.Endpoint
的完整形式,而不能只填一个桶名。默认的 accessModes 为 ReadOnlyMany,即只读模式,这里改为 ReadWriteMany 。另外,这里配置挂载的是 JuiceFS 的 / 目录,在生产使用时,可以按照项目、应用维度挂载不同的子目录。
1
2
3
4
| kubectl -n ${NAMESPACE} get dataset
NAME UFS TOTAL SIZE CACHED CACHE CAPACITY CACHED PERCENTAGE PHASE AGE
juicefs-direct-demo NotBound 4s
|
此时还没有配置同名的 Runtime,因此状态为 NotBound。
5. 配置 Runtime
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| kubectl apply -f - <<EOF
apiVersion: data.fluid.io/v1alpha1
kind: JuiceFSRuntime
metadata:
name: juicefs-direct-demo
namespace: ${NAMESPACE}
spec:
replicas: 1
tieredstore:
levels:
- mediumtype: SSD
path: /cache
quota: 40960 # 40GiB
low: "0.1"
EOF
|
这里有很多参数可以配置,可以参考 https://github.com/fluid-cloudnative/fluid 对应分支 api 目录下 CRD 的定义说明。使用不同的 Fluid 版本,参数可能会有不同,注意区分。
1
2
3
4
| kubectl -n ${NAMESPACE} get juicefsruntime
NAME WORKER PHASE FUSE PHASE AGE
juicefs-direct-demo Ready 96s
|
可能需要等待一会儿才能 Ready,因为需要创建 woker 。
1
2
3
4
| kubectl -n ${NAMESPACE} get pod
NAME READY STATUS RESTARTS AGE
juicefs-direct-demo-worker-0 1/1 Running 0 115s
|
worker 无异常,正常运行。
1
2
3
4
| kubectl -n ${NAMESPACE} get dataset
NAME UFS TOTAL SIZE CACHED CACHE CAPACITY CACHED PERCENTAGE PHASE AGE
juicefs-direct-demo 1.01GiB 40.00KiB Bound 33m
|
1
2
3
4
| kubectl -n shaowen-test get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
juicefs-direct-demo Bound shaowen-test-juicefs-direct-demo 100Pi RWX fluid 5m21s
|
RWX 表示 ReadWriteMany,即读写模式。
6. 创建负载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: juicefs-direct-demo
namespace: ${NAMESPACE}
spec:
containers:
- name: demo
image: shaowenchen/demo-ubuntu
volumeMounts:
- mountPath: /data/jfs
name: data
volumes:
- name: data
persistentVolumeClaim:
claimName: juicefs-direct-demo
EOF
|
1
2
3
4
5
6
| kubectl -n ${NAMESPACE} get pod juicefs-direct-demo
NAME READY STATUS RESTARTS AGE
juicefs-direct-demo 1/1 Running 0 52m
juicefs-direct-demo-fuse-mkz4x 1/1 Running 0 52m
juicefs-direct-demo-worker-0 1/1 Running 0 54m
|
1
2
3
4
5
6
7
8
9
10
11
12
| kubectl -n ${NAMESPACE} exec -it juicefs-direct-demo bash
ls -al /data/jfs/
total 7
drwxrwxrwx 2 root root 4096 Jan 25 12:33 .
drwxr-xr-x 3 root root 25 Jan 25 12:53 ..
-r-------- 1 root root 0 Jan 25 12:53 .accesslog
-r-------- 1 root root 1627 Jan 25 12:53 .config
-r--r--r-- 1 root root 0 Jan 25 12:53 .stats
dr-xr-xr-x 2 root root 0 Jan 25 12:53 .trash
-rw-r--r-- 1 root root 4 Jan 25 12:33 test.txt
|
在 Pod 中挂载了 JuiceFS 的目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| juicefs bench --block-size 4096 --big-file-size 1024 --threads 5 ./
+------------------+------------------+---------------+
| ITEM | VALUE | COST |
+------------------+------------------+---------------+
| Write big file | 207.88 MiB/s | 24.63 s/file |
| Read big file | 761.77 MiB/s | 6.72 s/file |
| Write small file | 136.8 files/s | 36.56 ms/file |
| Read small file | 293.7 files/s | 17.03 ms/file |
| Stat file | 9007.3 files/s | 0.56 ms/file |
| FUSE operation | 89312 operations | 0.97 ms/op |
| Update meta | 1595 operations | 1.57 ms/op |
| Put object | 1780 operations | 111.32 ms/op |
| Get object | 1780 operations | 75.37 ms/op |
+------------------+------------------+---------------+
|