数据亲和性调度

最后更新时间:2021-11-18 12:47:33

    在 Fluid 中,Dataset 资源对象中所定义的远程文件是可被调度的,这意味着您能够像管理您的 Pod 一样管理远程文件缓存在 Kubernetes 集群上的存放位置。另外,Fluid 同样支持对于应用的数据缓存亲和性调度,这种调度方式将应用(例如数据分析任务、机器学习任务等)与所需要的数据缓存放置在一起,以尽可能地减少额外的开销。

    前提条件

    在运行该示例之前,请参见 安装 文档完成安装,并检查 Fluid 各组件正常运行:

    $ kubectl get pod -n fluid-system
    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 集群中结点的数量。

    新建工作环境

    $ mkdir <any-path>/co-locality
    $ cd <any-path>/co-locality
    

    示例

    查看全部结点

    $ kubectl get nodes
    NAME                       STATUS   ROLES    AGE     VERSION
    192.168.1.146   Ready    <none>   7d14h   v1.18.4-tke.13
    192.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-cache
    NAME                       STATUS   ROLES    AGE     VERSION            HBASE-CACHE
    192.168.1.146   Ready    <none>   7d14h   v1.18.4-tke.13   true
    192.168.1.147   Ready    <none>   7d14h   v1.18.4-tke.13
    

    目前,在全部2个结点中,仅有一个结点添加了 hbase-cache=true 的标签,接下来我们希望数据缓存仅会被放置在该结点之上。

    检查待创建的 Dataset 资源对象

    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: hbase-cache
                 operator: In
                 values:
                   - "true"
    
    说明:

    为了方便用户进行测试,mountPoint 这里使用的是 Web UFS,使用 COS 作为 UFS 可见 使用 GooseFS 挂载 COS(COSN)

    在该 Dataset 资源对象的 spec 属性中,我们定义了一个 nodeSelectorTerm 的子属性,该子属性要求数据缓存必须被放置在具有 hbase-cache=true 标签的结点之上。

    创建 Dataset 资源对象

    $ kubectl create -f dataset.yaml
    dataset.data.fluid.io/hbase created
    

    检查待创建的 GooseFSRuntime 资源对象

    apiVersion: data.fluid.io/v1alpha1
    kind: GooseFSRuntime
    metadata:
     name: hbase
    spec:
     replicas: 2
     tieredstore:
       levels:
         - mediumtype: SSD
           path: /mnt/disk1
           quota: 2G
           high: "0.8"
           low: "0.7"
    

    该配置文件片段中,包含了许多与 GooseFS 相关的配置信息,这些信息将被 Fluid 用来启动一个 GooseFS 实例。上述配置片段中的 spec.replicas 属性被设置为2,这表明 Fluid 将会启动一个包含1个 GooseFS Master 和2个 GooseFS Worker 的 GooseFS 实例。

    创建 GooseFSRuntime 资源并查看状态

    $ kubectl create -f runtime.yaml
    goosefsruntime.data.fluid.io/hbase created
    
    $ kubectl get pod -o wide
    NAME                 READY   STATUS    RESTARTS   AGE    IP              NODE                       NOMINATED NODE   READINESS GATES
    hbase-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 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               2                 PartialReady   1             2               PartialReady   4m3s
    

    与预想一致,Worker Phase 状态此时为 PartialReady,并且 Ready Workers: 1小于 Desired Workers: 2

    查看待创建的应用

    我们提供了一个样例应用来演示 Fluid 是如何进行数据缓存亲和性调度的,首先查看该应用:

    app.yaml

    apiVersion: apps/v1beta1
    kind: StatefulSet
    metadata:
     name: nginx
     labels:
       app: nginx
    spec:
     replicas: 2
     serviceName: "nginx"
     podManagementPolicy: "Parallel"
     selector: # define how the deployment finds the pods it manages
       matchLabels:
         app: nginx
     template: # define the pods specifications
       metadata:
         labels:
           app: nginx
       spec:
         affinity:
           # prevent two Nginx Pod from being scheduled at the same Node
           # just for demonstrating co-locality demo
           podAntiAffinity:
             requiredDuringSchedulingIgnoredDuringExecution:
             - labelSelector:
                 matchExpressions:
                 - key: app
                   operator: In
                   values:
                   - nginx
               topologyKey: "kubernetes.io/hostname"
         containers:
           - name: nginx
             image: nginx
             volumeMounts:
               - mountPath: /data
                 name: hbase-vol
         volumes:
           - name: hbase-vol
             persistentVolumeClaim:
               claimName: hbase
    

    其中podAntiAffinity 属性将会确保属于相同应用的多个 Pod 被分散到多个不同的结点,这样的配置能够让我们更加清晰的观察到 Fluid 的数据缓存亲和性调度是怎么进行的。podAntiAffinity 只是一个专用于演示的属性,用户可不必太过关注。

    运行应用

    $ kubectl create -f app.yaml
    statefulset.apps/nginx created
    

    查看应用运行状态

    $ kubectl get pod -o wide -l app=nginx
    NAME      READY   STATUS    RESTARTS   AGE    IP              NODE                       NOMINATED NODE   READINESS GATES
    nginx-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 wide
    NAME                 READY   STATUS    RESTARTS   AGE   IP              NODE                       NOMINATED NODE   READINESS GATES
    hbase-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 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          2               2                 Ready          2             2               Ready        46m43s
    
    $ kubectl get pod -l app=nginx -o wide
    NAME      READY   STATUS    RESTARTS   AGE   IP              NODE                       NOMINATED NODE   READINESS GATES
    nginx-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-