关于golang:JuiceFS-CSI-Driver-的最佳实践

6次阅读

共计 6401 个字符,预计需要花费 17 分钟才能阅读完成。

文章依据 Juicedata 工程师朱唯唯,在云原生 Meetup 杭州站所作主题演讲《JuiceFS CSI Driver 的最佳实际》整顿而成。

大家好,我是来自 Juicedata 的朱唯唯,当初次要负责 JuiceFS CSI Driver 方面的开发,很快乐明天有这个机会跟大家做一个分享和交换,我明天分享的题目是“JuiceFS CSI Driver 的最佳实际”。次要会从以下几个方面给大家做一个分享:

  • Kubernetes 存储计划
  • 如何在 Kubernetes 中应用 JuiceFS
  • JuiceFS CSI Driver 架构设计实际

Kubernetes 存储计划

在 Kubernetes 外面对存储有三个概念,第一个是 PV,也就是长久卷,代表的是集群中的一份存储,能够定义存储的类型、大小等,比方指定它是哪一种类型,NFS 或 GlusterFS,也能够指定它是 CSI 的。第二个概念是 PVC,长久卷申明,代表的是 Pod 应用存储的一份申请,Pod 不间接应用 PV 而是通过 PVC 来应用 PV。另一个是 StorageClass,长久卷类型,代表的是集群中的存储类型,它不定义存储的大小,只定义类型,在应用的时候 Kubernetes 会依据 StorageClass 主动创立 PV。以上就是 Kubernetes 对 Pod 应用存储所定义的三种资源。

apiVersion: v1                     aversion: v1                     apiVersion: v1
kind: PersistentVolume             kind: PersistentVolumeClaim      kind: Pod
metadata:                          metadata:                        metadata:
  name: pv0001                       name: myclaim                   name: pv-recycler
  labels:                          spec:                            spec:
    pv: pv0001                      accessModes                      containers:
spec:                                - ReadWriteMany                 - name: pv-recycler
  capacity:                         volumeMode: Filesystem           image: "nginx"
    storage: 5Gi                    resources                        volumeMounts:
  volumeMode: Filesystem             requests:                       - name: my-volume
  accessModes:                        storage: 5Gi                    mountPath: /root/data
    - ReadWriteMany                 selector:                        volumes:
  hostPath:                          matchLabels:                     - name: my-volume
    path: /root/data/test             pv: pv0001                        persistentVolumeClaim:
                                                                           claimName: myclaim

咱们再来看一下在 Kubernetes 中 Pod 怎么应用存储,次要有两种形式,第一种是动态存储,就是 PV 加 PVC 的形式,能够看上图的几个 yaml 文件,第一个就是 PV 的 yaml 文件。个别由系统管理员先在集群中创立一份 PV,而后在应用的时候创立一个 PVC,指定应用哪个 PV,然而一个 PV 只能被一个 Pod 应用,每当有新的 Pod 须要应用存储时,系统管理员也要创立相应的 PV,并在 PV 外面是指定它有多大的存储量,用什么样的拜访形式以及它是什么类型的,文中给进去的例子就是 hostPath,当然也能够在这里指定它为 Kubernetes 内置的一些存储类型,比方 NFS、CSI,如果是 CSI 的话,那就须要咱们第三方去实现对于 CSI 的一个插件。

PV 定义好了之后,在集群外面就代表有这么一份存储能够用,当 Pod 在应用该 PV 的时候,须要用户提前先去建设一个 PVC 的资源,而后在 PVC 中去指定用什么样的形式去拜访存储,以及须要用多大的容量,当然这个容量不能超过 PV 中指定的已有容量。也能够用 label select 的形式去指定这个 PVC 应用哪个 PV,以上就实现了一个 PVC 资源的创立。

当 PVC 创立好了之后 Pod 就能够间接应用了,应用的形式就是当挂载在 volume 的时候指定一下 Claim 是哪一个 PVC 就能够了。这是动态存储的计划,然而这种计划有一个问题,一个 PV 只能被一个 PVC 应用,当 Pod 被运行起来在应用 PV 的时候,PV 的状态也就会被 Kubernetes 改成 Bound 状态,它一旦是 Bound 状态,另一个 Pod 的 PVC 就不能应用了。那也就意味着每当有新的 Pod 须要应用存储时,系统管理员也要创立相应的 PV,可想而知系统管理员的工作量会很大。

apiVersion: storage.k8s.io/v1           aversion: v1                        apiVersion: v1
kind: StorageClass                      kind: PersistentVolumeClaim         kind: Pod
metadata:                               metadata:                           metadata:
  name: example-nfs                      name: myclaim                       name: pv-recycler
provisioner: example.com/external-nfs   spec:                               spec:
parameters:                              accessModes:                        containers:
  server: nfs-server.example.com          - ReadWriteMany                    - name: pv-recycler
  path: /share                           volumeMode: Filesystem                image: "nginx"
  readOnly: false                        resources:                            volumeMounts:
                                          requests:                            - name: my-volume
                                           storage: 5Gi                        mountPath: /root/data
                                         storageClassName: example-nfs        volumes:
                                                                               - name: my-volume
                                                                                 persistentVolumeClaim:
                                                                                  claimName: myclaim

