在 Fluid 中,
Dataset
资源对象中所定义的远程文件是可被调度的,这意味着您能够像管理您的 Pod 一样管理远程文件缓存在 Kubernetes 集群上的存放位置。另外,Fluid 同样支持对于应用的数据缓存亲和性调度,这种调度方式将应用(例如数据分析任务、机器学习任务等)与所需要的数据缓存放置在一起,以尽可能地减少额外的开销。前提条件
$ kubectl get pod -n fluid-systemgoosefsruntime-controller-5b64fdbbb-84pc6 1/1 Running 0 8hcsi-nodeplugin-fluid-fwgjh 2/2 Running 0 8hcsi-nodeplugin-fluid-ll8bq 2/2 Running 0 8hdataset-controller-5b7848dbbb-n44dj 1/1 Running 0 8h
通常来说,您会看到一个名为
dataset-controller
的 Pod、一个名为 goosefsruntime-controller
的 Pod 和多个名为 csi-nodeplugin
的 Pod 正在运行。其中 csi-nodeplugin
这些 Pod 的数量取决于您的 Kubernetes 集群中结点的数量。新建工作环境
$ mkdir <any-path>/co-locality$ cd <any-path>/co-locality
示例
查看全部结点
$ kubectl get nodesNAME STATUS ROLES AGE VERSION192.168.1.146 Ready <none> 7d14h v1.18.4-tke.13192.168.1.147 Ready <none> 7d14h v1.18.4-tke.13
使用标签标识结点
$ kubectl label nodes 192.168.1.146 hbase-cache=true
在接下来的步骤中,我们将使用
NodeSelector
来管理集群中存放数据的位置,所以在这里标记期望的结点。再次查看结点
$ kubectl get node -L hbase-cacheNAME STATUS ROLES AGE VERSION HBASE-CACHE192.168.1.146 Ready <none> 7d14h v1.18.4-tke.13 true192.168.1.147 Ready <none> 7d14h v1.18.4-tke.13
目前,在全部2个结点中,仅有一个结点添加了
hbase-cache=true
的标签,接下来我们希望数据缓存仅会被放置在该结点之上。检查待创建的 Dataset 资源对象
apiVersion: data.fluid.io/v1alpha1kind: Datasetmetadata:name: hbasespec:mounts:- mountPoint: https://mirrors.tuna.tsinghua.edu.cn/apache/hbase/stable/name: hbasenodeAffinity:required:nodeSelectorTerms:- matchExpressions:- key: hbase-cacheoperator: Invalues:- "true"
说明
在该
Dataset
资源对象的 spec
属性中,我们定义了一个 nodeSelectorTerm
的子属性,该子属性要求数据缓存必须被放置在具有 hbase-cache=true
标签的结点之上。创建 Dataset 资源对象
$ kubectl create -f dataset.yamldataset.data.fluid.io/hbase created
检查待创建的 GooseFSRuntime 资源对象
apiVersion: data.fluid.io/v1alpha1kind: GooseFSRuntimemetadata:name: hbasespec:replicas: 2tieredstore:levels:- mediumtype: SSDpath: /mnt/disk1quota: 2Ghigh: "0.8"low: "0.7"
该配置文件片段中,包含了许多与 GooseFS 相关的配置信息,这些信息将被 Fluid 用来启动一个 GooseFS 实例。上述配置片段中的
spec.replicas
属性被设置为2,这表明 Fluid 将会启动一个包含1个 GooseFS Master 和2个 GooseFS Worker 的 GooseFS 实例。创建 GooseFSRuntime 资源并查看状态
$ kubectl create -f runtime.yamlgoosefsruntime.data.fluid.io/hbase created$ kubectl get pod -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATEShbase-fuse-42csf 1/1 Running 0 104s 192.168.1.146 192.168.1.146 <none> <none>hbase-master-0 2/2 Running 0 3m3s 192.168.1.147 192.168.1.147 <none> <none>hbase-worker-l62m4 2/2 Running 0 104s 192.168.1.146 192.168.1.146 <none> <none>
在此处可以看到,尽管我们期望看见两个 GooseFS Worker 被启动,但仅有一组 GooseFS Worker 成功启动,并且运行在具有指定标签(即
hbase-cache=true
)的结点之上。检查 GooseFSRuntime 状态
$ kubectl get goosefsruntime hbase -o wideNAME READY MASTERS DESIRED MASTERS MASTER PHASE READY WORKERS DESIRED WORKERS WORKER PHASE READY FUSES DESIRED FUSES FUSE PHASE AGEhbase 1 1 Ready 1 2 PartialReady 1 2 PartialReady 4m3s
与预想一致,
Worker Phase
状态此时为 PartialReady
,并且 Ready Workers: 1
小于 Desired Workers: 2
。查看待创建的应用
我们提供了一个样例应用来演示 Fluid 是如何进行数据缓存亲和性调度的,首先查看该应用:
app.yaml
apiVersion: apps/v1beta1kind: StatefulSetmetadata:name: nginxlabels:app: nginxspec:replicas: 2serviceName: "nginx"podManagementPolicy: "Parallel"selector: # define how the deployment finds the pods it managesmatchLabels:app: nginxtemplate: # define the pods specificationsmetadata:labels:app: nginxspec:affinity:# prevent two Nginx Pod from being scheduled at the same Node# just for demonstrating co-locality demopodAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- nginxtopologyKey: "kubernetes.io/hostname"containers:- name: nginximage: nginxvolumeMounts:- mountPath: /dataname: hbase-volvolumes:- name: hbase-volpersistentVolumeClaim:claimName: hbase
其中
podAntiAffinity
属性将会确保属于相同应用的多个 Pod 被分散到多个不同的结点,这样的配置能够让我们更加清晰的观察到 Fluid 的数据缓存亲和性调度是怎么进行的。podAntiAffinity
只是一个专用于演示的属性,用户可不必太过关注。运行应用
$ kubectl create -f app.yamlstatefulset.apps/nginx created
查看应用运行状态
$ kubectl get pod -o wide -l app=nginxNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESnginx-0 1/1 Running 0 2m5s 192.168.1.146 192.168.1.146 <none> <none>nginx-1 0/1 Pending 0 2m5s <none> <none> <none> <none>
仅有一个 Nginx Pod 成功启动,并且运行在满足
nodeSelectorTerm
的结点之上。查看应用启动失败原因
$ kubectl describe pod nginx-1...Events:Type Reason Age From Message---- ------ ---- ---- -------Warning FailedScheduling <unknown> default-scheduler 0/2 nodes are available: 1 node(s) didn't match pod affinity/anti-affinity, 1 node(s) didn't satisfy existing pods anti-affinity rules, 1 node(s) had volume node affinity conflict.Warning FailedScheduling <unknown> default-scheduler 0/2 nodes are available: 1 node(s) didn't match pod affinity/anti-affinity, 1 node(s) didn't satisfy existing pods anti-affinity rules, 1 node(s) had volume node affinity conflict.
如上所示,一方面,为了满足
PodAntiAffinity
属性的要求,使得两个 Nginx Pod 无法被调度到同一节点。另一方面,由于目前满足 Dataset 资源对象亲和性要求的结点仅有一个,因此仅有一个 Nginx Pod 被成功调度。为另一个结点添加标签
$ kubectl label node 192.168.1.147 hbase-cache=true
现在全部两个结点都具有相同的标签了,此时重新检查各个组件的运行状态。
$ kubectl get pod -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATEShbase-fuse-42csf 1/1 Running 0 44m 192.168.1.146 192.168.1.146 <none> <none>hbase-fuse-kth4g 1/1 Running 0 10m 192.168.1.147 192.168.1.147 <none> <none>hbase-master-0 2/2 Running 0 46m 192.168.1.147 192.168.1.147 <none> <none>hbase-worker-l62m4 2/2 Running 0 44m 192.168.1.146 192.168.1.146 <none> <none>hbase-worker-rvncl 2/2 Running 0 10m 192.168.1.147 192.168.1.147 <none> <none>
两个 GooseFS Worker 都成功启动,并且分别运行在两个结点上:
$ kubectl get goosefsruntime hbase -o wideNAME READY MASTERS DESIRED MASTERS MASTER PHASE READY WORKERS DESIRED WORKERS WORKER PHASE READY FUSES DESIRED FUSES FUSE PHASE AGEhbase 1 1 Ready 2 2 Ready 2 2 Ready 46m43s
$ kubectl get pod -l app=nginx -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESnginx-0 1/1 Running 0 21m 192.168.1.146 192.168.1.146 <none> <none>nginx-1 1/1 Running 0 21m 192.168.1.147 192.168.1.147 <none> <none>
另一个 nginx Pod 不再处于
Pending
状态,已经成功启动并运行在另一个结点上。由此可见,可调度的数据缓存以及对应用的数据缓存亲和性调度都是被 Fluid 所支持的特性。在绝大多数情况下,这两个特性协同工作,为用户提供了一种更灵活、更便捷的方式管理在 Kubernetes 集群中的数据。
综上可见,Fluid 支持数据缓存的调度策略,这些调度策略为用户提供了更加灵活的数据缓存管理能力。
环境清理
$ kubectl delete -f .$ kubectl label node 192.168.1.146 hbase-cache-$ kubectl label node 192.168.1.147 hbase-cache-