跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
编程语言

Fluid 数据编排能力原理解析

Fluid 通过 Dataset 和 Runtime CRD 实现云原生环境下的数据编排。用户声明数据集与后端存储引擎(如 JuiceFS),Controller 自动创建 Master、Worker 及 FUSE 组件。CSI Driver 负责卷挂载,将远端存储映射为本地 PVC。流程涵盖状态同步、节点 Label 管理及 Pod 调度绑定,屏蔽底层存储细节,实现类似本地存储的访问体验。

PhpPioneer发布于 2025/1/20更新于 2026/9/1261 浏览
Fluid 数据编排能力原理解析

前言

Fluid 基础功能中的数据编排能力是本文解析的重点。这涉及到 Fluid 架构与 Kubernetes CSI Driver 的相关知识。建议读者先对相关概念有一定了解。为了便于理解,下文以 JuiceFS 作为后端 runtime 引擎进行说明。

原理概述

Fluid 的数据编排能力旨在云原生环境中简化远端存储的使用。用户只需声明几个对象,就能像使用本地存储一样方便,无需关心后端繁琐的配置、数据存储或拉取过程,甚至不需要了解具体的存储实现方式。

该能力主要依赖 DataSet、Runtime 以及对应的 Controller 组件来实现。 DataSet 用于告知 Fluid 数据的位置。例如对于 JuiceFS,它指向 JuiceFS 文件系统下的子目录。 Runtime 根据后端引擎不同有多种形式,如 AlluxioRuntime、JuiceFSRuntime 等,它们都是 Kubernetes 的 CRD。以 JuiceFSRuntime 为例,它声明了 JuiceFS 的最小化集群配置,包括 Worker 副本数、缓存介质(MEM、SSD、HDD)及大小等。Runtime Controller 会根据这些声明部署相应的组件。 用户使用时,只需在 Pod 中引用同名的 PVC 即可。

工作流程梳理

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

详细流程解析

一、用户创建 Dataset

首先定义 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:///demo 代表 /demo 子目录。
  • options.bucket:Bucket URL。如果使用 S3 作为对象存储,此处填写对象存储 URL;若使用 MinIO、MySQL 等其他后端,则填写对应的连接地址。
二、Dataset Controller 处理 Dataset

Controller 监听到 Dataset 被创建后,会将其状态设置为 NotBound,表示尚未与任何 Runtime 绑定。

三、用户创建 JuiceFSRuntime

接着定义 Runtime 资源,配置缓存策略。

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

参数说明:

  • mediumtype:Worker 缓存形式,支持 MEM、SSD、HDD。
  • path:Worker 的缓存目录。
  • quota:缓存大小,单位为 Mi。
四、Runtime Controller 处理 JuiceFSRuntime

Controller 监听到 JuiceFSRuntime 创建后,开始执行一系列集群创建操作。

  1. 关联 Dataset:查找同名且同命名空间的 Dataset,并将其设置为 OwnerReference。

    if !utils.ContainsOwners(objectMeta.GetOwnerReferences(), dataset) {
        return r.AddOwnerAndRequeue(ctx, dataset)
    }
    
  2. 创建 Master 负载:根据 Runtime 参数,通过 Helm 安装 Master 组件。

    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. 创建 Worker 负载:同样通过 Helm 安装,并设置 Pod 反亲和性,确保 Worker 分散在不同节点。

    desireReplicas := runtime.Replicas()
    if *workers.Spec.Replicas != desireReplicas {
        workerToUpdate, err := e.BuildWorkersAffinity(workers)
        if err != nil {
            return err
        }
        workerToUpdate.Spec.Replicas = &desireReplicas
        err = e.client.Update(context.TODO(), workerToUpdate)
        // ...
    }
    
  5. 创建 DaemonSet FUSE 组件:FUSE 组件仅会在带有特定 Label(如 fluid.io/f-default-jfsdemo=true)的节点上运行。初始状态下所有节点均无此 Label,因此 FUSE Pod 数量为 0。后续步骤会补充该 Label。

  6. 等待组件就绪:当 Worker 和 Master 的 Pod 全部启动后,Runtime 状态更新为 Ready。

    if workers.Status.ReadyReplicas > 0 {
        if runtime.Replicas() == workers.Status.ReadyReplicas {
            runtimeToUpdate.Status.WorkerPhase = data.RuntimePhaseReady
            workerReady = true
        }
        // ...
    }
    
  7. 绑定 Dataset:更新 Dataset 状态,由 Pending 变为 Bound。

    return j.UpdateDatasetStatus(datav1alpha1.BoundDatasetPhase)
    
  8. 创建 PV 和 PVC:Controller 随后创建持久卷资源。PV 的关键参数包括:

    • driver:CSI Driver 名称,需与 GetPluginInfoResponse 返回的值一致。Fluid 中使用的是 fuse.csi.fluid.io。
    • volumeHandle:唯一标识卷的字符串,需与 CreateVolumeResponse 中的 volume_id 对应。
    spec:
      csi:
        driver: fuse.csi.fluid.io
        volumeAttributes:
          fluid_path: /runtime-mnt/juicefs/default/jfsdemo/juicefs-fuse
          mount_type: JuiceFS
        volumeHandle: default-jfsdemo
        persistentVolumeReclaimPolicy: Retain
        storageClassName: fluid
        volumeMode: Filesystem
    
  9. 周期性同步状态:通过查询 FUSE Pod 和 Worker Pod,持续更新 Runtime 和 Dataset 的状态。包括基于 Metrics 监控信息的缓存进度更新,以及基于 Worker 数量的健康状态检查。

  10. 同步 Worker 节点 Label:由于 Worker 具备缓存能力,需要给其所在节点打上 Label,标记该节点具有数据缓存,以便业务 Pod 调度。系统会对比 Worker 所在节点与已打 Label 的节点,动态增删 Label。

