Fluid-数据编排能力原理解析

news2025/6/9 19:12:58

前言

本文对Fluid基础功能-数据编排能力进行原理解析。其中涉及到Fluid架构和k8s csi driver相关知识。建议先了解相关概念,

为了便于理解,本文使用JuiceFS作为后端runtime引擎。

原理概述

Fuild数据编排能力,主要是在云原生环境中,能让用户在使用远端存储时,只需简单声明几个对象,即可像使用本地存储一样简单。无需关心后端的繁琐配置,和数据存储、拉取过程。甚至无需关心后端的存储实现方式。

该能力主要利用dataSet和Runtime以及对应的controller组件实现。

dataset是用于告诉Fluid,在哪里能够找到所需要的数据,比如对于JuiceFS,指的是 JuiceFS 的子目录,是用户在 JuiceFS 文件系统中存储数据的目录。

runtime这里根据后端实际引擎不同,runtime的实现形式有多种,比如AlluxioRuntime、JuiceFSRuntime等,这些都是k8s的CRD。

以JuiceFSRuntime为例,它用于声明一个juiceFS的最小化集群,包括worker副本数量,worker的缓存形式(mem、ssd、hdd),worker的缓存大小等。runtime-controller根据该声明,部署相应的juiceFS组件。

用户使用时,只需要在pod中使用同名的pvc即可。

工作流程梳理

若字体看不清,可点击图片查看大图:

详细流程解析

一、用户创建Dataset

apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
  name: jfsdemo
spec:
  mounts:
    - name: test
      mountPoint: "juicefs:///demo"
      options:
        bucket: "<bucket>"

mounts字段:

name:juiceFS中创建的文件系统名称

mountPoint:指的是 JuiceFS 的子目录,是用户在 JuiceFS 文件系统中存储数据的目录,以 juicefs:// 开头;如 juicefs:///demo 为 JuiceFS 文件系统的 /demo 子目录。

options.bucket:Bucket URL。例如使用 S3 作为对象存储,bucket 为对象存储URL,如果使用其他,比如minio,mysql,也为对应URL。

二、Dataset Controller处理Dataset

controller监听到dataset被创建,将dataset状态设置为NotBound,表示还没有与任何runtime绑定。

三、用户创建JuiceFSRuntime

apiVersion: data.fluid.io/v1alpha1
kind: JuiceFSRuntime
metadata:
  name: jfsdemo
spec:
  replicas: 1
  tieredstore:
    levels:
      - mediumtype: MEM
        path: /dev/shm
        quota: 40960

mudiumtype:worker缓存形式,MEM,SSD,HDD

path:worker的缓存目录

quota:缓存大小,单位Mi

四、runtime controller处理JuiceFSRuntime

controller监听到JuiceFSRuntime被创建,开始一系列对于juiceFS 集群的创建操作。

1)查找对应的dataset(同名,同ns)。并将dataset设置为该runtime的ownerReferences。

...
if !utils.ContainsOwners(objectMeta.GetOwnerReferences(), dataset) {
   return r.AddOwnerAndRequeue(ctx, dataset)
  }
...

2)创建runtime 的master负载。

根据runtime填入的参数,通过helm进行安装

valuefileName, err := j.generateJuicefsValueFile(runtime)
...
 found, err := helm.CheckRelease(j.name, j.namespace)
...
 return helm.InstallRelease(j.name, j.namespace, valuefileName, chartName)

3)更新runtime的状态为NotReady

4)创建runtime的worker负载

根据runtime填入的参数,通过helm进行安装,同时设置pod 反亲和性,worker分散在不同节点