另一种形式是动静存储,动静存储的形式就是 StorageClass + PVC 应用形式也相似,就是系统管理员先在集群中创立一份 StorageClass,只需指定存储类型,以及它的一些拜访参数。在 Pod 在应用的时候仍然是创立一个 PVC 指定它须要应用多大容量以及它的拜访形式,再指定 StorageClass,而后 Pod 外面应用和上文是一样的。但在该计划中当 Kubernetes 在创立 Pod 之前会依据 StorageClass 中指定的类型和 PVC 中指定的容量大小等参数,主动创立出对应的 PV,这种形式相比之下解放了系统管理员。

无论是 PV 还是 StorageClass,在指定存储类型的时候,能够应用 Kubernetes 内置的存储类型,比方 hostPath、NFS 等,还有一种形式就是 CSI,第三方云厂商通过实现 CSI 接口来为 Pod 提供存储服务。JuiceFS 也实现了本人的 CSI Driver。

什么是 JuiceFS

JuiceFS 是一款面向云环境设计的高性能共享文件系统,能够被多台主机同时挂载读写,应用对象存储来作为底层的存储层,咱们没有反复造轮子,而是抉择了站在对象存储的肩膀上。对象存储大家都晓得它有很多益处,一个是高价排量、高吞吐、高可用性,然而它同时也有很多毛病,比方很重要的一点就是它没有目录的治理能力,对于文件系统来说,用户拜访起来不是很不便,同时它就只有 HTTP 接口,并且是依照调用次数免费的。

针对对象存储的这种问题,咱们引入了元数据服务,通过这形式咱们能够在对象存储的根底上提供齐备的 POSIX 兼容性。咱们对外提供各种各样的接口,包含 POSIX 接口,各种网络存储协定以及各种各样的 SDK,通过这样的一种架构,咱们能够将海量高价的云存储作为本地磁盘应用成为了一种可能。

如何在 Kubernetes 中应用 JuiceFS?

Kubernetes 是目前最风行的一种利用编排引擎,将资源池化,使得用户不再须要关怀底层的基础设施和根底资源,这一点 JuiceFS 的设计理念是雷同的。同时 Kubernetes 也提供了一些申明式 API 并且它的可拓展性很强,它提供了一种 CSI 的一种接入形式,让 JuiceFS 能够很不便的接入进来,

在 Kubernetes 中应用 JuiceFS 非常简略,咱们提供了两种装置形式,helm chart 装置和 Kubernetes yaml 间接 apply,任意一种形式都能够做到一键装置部署。而后再筹备一个元数据引擎和对象存储服务就能够间接通过 Kubernetes 原生形式,在 Pod 里间接应用 Juicefs 类型的存储了。

在 KubeSphere 中应用 JuiceFS 就更简略了。在界面上通过「利用模板」上传 chart 包或者在「利用仓库」中增加 JuiceFS 的官网 chart 仓库地址,就能够间接装置 Juicefs CSI Driver 了,而后在 KubeSphere 中应用和原生的 Kubernetes 应用形式是一样的,后续咱们会把 JuiceFS 做为 Kubesphere 的原生插件,在部署 Kubesphere 之后即可间接应用,大家能够期待一下。

CSI 工作原理

如果大家平时应用过 CSI 或者接触过它的一些原理的话,咱们会晓得它其实很简单,CSI 的官网提供了很多插件,次要有两种形式,一种是 CSI 外部的组件,另一种是内部的,外部的话咱们在这里就不介绍了,咱们只介绍内部的两类插件,一类是须要咱们本人去实现的插件,CSI ControllerCSI NodeCSI Identity,还有一类就是官网提供的一些 SideCar,这些 SideCar 全部都是配合以上三个插件去实现存储的所有性能。

CSI Controller,它是以 deployment 的模式运行在集群外面,次要负责 provision 和 attach 工作。当然 attach 不是每一个存储都会用到的,而 provision 就是在应用 StorageClass 的时候会动态创建 PV 的过程,所以 CSI Controller 在实现 provision 这个性能的时候,是 external-provisioner 这个 SideCar 去配合实现的,在实现 attach 性能的时候是 external-attacher 配合它一起实现的。

CSI NodeCSI Identity 通常是部署在一个容器外面的,它们是以 daemonset 的模式运行在集群外面,保障每一个节点会有一个 Pod 部署进去,这两个组件会和 CSI Controller 一起实现 volume 的 mount 操作。CSI Identity 是用来通知 Controller,我当初是哪一个 CSI 插件,它实现的接口会被 node-driver-registrar 调用给 Controller 去注册本人。CSI Node 会实现一些 publish volumeunpublished volume 的接口,Controller 会去调用来实现 volume 的 mount 的操作,咱们只须要实现这几个插件的接口就能够了。

Provision 过程

