【技术·真相谈一谈K8S的存储(一)

2023年 8月 18日 54.3k 0

自以为什么都懂的人不可能开始学习。

郑重说明:本文适合对游戏开发感兴趣的初级及中级开发和学习者,本人力图将技术用简单的语言表达清楚。鉴于水平有限,能力一般,文章如有错漏之处,还望批评指正,谢谢。

一、背景

图灵机,一开始就是模拟人来做计算问题,信息通过无限长度的纸带来写入或者擦除,纸带就是最初的临时存储设备。

image.png

后来通用计算机问世,势必需要记录信息,于是又发明了专门用来做存储的部件。存储部件可以用来存储计算用的指令(程序)和数据(运算的输入或者输出)。

通用计算机有计算部件,如 CPU、内存。如何发起计算呢? 其实就是写好程序,启动进程,来利用计算部件如 CPU 和内存来做计算;如果进程运行结束了,我们还需要运算的结果,可以存储在文件中。

还有存储部件,如硬盘。

k8s 的更宏观的生态也有计算与存储。

可以把 pod 及里面的容器理解为计算部件,那么 k8s 势必也需要存储。

pod 和容器 会停止、会被调度到别的机器,其附带的信息也需要能跟着带过去。

二、预备知识

2.1 存储分类

  • 单机块存储

  • 集中式存储,如企业级 EMC 存储

  • 分布式存储

  • 对象存储 OSS

2.2 文件系统

文件系统是用来管理硬件上的存储空间的软件系统,类似于仓库中的货架:

image.png

文件系统可以分为以下几类

  • 本地文件系统,如 Ext4、Fat32 等,本地计算机访问的文件系统
  • 网络文件系统,如 NFS(数据集中在网络上某个服务器),这样可以通过网络访问非本机的存储,一般是在同一个局域网内

image.png

  • 分布式文件系统(Distributed file system, DFS),数据和 NFS 存在单一节点上不同,分布式文件系统的数据分布在多个节点上

典型的分布式文件系统如 Ceph、GlusterFS,通过对应的 client 来决定数据应该存储到哪个服务器节点上

此外,大数据用的 GFS、HDFS 也属于分布式文件系统,只不过数据分片和服务器节点有专门的 namenode 服务器来管理

三、k8s 存储的演进

3.1 Volume

Volume 的提出

容器的存储存在以下两个问题:

  • 容器内部存储的生命周期是短暂的,会随着容器环境的销毁而销毁,具有不稳定性
  • 如果多个容器希望共享同一份存储,则仅仅依赖容器本身是很难实现的

在Kubernetes系统中,将对容器应用所需的存储资源抽象为存储卷(Volume)这个资源来解决这些问题。

Volume是与 Pod 绑定的(独立于容器)与Pod具有相同生命周期的资源对象。

我们可以将 Volume 的内容理解为目录或文件,容器如需使用某个Volume,则仅需设置 volumeMounts 将一个或多个 Volume 挂载为容器中的目录或文件,即可访问 Volume 中的数据。

Volume具体是什么类型,以及由哪个系统提供,对容器应用来说是透明的。

资源关系图:

配置方式如下:

apiVersion: v1
kind: Pod
metadata:
  name: rbd
spec:
  containers:
    volumeMounts:
       ...
  volumes:
       ...

Volume 的类型

k8s 支持的 volume 类型有多种,他们都可以以存储卷 volume 的形式挂载到容器中,成为目录或文件,如下图:

  • k8s 内部的一些资源,包括

    • configmap,应用的配置
    • secret,密钥文件
    • downward api,Pod 或 容器的元数据
    • ServiceAccountToken
    • Projected Volume
  • pod 宿主机本地目录,包括

    • EmptyDir,临时存储
    • hostPath,主机上的某个目录
  • 持久化存储卷

    • 本地持久化块存储(本地各 node 节点中实现)
    • 网络文件存储,如 NFS
    • 分布式文件存储,如 Ceph,GlusterFS 等
    • 存储厂商存储,如 EMC 的存储
    • 公有云持久化存储,一般是块存储(需要使用者自己格式化成特定文件系统)