func (e *Helper) SetupWorkers(runtime base.RuntimeInterface,
 currentStatus datav1alpha1.RuntimeStatus,
 workers *appsv1.StatefulSet) (err error) {

 desireReplicas := runtime.Replicas()
 if *workers.Spec.Replicas != desireReplicas {
  // workerToUpdate, err := e.buildWorkersAffinity(workers)

  workerToUpdate, err := e.BuildWorkersAffinity(workers)
  if err != nil {
   return err
  }

  workerToUpdate.Spec.Replicas = &desireReplicas
  err = e.client.Update(context.TODO(), workerToUpdate)
  if err != nil {
   return err
  }

5)创建daemonset fuse组件

且只会在有label:fluid.io/f-default-jfsdemo=true 的node上运行pod。目前所有node都没有该label,因此fuse 的ds虽然部署成功,但是pod运行数量暂时为0。什么时候会给node打上该label呢,继续往后看。

6)等待worker和master的pod全部启动,设置runtime的状态为Ready

func (j *JuiceFSEngine) CheckAndUpdateRuntimeStatus() (ready bool, err error) {

......
  runtimeToUpdate.Status.WorkerNumberReady = int32(workers.Status.ReadyReplicas)
  runtimeToUpdate.Status.WorkerNumberUnavailable = int32(*workers.Spec.Replicas - workers.Status.ReadyReplicas)
  runtimeToUpdate.Status.WorkerNumberAvailable = int32(workers.Status.CurrentReplicas)
  if workers.Status.ReadyReplicas > 0 {
   if runtime.Replicas() == workers.Status.ReadyReplicas {
    runtimeToUpdate.Status.WorkerPhase = data.RuntimePhaseReady
    workerReady = true
   } else if workers.Status.ReadyReplicas >= 1 {
    runtimeToUpdate.Status.WorkerPhase = data.RuntimePhasePartialReady
    workerReady = true
   }

7)更新dataset状态,由pending->bound

func (j *JuiceFSEngine) BindToDataset() (err error) {

 return j.UpdateDatasetStatus(datav1alpha1.BoundDatasetPhase)
}

8)创建pv和pvc

controller接下来创建pv和pvc

创建pv

