有奖捉虫:云通信与企业服务文档专题,速来> HOT
通过 GooseFS 和 Fuse,Fluid 为用户提供了一种更为简单的文件访问接口,使得任意运行在 Kubernetes 集群上的程序能够像访问本地文件一样轻松访问存储在远程文件系统中的文件。Fluid 针对数据集进行全生命周期的管理和隔离,尤其对于短生命周期应用(例如数据分析任务、机器学习任务),用户可以在集群中大规模部署。

前提条件

在运行该示例之前,请参考 安装 文档完成安装,并检查 Fluid 各组件正常运行:
$ kubectl get pod -n fluid-system
NAME READY STATUS RESTARTS AGE
goosefsruntime-controller-5b64fdbbb-84pc6 1/1 Running 0 8h
csi-nodeplugin-fluid-fwgjh 2/2 Running 0 8h
csi-nodeplugin-fluid-ll8bq 2/2 Running 0 8h
dataset-controller-5b7848dbbb-n44dj 1/1 Running 0 8h
通常来说,您会看到一个名为 dataset-controller 的 Pod、一个名为 goosefsruntime-controller 的 Pod 和多个名为 csi-nodeplugin 的 Pod 正在运行。其中 csi-nodeplugin 这些 Pod 的数量取决于您的 Kubernetes 集群中结点的数量。

运行示例

对某个节点打标签
$ kubectl label node 192.168.0.199 fluid=multi-dataset
说明
在接下来的步骤中,我们将使用 NodeSelector 来管理 Dataset 调度的节点,这里仅做测试使用。
查看待创建的 Dataset 资源对象
dataset.yaml
apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: hbase
spec:
mounts:
- mountPoint: https://mirrors.tuna.tsinghua.edu.cn/apache/hbase/stable/
name: hbase
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: fluid
operator: In
values:
- "multi-dataset"
placement: "Shared" # 设置为 Exclusive 或者为空则为独占节点数据集

dataset1.yaml
apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: spark
spec:
mounts:
- mountPoint: https://mirrors.bit.edu.cn/apache/spark/
name: spark
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: fluid
operator: In
values:
- "multi-dataset"
placement: "Shared"

说明
为了方便用户进行测试,mountPoint 这里使用的是 Web UFS,使用 COS 作为 UFS 可见 使用 GooseFS 挂载 COS(COSN)
创建 Dataset 资源对象
$ kubectl apply -f dataset.yaml
dataset.data.fluid.io/hbase created
$ kubectl apply -f dataset1.yaml
dataset.data.fluid.io/spark created
查看 Dataset 资源对象状态
$ kubectl get dataset
NAME UFS TOTAL SIZE CACHED CACHE CAPACITY CACHED PERCENTAGE PHASE AGE
hbase NotBound 6s
spark NotBound 4s
如上所示,status中的phase属性值为NotBound,这意味着该Dataset资源对象目前还未与任何GooseFSRuntime资源对象绑定,接下来,我们将创建一个GooseFSRuntime资源对象。
查看待创建的 GooseFSRuntime 资源对象
runtime.yaml
apiVersion: data.fluid.io/v1alpha1
kind: GooseFSRuntime
metadata:
name: hbase
spec:
replicas: 1
tieredstore:
levels:
- mediumtype: SSD
path: /mnt/disk1
quota: 2G
high: "0.8"
low: "0.7"

runtime-1.yaml
apiVersion: data.fluid.io/v1alpha1
kind: GooseFSRuntime
metadata:
name: spark
spec:
replicas: 1
tieredstore:
levels:
- mediumtype: SSD
path: /mnt/disk2/
quota: 4G
high: "0.8"
low: "0.7"

创建 GooseFSRuntime 资源对象
$ kubectl create -f runtime.yaml
goosefsruntime.data.fluid.io/hbase created


# 等待 Dataset hbase 全部组件 Running
$ kubectl get pod -o wide | grep hbase
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
hbase-fuse-jl2g2 1/1 Running 0 2m24s 192.168.0.199 192.168.0.199 <none> <none>
hbase-master-0 2/2 Running 0 2m55s 192.168.0.200 192.168.0.200 <none> <none>
hbase-worker-g89p8 2/2 Running 0 2m24s 192.168.0.199 192.168.0.199 <none> <none>