上文介绍的 Kubernetes 中的动静存储计划,是管理员只须要创立 StorageClass,而后用户创立 PVC,由 Kubernetes 主动的帮你创立 PV 的这么一个过程,其中具体的流程如上图所示,首先是 PVController 会去向 API Server 监听 PVC 资源的创立,它监听到 PVC 资源的创立会给 PVC 打上一个注解,注解里通知 Kubernetes 是当初 PVC 应用的是哪一个 CSI 而后同时 external-provisioner 这个 SideCar 也会去监听 PVC 的资源,如果注解信息和本人的 CSI 是一样的话,它就会去调用 CSI controller 的接口去实现创立 volume 的逻辑,这个接口调用胜利之后,external-provisioner 就会认为 volume 曾经创立好了,而后就会去对应的创立 PV。

Mount 过程

PV 创立好了之后就到了 Mount 的过程,还是那张图,然而调用接口不一样,在 Mount 过程中参加的组件是 KubeletCSI NodeKubelet 在创立 Pod 之前会去帮它筹备各种各样的运行环境,包含须要申明存储的环境,这些环境筹备好之后 Kubelet 才会去创立 Pod,那么筹备 volume 的环境就是 Kubelet 去调用 CSI Node Plugin 的接口去实现的,在这个接口外面去实现 volume 的 mount 过程就实现了整个 Pod 所须要的一些存储环境。这些整个实现之后,Kubelet 的才会创立 Pod。

JuiceFS CSI Driver 的设计

CSI Driver 遇到的挑战

JuiceFS CSI Driver 最后的架构设计是这样的,咱们实现了 CSI 的几个接口和常见的根本一样,不同的就是咱们在 NodeService 组件外面,咱们会去实现 JuiceFS mount 这个过程。

因为 JuiceFS 是用户态文件系统,CSI 在实现 Mount 工作的时候,首先是会在节点上创立一个挂载点,同时会 fork 出一个 mount 过程,也就是 JuiceFS 客户端。而过程它是间接运行在 CSI Node 的 Pod 里的,挂载点筹备好之后,咱们还会在接口外面把这个机器上的挂载点 bind 到 kubelet target 门路。这个过程间接运行在 CSI Pod 里,有多少 Volume 就会有多少过程同时运行在这个 Pod 里,这样的实现就会带来一系列的问题。

首先,JuiceFS 客户端之间没有资源隔离,而且过程间接运行在 CSI Pod 里会导致 Kubernetes 集群对客户端过程无感知,当客户端过程意外退出的时候,在集群中是看不出任何变动的;最要害的是 CSI Driver 不能平滑降级,降级的惟一形式就是,先把用户所有应用到 JuiceFS 的 Pod 全副停掉,而后降级,降级完再把所有的业务 Pod 一个个再运行起来。这样的降级形式对于运维同学来说几乎是劫难;另外一个问题是 CSI Driver 的爆炸半径过大,跟第三点相似,CSI Driver 一旦退出,那运行在外面的 JuiceFS 客户端都不能失常应用。

CSI Driver 架构降级

针对这些问题,咱们对 CSI Driver 的架构设计进行了一些改良。具体的做法就是将执行 volume 挂载的操作在独自的 Pod 里执行,这样 fork 进去的过程就能够运行在 Pod 里了。如果有多个的业务 Pod 共用一份存储,mount Pod 会在 annotation 进行援用计数,确保不会反复创立。每当有业务 Pod 退出时,mount Pod 会删除对应的计数,只有当最初一个记录被删除时 mount Pod 才会被删除。还有一点是 CSI Node 会通过 APIService watch mount Pod 的状态变动,以治理其生命周期。咱们一旦察看到它意外退出,及它 Pod 的退出了,然而它的 annotation 还有计数,证实它是意外退出,并不是失常的一个被删除,这样的话咱们会把它从新起来,而后在业务的容器的 target 门路从新执行 mount bind,这是咱们目前还在开发的一个性能。

架构降级的好处

  1. 最间接的益处就是 CSI Driver 被解耦进去了,CSI driver 无论做什么操作都不会影响到客户端,做降级不会再影响到业务容器了,
  2. 将 JuiceFS 客户端独立在 Pod 中运行也就使其在 Kubernetes 的管控内,可观测性更强;
  3. 同时 Pod 的益处咱们也能享受到,比方隔离性更强,能够独自设置客户端的资源配额等。

将来瞻望

对于将来咱们还会去做一些工作,目前咱们把 JuiceFS 客户端的过程运行在独自的 Pod 里,然而对于 FUSE 过程在容器环境的高可用性仍然存在很大的挑战,这也是咱们今后会始终关注探讨的问题。另外咱们也在继续摸索对于 JuiceFS 在云原生环境更多的可能性,比方应用形式下面除了 CSI 还会有 Fluid、Paddle-operator 等形式。

举荐浏览:
百亿级小文件存储,JuiceFS 在主动驾驶行业的最佳实际

我的项目地址 :Github(https://github.com/juicedata/juicefs)如有帮忙的话 欢送关注咱们哟! (0ᴗ0✿)

正文完
 0