PersistentVolumeSource: v1.PersistentVolumeSource{
     CSI: &v1.CSIPersistentVolumeSource{
      Driver:       common.CSIDriver,
      VolumeHandle: pvName,
      VolumeAttributes: map[string]string{
       common.FluidPath: mountPath,
       common.MountType: mountType,

其中pv的参数需要注意:

driver:所使用的csi driver的名称。这个值必须与 CSI 驱动程序在 GetPluginInfoResponse 中返回的值相对应;CSI 驱动程序也使用该值来辨识哪些 PV 对象属于该 CSI 驱动程序。这里common.CSIDriver就是:fuse.csi.fluid.io

VolumeHandle:唯一标识卷的字符串值。 该值必须与 CSI 驱动在 CreateVolumeResponse 的 volume_id 字段中返回的值相对应;在所有对 CSI 卷驱动程序的调用中,引用该 CSI 卷时都使用此值作为 volume_id 参数

spec:
......
  csi:
    driver: fuse.csi.fluid.io //csi driver
    volumeAttributes:
      fluid_path: /runtime-mnt/juicefs/default/jfsdemo/juicefs-fuse
      mount_type: JuiceFS
    volumeHandle: default-jfsdemo
  persistentVolumeReclaimPolicy: Retain
  storageClassName: fluid
  volumeMode: Filesystem

9)周期性同步runtime和dataset状态

通过查询fuse pod,worker pod。更新runtime和dataset的状态。包括

根据查询worker pod的metrics监控信息,查询缓存状态。并更新runtime和dataset的缓存数据状态,缓存进度。

根据worker pod数量是否正常,设置runtime和dataset的状态是否健康。

10)同步worker所在节点

由于worker具有缓存能力,因此需要对所在的node打上label,标志该node具有数据缓存。方便对业务pod进行调度。

查询所有worker所在节点,并与当前已经打上缓存label的节点进行对比,worker所在节点没有label的,需要加上。worker不在节点上有label的,需要删除。

五、创建业务pod,并使用该pvc

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

k8s调度器将其调度到某个node上运行。将pod信息与node绑定,接下来该节点上的kubelet接手pod,开始pod的真正创建流程。

六、kubelet向csi driver请求NodeStageVolume

kubelet发现pod有pvc的需求,kubelet的volumemanager组件会根据pvc声明所使用的csi driver名称:fuse.csi.fluid.io。查询当前集群中注册的csi driver,一旦发现匹配,就根据注册的信息,向csi driver发送请求,让csi driver开始进行数据卷挂载。

请求的接口是:NodeStageVolume。该接口也是csi drvier规范中必须实现的方法。该接口用于:如果存储卷没有格式化,首先要格式化。然后把存储卷mount到一个临时的目录(这个目录通常是节点上的一个全局目录)。

kubelet代码:

k8s.io/kubernetes/pkg/volume/csi/csi_attacher.go

 func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error {
 .....
     fsType := csiSource.FSType
     err = csi.NodeStageVolume(ctx,
      csiSource.VolumeHandle,
      publishContext,
      deviceMountPath,
      fsType,
      accessMode,
      nodeStageSecrets,
      csiSource.VolumeAttributes,
      mountOptions)
  ....
  }

七、csi driver 设置Node label

fluid的csi driver接收到kubelet发送的NodeStageVolume请求后,设置所在Node的label:fluid.io/f-default-jfsdemo=true

fluid/pkg/csi/plugins/nodeserver.go

 // 2. Label node
 fuseLabelKey := common.LabelAnnotationFusePrefix + namespace + "-" + name
 var labelsToModify common.LabelsToModify
 labelsToModify.Add(fuseLabelKey, "true")

 node, err := kubeclient.GetNode(ns.client, ns.nodeId)
 if err != nil {
  glog.Errorf("NodeStageVolume: can't get node %s: %v", ns.nodeId, err)
  return nil, errors.Wrapf(err, "NodeStageVolume: can't get node %s", ns.nodeId)
 }

 if _, ok := node.Labels[fuseLabelKey]; !ok {
  _, err = utils.ChangeNodeLabelWithPatchMode(ns.client, node, labelsToModify)
  if err != nil {
   glog.Errorf("NodeStageVolume: error when patching labels on node %s: %v", ns.nodeId, err)
   return nil, errors.Wrapf(err, "NodeStageVolume: error when patching labels on node %s", ns.nodeId)
  }

设置该label后,之前部署的fuse daemonset会检测到该node存在符合条件label,就会在node上拉起fuse pod。

八、juice fuse pod进行本地目录挂载

fuse pod在节点上启动后,会使用juiceFS的命令,将远端存储挂载到本地临时目录。

fuse内部执行命令:

/usr/local/bin/juicefs format --storage=mysql --bucket=mysql2.redis.svc.linux.local:3306/test --access-key=${ACCESS_KEY} --secret-key=${SECRET_KEY} ${METAURL} mysql

/bin/mount.juicefs redis://:123456@mymaster,redis-0.redis.redis.svc.linux.local,redis-1.redis.redis.svc.linux.local,redis-2.redis.redis.svc.linux.local:26379/3 /runtime-mnt/juicefs/default/jfsdemo/juicefs-fuse 

/runtime-mnt/juicefs/default/jfsdemo/juicefs-fuse 就是本节点的临时存储目录。

九、kubelet向csi driver请求NodePublishVolume

csi 规范的NodePublishVolume 方法。将存储卷从节点临时目录mount到目标目录(pod目录)。

k8s.io/kubernetes/pkg/volume/csi/csi_mounter.go

func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
    err = csi.NodePublishVolume(
      ctx,
      volumeHandle,
      readOnly,
      deviceMountPath,
      dir,
      accessMode,
      publishContext,
      volAttribs,
      nodePublishSecrets,
      fsType,
      mountOptions,
     )
}

十、csi driver 执行NodePublishVolume方法

fluid的csi driver接收到kubelet发送的NodePublishVolume请求后,将本节点临时目录mount bind到pod目录。

func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
    err = csi.NodePublishVolume(
      ctx,
      volumeHandle,
      readOnly,
      deviceMountPath,
      dir,
      accessMode,
      publishContext,
      volAttribs,
      nodePublishSecrets,
      fsType,
      mountOptions,
     )
}