$ kubectl create -f runtime1.yaml
goosefsruntime.data.fluid.io/spark created
检查 GooseFSRuntime 资源对象是否已经创建
$ kubectl get goosefsruntime
NAME MASTER PHASE WORKER PHASE FUSE PHASE AGE
hbase Ready Ready Ready 2m14s
spark Ready Ready Ready 58s
GooseFSRuntime是另一个 Fluid 定义的 CRD。一个 GooseFSRuntime 资源对象描述了在 Kubernetes 集群中运行一个 GooseFS 实例所需要的配置信息。
等待一段时间,让 GooseFSRuntime 资源对象中的各个组件得以顺利启动,您会看到类似以下状态:
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
hbase-fuse-jl2g2 1/1 Running 0 2m24s 192.168.0.199 192.168.0.199 <none> <none>
hbase-master-0 2/2 Running 0 2m55s 192.168.0.200 192.168.0.200 <none> <none>
hbase-worker-g89p8 2/2 Running 0 2m24s 192.168.0.199 192.168.0.199 <none> <none>
spark-fuse-5z49p 1/1 Running 0 19s 192.168.0.199 192.168.0.199 <none> <none>
spark-master-0 2/2 Running 0 50s 192.168.0.200 192.168.0.200 <none> <none>
spark-worker-96ksn 2/2 Running 0 19s 192.168.0.199 192.168.0.199 <none> <none>
注意上面不同的 Dataset 的 worker 和 fuse 组件可以正常的调度到相同的节点 192.168.0.199
再次查看 Dataset 资源对象状态
$ kubectl get dataset
NAME UFS TOTAL SIZE CACHED CACHE CAPACITY CACHED PERCENTAGE PHASE AGE
hbase 443.89MiB 0.00B 2.00GiB 0.0% Bound 11m
spark 1.92GiB 0.00B 4.00GiB 0.0% Bound 9m38s
因为已经与一个成功启动的 GooseFSRuntime 绑定,该 Dataset 资源对象的状态得到了更新,此时 PHASE 属性值已经变为 Bound 状态。通过上述命令可以获知有关资源对象的基本信息
查看 GooseFSRuntime 状态
$ kubectl get goosefsruntime -o wide
NAME READY MASTERS DESIRED MASTERS MASTER PHASE READY WORKERS DESIRED WORKERS WORKER PHASE READY FUSES DESIRED FUSES FUSE PHASE AGE
hbase 1 1 Ready 1 1 Ready 1 1 Ready 11m
spark 1 1 Ready 1 1 Ready 1 1 Ready 9m52s
说明
GooseFSRuntime 资源对象的 status 中包含了更多更详细的信息。
查看与远程文件关联的 PersistentVolume 以及 PersistentVolumeClaim
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
hbase 100Gi RWX Retain Bound default/hbase 4m55s
spark 100Gi RWX Retain Bound default/spark 51s
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
hbase Bound hbase 100Gi RWX 4m57s
spark Bound spark 100Gi RWX 53s
Dataset资源对象准备完成后(即与 GooseFS 实例绑定后),与该资源对象关联的 PV,PVC 已经由 Fluid 生成,应用可以通过该 PVC 完成远程文件在 Pod 中的挂载,并通过挂载目录实现远程文件访问。

远程文件访问

查看待创建的应用
nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-hbase
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- mountPath: /data
name: hbase-vol
volumes:
- name: hbase-vol
persistentVolumeClaim:
claimName: hbase
nodeName: 192.168.0.199

nginx1.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-spark
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- mountPath: /data
name: hbase-vol
volumes:
- name: hbase-vol
persistentVolumeClaim:
claimName: spark
nodeName: 192.168.0.199

启动应用进行远程文件访问
$ kubectl create -f nginx.yaml
$ kubectl create -f nginx1.yaml
登录 Nginx hbase Pod:
$ kubectl exec -it nginx-hbase -- bash
查看远程文件挂载情况:
$ ls -lh /data/hbase
total 444M
-r--r----- 1 root root 193K Sep 16 00:53 CHANGES.md
-r--r----- 1 root root 112K Sep 16 00:53 RELEASENOTES.md
-r--r----- 1 root root 26K Sep 16 00:53 api_compare_2.2.6RC2_to_2.2.5.html
-r--r----- 1 root root 211M Sep 16 00:53 hbase-2.2.6-bin.tar.gz
-r--r----- 1 root root 200M Sep 16 00:53 hbase-2.2.6-client-bin.tar.gz
-r--r----- 1 root root 34M Sep 16 00:53 hbase-2.2.6-src.tar.gz
登录 Nginx spark Pod:
$ kubectl exec -it nginx-spark -- bash
查看远程文件挂载情况:
$ ls -lh /data/spark/
total 1.0K
dr--r----- 1 root root 7 Oct 22 12:21 spark-2.4.7
dr--r----- 1 root root 7 Oct 22 12:21 spark-3.0.1
$ du -h /data/spark/
999M /data/spark/spark-3.0.1
968M /data/spark/spark-2.4.7
2.0G /data/spark/
登出 Nginx Pod:
$ exit
正如您所见,WebUFS 上所存储的全部文件像本地文件一样无区别地存在于某个 Pod 中,并且可以被该 Pod 十分方便地访问。