五、创建业务 Pod 并使用 PVC

定义业务 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

Kubernetes 调度器将其调度到某个节点。Kubelet 接手 Pod 后,开始真正的创建流程。

六、Kubelet 向 CSI Driver 请求 NodeStageVolume

Kubelet 发现 Pod 有 PVC 需求,Volumemanager 组件根据 PVC 声明的 CSI Driver 名称(fuse.csi.fluid.io)查询注册信息,并向 CSI Driver 发送 NodeStageVolume 请求。这是 CSI 规范必须实现的方法,用于格式化存储卷(如需)并将其挂载到节点的临时全局目录。 相关代码逻辑位于 k8s.io/kubernetes/pkg/volume/csi/csi_attacher.go。

七、CSI Driver 设置 Node Label

Fluid 的 CSI Driver 接收到 NodeStageVolume 请求后,会给当前节点打上 Label:fluid.io/f-default-jfsdemo=true。

fuseLabelKey := common.LabelAnnotationFusePrefix + namespace + "-" + name
labelsToModify.Add(fuseLabelKey, "true")
// ...
if _, ok := node.Labels[fuseLabelKey]; !ok {
    _, err = utils.ChangeNodeLabelWithPatchMode(ns.client, node, labelsToModify)
    // ...
}

打上 Label 后,之前部署的 FUSE DaemonSet 会检测到符合条件的节点,从而拉起 FUSE Pod。

八、JuiceFS FUSE Pod 进行本地目录挂载

FUSE Pod 启动后,使用 JuiceFS 命令将远端存储挂载到本地临时目录。

/usr/local/bin/juicefs format --storage=mysql --bucket=... ${METAURL} mysql
/bin/mount.juicefs redis://... /runtime-mnt/juicefs/default/jfsdemo/juicefs-fuse

其中 /runtime-mnt/juicefs/default/jfsdemo/juicefs-fuse 即为本节点的临时存储目录。

九、Kubelet 向 CSI Driver 请求 NodePublishVolume

CSI 规范的 NodePublishVolume 方法负责将存储卷从节点临时目录挂载到目标目录(Pod 目录)。 相关代码位于 k8s.io/kubernetes/pkg/volume/csi/csi_mounter.go。

十、CSI Driver 执行 NodePublishVolume 方法

Fluid 的 CSI Driver 接收到请求后,将本节点临时目录 bind mount 到 Pod 目录。 例如 Pod 目录:/var/lib/kubelet/pods/.../volumes/kubernetes.io~csi/default-jfsdemo/mount。 该目录通过 Docker Volume 挂载到 Pod 内部,因此 Pod 内的改动能实时感知。至此,远端存储成功挂载到 Pod 内部。

目录

  1. 前言
  2. 原理概述
  3. 工作流程梳理
  4. 详细流程解析
  5. 一、用户创建 Dataset
  6. 二、Dataset Controller 处理 Dataset
  7. 三、用户创建 JuiceFSRuntime
  8. 四、Runtime Controller 处理 JuiceFSRuntime
  9. 五、创建业务 Pod 并使用 PVC
  10. 六、Kubelet 向 CSI Driver 请求 NodeStageVolume
  11. 七、CSI Driver 设置 Node Label
  12. 八、JuiceFS FUSE Pod 进行本地目录挂载
  13. 九、Kubelet 向 CSI Driver 请求 NodePublishVolume
  14. 十、CSI Driver 执行 NodePublishVolume 方法

更多推荐文章

查看全部
  • Stable Diffusion 报错排查:CheckpointLoaderSimple 模型文件缺失修复
  • C++ Qt 网络编程:QUdpSocket、QTcpSocket 与 Http 实战
  • Whisper-large-v3 离线部署实战:摆脱 HuggingFace Hub 的网络依赖
  • Python 变量和数据类型
  • DeepSeek-R1 大模型基于 MS-Swift 框架的部署、推理与微调实践
  • Git 版本控制系统入门与核心命令
  • GitHub Copilot 插件无法加载模型问题排查
  • Python 27 个常见问题解答与核心概念解析
  • React Native 热更新方案:现状与选型分析
  • VSCode 中关闭 GitHub Copilot 功能的两种方法
  • 用 Spring Boot 在 Java 里搭 AI Agent 体系
  • 二分算法实战:A-B 数对与高考志愿问题解析
  • GitHub Copilot 在 VSCode 中的使用指南
  • GitHub Copilot:Python 开发者的智能编码助手
  • Vue3 开发主流 AI 代码助手推荐与配置指南
  • C++ 异常处理机制详解
  • GitHub 学生开发者认证流程及 Copilot 免费使用指南
  • JavaScript 基础语法与 jQuery 入门指南
  • Java 多线程基础:Thread 类与创建方式
  • VS Code 中 GitHub Copilot 代理与 AI 编程实战指南

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online