比如pod目录:/var/lib/kubelet/pods/15b00274-11f2-4dde-9fdf-e590a6284e20/volumes/kubernetes.io~csi/default-jfsdemo/mount

该目录也是在节点上,也通过docker -v的形式挂载到pod内部,因此该目录的改动也能够在pod内部感知到。

以上,就完成了将远端存储挂载到pod内部的操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/334165.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FEC原理与操作及BigTao机框装机说明

一、FEC原理与操作​ 1.FEC 原理简介 ​ 前向纠错&#xff08;英语&#xff1a;forward error correction&#xff0c;缩写FEC&#xff09;或信道编码&#xff08;英语&#xff1a;channel coding&#xff09;是一种在单向通信系统中控制传输错误的技术&#xff0c;通过连同数…

2023年十款开源测试开发工具推荐!

今天为大家奉献一篇测试开发工具集锦干货。在本篇文章中&#xff0c;将给大家推荐10款日常工作中经常用到的测试开发工具神器&#xff0c;涵盖了自动化测试、性能压测、流量复制、混沌测试、造数据等。 1、AutoMeter-API 自动化测试平台 AutoMeter 是一款针对分布式服务&…

环境变量与命令行参数详解

问题引入 ​ 我们先来看一段简单的死循环代码&#xff1a; int main() {while(1){printf("i am running!\n");sleep(1);}return 0; }​ 我们将其运行编译并生成为可执行文件 myproc &#xff0c;当我们要运行它的时候&#xff0c;都得在这个可执行文件前面加一个 .…

【C++】 类和对象 (下)

文章目录&#x1f4d5;再谈构造函数1. 构造函数体赋值2. 初始化列表3. explicit 关键字&#x1f4d5;static 成员1. 概念2. static 成员变量3. static 成员函数&#x1f4d5; 友元1. 友元函数2. 友元类&#x1f4d5;内部类&#x1f4d5;编译器优化&#x1f4d5;再谈构造函数 1…

Python traceback模块:获取异常信息

除了使用 sys.exc_info() 方法获取更多的异常信息之外&#xff0c;还可以使用 traceback 模块&#xff0c;该模块可以用来查看异常的传播轨迹&#xff0c;追踪异常触发的源头。下面示例显示了如何显示异常传播轨迹&#xff1a;classSelfException(Exception): pass defmain(): …

linux 学习(持续更新)

一&#xff1a;初识linux 新装操作环境&#xff1a; mac intel电脑 CentOS系统版本&#xff1a;CentOS-8.1.1911 在这里解释一下[chenllocalhost /]$这句话的含义&#xff1a; chenl是用户名&#xff0c;也就是你自己起的名字。 是分割的符号 localhost是主机名&#xff0c;也…

轻松实现微信小程序上传多文件/图片到腾讯云对象存储COS(免费额度)

概述 对象存储&#xff08;Cloud Object Storage&#xff0c;COS&#xff09;是腾讯云提供的一种存储海量文件的分布式存储服务&#xff0c;用户可通过网络随时存储和查看数据。个人账户首次开通COS可以免费领取50GB 标准存储容量包6个月&#xff08;180天&#xff09;的额度。…

VBA提高篇_19 可选参数Optional_ IsMissing _MSgbox