所谓 “持久化” 的存储卷 Volume,是相对于普通的 Volume 来说的,指的是该宿主机上得目录具有持久性,即该目录里的内容既不会因为容器的删除而被清理,也不会跟当前的宿主机绑定。当容器重启或者在其他节点重建之后,它仍然能通过挂载这个 Volume 访问到这些内容。前面说的宿主机本地目录 EmptyDir 和 hostPath 不具有这个特征。

对于需要持久化的 Volume,volume 中的参数非常多,部署时候用户需要知道一大堆的参数,而且不同 volume 还不一样,非常麻烦。此外,用户 Pod 中 的 volumes 中暴露过多存储组件相关的信息,也会带来安全隐患。

为此,k8s 中引入了 pv/pvc 来做部署上的解耦。(看,又是经典的引入中间层)

3.2 PV/PVC

引入一种新的资源: PV/PVC 做持久化存储后关系如下:

PV

PV 是对持久化的存储资源的抽象,由具体的存储提供商实现。

它通过插件化的机制进行管理。面向的是系统管理人员,不需要用户知道细节。

PVC

PVC 是用户对存储资源的申请,就像 Pod 消耗 Node 的CPU和内存资源一样,PVC 消耗 PV 的磁盘空间资源。

用户只需要说明申请的大小和访问模式 。

详细资源关系图

PV 的生命周期和使用它的 Pod 是相互独立的,一个 PV 任一时刻只能被一个 Pod (通过pvc)使用,但释放后又可以被其他 Pod 使用。

此时,Pod 里加入 pvc 字段来引入( Pod.volumes → pvc ),如:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pv-claim
spec:
  accessModes:
    - ReadWriteOnce
    resources:
        requests:
            storage: 1Gi

apiVersion: v1
kind: Pod
metadata:
  name: rbd
spec:
  containers:
    volumeMounts:
    ...
  volumes:
    - name: my-pv
      persistentVolumeClaim: #pvc
          claimName: pv-claim

通过PVC/PV解决了开发者使用存储的困难,但是没有解决运维人员管理存储的困难。创建 pv 的工作还是很繁琐。

3.3 StorageClass

通过引入 StorageClass 来做 provision,可以动态创建网络存储和pv,省去了手动创建 pv 的麻烦。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: block-service
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-ssd

详细资源关系图V2

现在拓扑结构和部署目前都没有问题了,但还需要考虑代码维护的问题。

如果我们的存储资源使用的是持久化存储,而不同的存储有不同的实现,如果代码全部放到 k8s 代码库里一起发布、测试,类似下面虚线框:

这样非常不方便。需要把持久化存储的代码隔离开来。

3.4 FlexVolume插件机制

于是提供一种抽象层,使得新增的存储插件不必和 k8s 主干一起演进和测试。随后就引入了FlexVolume这种 Volume 类型。

但这种做法也有个问题:

实际执行插件代码时,是 k8s 来直接调用机器上的插件二进制/脚本程序。

当你编写完了 FlexVolume 插件的实现之后,一定要手动把它的可执行文件放在每个Node节点的插件目录下(/usr/libexec/kubernetes/kubelet-plugins/volume/exec)。

这就很麻烦了。

还有一些其他问题,比如,这些插件都是一次性的操作,挂载和反挂载的可执行程序都是独立的,没法交换一些中间的信息。

3.5 CSI 标准插件

于是社区又提出了CSI方案,彻底把存储插件的管理逻辑 和 k8s 解耦开来:

  • 代码上,把k8s用来挂载存储(动态provision、attach等)的代码从k8s主干分支中抽离出来,放在kubernetes-csi这个项目中。代码抽离出来之后,就可以做成单独的镜像来使用了。
  • 部署上,不需要手动在节点上安装可执行文件,而采用 k8s 常规的方式拉取镜像来部署一个插件服务。k8s 和插件通过接口/协议的形式来调用,而不是直接调用二进制代码。
  • 代码管理及部署关系如下:

    小结

    本文,我们介绍了 k8s 中存储有关的一些概念,提出的这些概念的背景和演化历程。希望对大家更好的使用和理解 k8s 有帮助。

    作者:我是码财小子,会点编程代码,懂些投资理财;期待你的关注,不要错过我后续的文章更新。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论