远程文件访问加速

为了演示在访问远程文件时,您能获得多大的加速效果,我们提供了一个测试作业的样例:
查看待创建的测试作业
app.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: fluid-copy-test-hbase
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: busybox
image: busybox
command: ["/bin/sh"]
args: ["-c", "set -x; time cp -r /data/hbase ./"]
volumeMounts:
- mountPath: /data
name: hbase-vol
volumes:
- name: hbase-vol
persistentVolumeClaim:
claimName: hbase
nodeName: 192.168.0.199

app1.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: fluid-copy-test-spark
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: busybox
image: busybox
command: ["/bin/sh"]
args: ["-c", "set -x; time cp -r /data/spark ./"]
volumeMounts:
- mountPath: /data
name: spark-vol
volumes:
- name: spark-vol
persistentVolumeClaim:
claimName: spark
nodeName: 192.168.0.199

启动测试作业
$ kubectl create -f app.yaml
job.batch/fluid-copy-test-hbase created
$ kubectl create -f app1.yaml
job.batch/fluid-copy-test-spark created
hbase 任务程序会执行 time cp -r /data/hbase ./ 的 shell 命令,其中 /data/hbase 是远程文件在 Pod 中挂载的位置,该命令完成后会在终端显示命令执行的时长。
spark 任务程序会执行 time cp -r /data/spark ./ 的 shell 命令,其中 /data/spark 是远程文件在 Pod 中挂载的位置,该命令完成后会在终端显示命令执行的时长。
等待一段时间,待该作业运行完成,作业的运行状态可通过以下命令查看:
$ kubectl get pod -o wide | grep copy
fluid-copy-test-hbase-r8gxp 0/1 Completed 0 4m16s 172.29.0.135 192.168.0.199 <none> <none>
fluid-copy-test-spark-54q8m 0/1 Completed 0 4m14s 172.29.0.136 192.168.0.199 <none> <none>
如果看到如上结果,则说明该作业已经运行完成。
注意
fluid-copy-test-hbase-r8gxp 中的 r8gxp 为作业生成的标识,在您的环境中,这个标识可能不同,接下来的命令中涉及该标识的地方请以您的环境为准。
查看测试作业完成时间
$ kubectl logs fluid-copy-test-hbase-r8gxp
+ time cp -r /data/hbase ./
real 3m 34.08s
user 0m 0.00s
sys 0m 1.24s
$ kubectl logs fluid-copy-test-spark-54q8m
+ time cp -r /data/spark ./
real 3m 25.47s
user 0m 0.00s
sys 0m 5.48s
可见,第一次远程文件读取 hbase 耗费了接近3分34秒的时间,读取 spark 耗费接近3分25秒的时间。
查看 Dataset 资源对象状态
$ kubectl get dataset
NAME UFS TOTAL SIZE CACHED CACHE CAPACITY CACHED PERCENTAGE PHASE AGE
hbase 443.89MiB 443.89MiB 2.00GiB 100.0% Bound 30m
spark 1.92GiB 1.92GiB 4.00GiB 100.0% Bound 28m
现在,所有远程文件都已经被缓存在了 GooseFS 中。
再次启动测试作业
$ kubectl delete -f app.yaml
$ kubectl create -f app.yaml
$ kubectl delete -f app1.yaml
$ kubectl create -f app1.yaml
由于远程文件已经被缓存,此次测试作业能够迅速完成:
$ kubectl get pod -o wide| grep fluid
fluid-copy-test-hbase-sf5md 0/1 Completed 0 53s 172.29.0.137 192.168.0.199 <none> <none>
fluid-copy-test-spark-fwp57 0/1 Completed 0 51s 172.29.0.138 192.168.0.199 <none> <none>
$ kubectl logs fluid-copy-test-hbase-sf5md
+ time cp -r /data/hbase ./
real 0m 0.36s
user 0m 0.00s
sys 0m 0.36s
$ kubectl logs fluid-copy-test-spark-fwp57
+ time cp -r /data/spark ./
real 0m 1.57s
user 0m 0.00s
sys 0m 1.57s
同样的文件访问操作,hbase 仅耗费了0.36秒,spark仅耗费了1.57秒。
这种大幅度的加速效果归因于 GooseFS 所提供的强大的缓存能力,这种缓存能力意味着,只要您访问某个远程文件一次,该文件就会被缓存在 GooseFS 中,您的所有接下来的重复访问都不再需要读取远程文件,而是从 GooseFS 中直接获取数据。

环境清理

$ kubectl delete -f .
$ kubectl label node 192.168.0.199 fluid-