文章目录1. 可选参数Optional2.IsMissing判断参数是否提供,只能判断变体类型3. 使用 : 可以按参数名传递参数 a:1,c:34.Msgbox 常用参数5.VBA颜色常量表1. 可选参数Optional Optional 代表本参数是可选项 False ; 代表参数若不指定,则默认为False Function mySumProduct(r As R…

2023年rabbitMq面试题汇总3(5道)

一、如何确保消息不丢失&#xff1f;消息持久化的前提是&#xff1a;将交换器/队列的durable属性设置为true&#xff0c;表示交换器/队列是持久交换器/队列&#xff0c;在服务器崩溃或重启之后不需要重新创建交换器/队列&#xff08;交换器/队列会⾃动创建&#xff09;。如果消…

【监控】Prometheus(普罗米修斯)监控概述

文章目录一、监控系统概论二、基础资源监控2.1、网络监控2.2、存储监控2.3、服务器监控2.4、中间件监控2.5、应用程序监控&#xff08;APM&#xff09;三、Prometheus 简介3.1、什么是 Prometheus3.2、优点3.3、组件3.4、架构3.5、适用于什么场景3.6、不适合什么场景四、数据模…

weston 2: 登录后直接启动weston配置

本人Kubuntu版本是22.04 名词&#xff1a;SDDM&#xff08;SDDM - Arch Linux 中文维基&#xff09;显示管理器 配置流程如下&#xff1a; 1.修改配置文件 a.配置.bashrc vim ~/.bashrc //以下内容删除 #export WLD$HOME/install #export LD_LIBRARY_PATH$WLD/lib/x86_64-…

使用IntelliJ IDEA搭建datax-web开发环境

记录&#xff1a;372场景&#xff1a;使用IntelliJ IDEA搭建datax-web开发环境&#xff0c;以及datax-web基本使用。版本&#xff1a;JDK 1.8Python 2.7.5datax-web开源地址&#xff1a;https://github.com/WeiYe-Jing/datax-web1.配置Maven环境1.1安装目录目录&#xff1a;D:\…

Spring6-基于XML自动装配

一、介绍自动装配&#xff1a;根据指定的策略&#xff0c;在IOC容器中匹配某一个bean&#xff0c;自动为指定的bean中所依赖的类类型或接口类型属性赋值二、创建controllerpackage com.wsy.auto.controller;import com.wsy.auto.service.UserService; import com.wsy.auto.serv…

应用于LSSVM对偶问题的张量列车卡尔曼滤波器的代码(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 ​ &#x1f4a5;1 概述 支持向量机是借助优化方法解决机器学习问题的新工具.近年来,支持向量机越来越受到人们的广泛关注,在其理论研究和算法实现方…

Vue拼图验证

vue-puzzle-verification 封装的一个用于登录验证的拼图的vue组件&#xff0c;使用了canvas画图和拖拽的一些技巧。支持大小、形状、图片、偏差、范围的自定义。 一、安装使用 npm install vue-puzzle-verification 二、main.js里引入 import PuzzleVerification from vue…

训练营day18

513.找树左下角的值 力扣题目链接(opens new window) 给定一个二叉树&#xff0c;在树的最后一行找到最左边的值。 示例 1: 示例 2: var findBottomLeftValue function(root) {let queue [root];let res root.val;while (queue.length) {let node queue.shift();if (nod…

Blender——烘培记录

参考链接&#xff1a;Blender2.8基础三&#xff1a;贴图烘培篇Blender 材质如何导出到 UE 和 Unity 里使用贴图烘焙打开【渲染属性】面板&#xff0c;把【渲染引擎】改为【Cycles】。把【设备】改为GPU计算&#xff0c;可以加快烘培速度。创建一个【图像纹理】节点&#xff08;…

fastadmin后台表单文字过长,限制显示,鼠标悬停显示全部

问题&#xff1a;显示文字区域过长&#xff0c;影响用户体验感 解决措施&#xff1a; 特别注意&#xff1a; return "<span styledisplay: block;overflow: hidden;text-overflow: ellipsis;white-space: nowrap; title" row.contents ">" value …

ARM uboot源码分析1-启动第一阶段

一、start.S 引入 1、u-boot.lds 中找到 start.S 入口 (1) 在 C 语言中整个项目的入口就是 main 函数&#xff08;这是 C 语言规定的&#xff09;&#xff0c;所以譬如说一个有 10000 个.c 文件的项目&#xff0c;第一个要分析的文件就是包含了 main 函数的那个文件。 (2) 在…

分享75个JS焦点图代码,总有一款适合您

分享75个JS焦点图代码&#xff0c;总有一款适合您 75个JS焦点图代码下载链接&#xff1a;https://pan.baidu.com/s/1WuydBKN3eYd3H64lPXv0Fw?pwd0nq7 提取码&#xff1a;0nq7 Python采集代码下载链接&#xff1a;https://wwgn.lanzoul.com/iKGwb0kye3wj base_url "…