学习笔记-架构的演进之k8s的存储设计-3月day09

前言

Kubernetes 在规划持久化存储能力的时候,依然遵循着它的一贯设计哲学,用户负责以资源和声明式 API 来描述自己的意图,Kubernetes 负责根据用户意图来完成具体的操作。但是,描述清楚用户的存储意图,也不是一件容易的事情,相比 Kubernetes 提供的其他能力的资源,它内置的存储资源其实格外地复杂。(可以说比较繁琐了)
通过以下围绕着“Volume”所衍生出的概念,就可见一斑:

概念:Volume、PersistentVolume、PersistentVolumeClaim、Provisioner、StorageClass、Volume Snapshot、Volume Snapshot Class、Ephemeral Volumes、FlexVolume Driver、Container Storage Interface、CSI Volume Cloning、Volume Limits、Volume Mode、Access Modes、Storage Capacity……
操作:Mount、Bind、Use、Provision、Claim、Reclaim、Reserve、Expand、Clone、Schedule、Reschedule……

Kubernetes 之所以有如此多关于存储的术语概念,最重要的原因是存储技术本来就有很多种类,为了尽可能多地兼容各种存储,Kubernetes 不得不预置了很多 In-Tree(在 Kubernetes 的代码树里)插件来对接,让用户根据自己的业务按需选择。同时,为了兼容那些不在预置范围内的需求场景,Kubernetes 也支持用户使用 FlexVolume 或者 CSI 来定制 Out-of-Tree(在 Kubernetes 的代码树之外)的插件,实现更加丰富多样的存储能力。
在这里插入图片描述

Mount 和 Volume

Mount 和 Volume 都是来源于操作系统的常用术语,Mount 是动词,表示将某个外部存储挂载到系统中;Volume 是名词,表示物理存储的逻辑抽象,目的是为物理存储提供有弹性的分割方式。
从 Docker 的 Mount 操作来看,其支持了三种挂载类型,分别是 Bind(–mount type=bind)、Volume(–mount type=volume)和 tmpfs(–mount type=tmpfs)。其中,tmpfs 主要用于在内存中读写临时数据。
在这里插入图片描述

Bind Mount 是 Docker 最早提供的(发布时就支持)挂载类型,作用是把宿主机的某个目录(或文件)挂载到容器的指定目录(或文件)下。从 Docker 17.06 版本开始,Bind 就在 Docker Swarm 中借用了–mount参数过来,这个参数默认创建的是 Volume Mount,用户可以通过明确的 type 子参数来指定另外两种挂载类型。

从 Bind Mount 到 Volume Mount,实质上是容器发展过程中对存储抽象能力提升的外在表现存储的位置并不局限只在外部宿主机,存储的介质并不局限只是物理磁盘,存储的管理也并不局限只有映射关系。

Bind Mount 只能让容器与本地宿主机之间建立某个目录的映射,那么如果想要在不同宿主机上的容器共享同一份存储,就必须先把共享存储挂载到每一台宿主机操作系统的某个目录下,然后才能逐个挂载到容器内使用,这种跨宿主机共享存储的场景如下图所示:
在这里插入图片描述
这种存储范围超越了宿主机的共享存储,配置过程却要涉及到大量与宿主机环境相关的操作。再比如,即使只考虑单台宿主机的情况,基于可管理性的需求,Docker 也完全有支持 Volume Mount 的必要,因为在 Bind Mount 的设计里,Docker 只有容器的控制权,存放容器生产数据的主机目录是完全独立的,与 Docker 没有任何关系,它既不受 Docker 保护,也不受 Docker 管理。所以这就使得数据很容易被其他进程访问到,甚至是被修改和删除。如果用户想对挂载的目录进行备份、迁移等管理运维操作,也只能在 Docker 之外靠管理员人工进行,而这些都增加了数据安全与操作意外的风险。

提出 Volume 最核心的一个目的,是为了提升 Docker 对不同存储介质的支撑能力,这同时也是为了减轻 Docker 本身的工作量。

在云计算时代,网络存储逐渐成为了数据中心的主流选择,不同的网络存储都有各自的协议和交互接口。而且,并不是所有的存储系统都适合先挂载到操作系统,然后再挂载到容器的,如果 Docker 想要越过操作系统去支持挂载某种存储系统,首先必须要知道该如何访问它,然后才能把容器中的读写操作自动转移到该位置。

Docker 把解决如何访问存储的功能模块叫做存储驱动(Storage Driver)。Docker 已经内置了市面上主流的 OverlayFS 驱动,比如 Overlay、Overlay2、AUFS、BTRFS、ZFS 等等,还提出了与 Storage Driver 相对应的 Volume Driver(卷驱动)的概念,在创建 Volume 时,指定一个与其存储系统相匹配的外部卷驱动。(如AWS EBS 的驱动,Azure File Storage 驱动等)如果在创建 Volume 时,不指定卷驱动,那默认就是 local 类型,在 Volume 中存放的数据就会存储在宿主机的/var/lib/docker/volumes/目录之中。

Static Provisioning

Kubernetes 把 Volume 分为了持久化的 PersistentVolume 和非持久化的普通 Volume 两类。

普通 Volume 的设计目标并不是为了持久地保存数据,而是为同一个 Pod 中多个容器提供可共享的存储资源,所以普通 Volume 的生命周期非常明确,也就是与挂载它的 Pod 有着相同的生命周期。普通 Volume 不具备持久化的存储能力,但至少比 Pod 中运行的任何容器的存活期都更长,Pod 中不同的容器能共享相同的普通 Volume,当容器重新启动时,普通 Volume 中的数据也能够得到保留。

PersistentVolume 可以独立于 Pod 存在,生命周期与 Pod 无关,所以也就决定了 PersistentVolume 不应该依附于任何一个宿主机节点,否则必然会对 Pod 调度产生干扰限制。在把 PersistentVolume 与 Pod 分离后,就需要专门考虑 PersistentVolume 该如何被 Pod 所引用的问题了。为此,Kubernetes 又额外设计出了 PersistentVolumeClaim 资源。
PersistentVolume 是由管理员(运维人员)负责维护的,用户(开发人员)通过 PersistentVolumeClaim,来匹配到合乎需求的 PersistentVolume。

PersistentVolume & PersistentVolumeClaim
A PersistentVolume (PV) is a piece of storage in the cluster that has been provisioned by an administrator.
A PersistentVolumeClaim (PVC) is a request for storage by a user.
PersistentVolume 是由管理员负责提供的集群存储。
PersistentVolumeClaim 是由用户负责提供的存储请求。
—— Kubernetes Reference Documentation

具体过程如下:

  1. 管理员准备好要使用的存储系统,它应该是某种网络文件系统(NFS)或者云储存系统,一般来说应该具备跨主机共享的能力。
  2. 管理员会根据存储系统的实际情况,手工预先分配好若干个 PersistentVolume,并定义好每个 PersistentVolume 可以提供的具体能力。
  3. 用户根据业务系统的实际情况,创建 PersistentVolumeClaim,声明 Pod 运行所需的存储能力。
  4. Kubernetes 在创建 Pod 的过程中,会根据系统中 PersistentVolume 与 PersistentVolumeClaim 的供需关系,对两者进行撮合,如果系统中存在满足 PersistentVolumeClaim 声明中要求能力的 PersistentVolume,就表示撮合成功,它们将会被绑定。而如果撮合不成功,Pod 就不会被继续创建,直到系统中出现新的、或让出空闲的 PersistentVolume 资源。
    在这里插入图片描述

Kubernetes 对 PersistentVolumeClaim 与 PersistentVolume 撮合的结果是产生一对一的绑定关系,“一对一”的意思是 PersistentVolume 一旦绑定在某个 PersistentVolumeClaim 上,直到释放以前都会被这个 PersistentVolumeClaim 所独占,不能再与其他 PersistentVolumeClaim 进行绑定。这意味着即使 PersistentVolumeClaim 申请的存储空间比 PersistentVolume 能够提供的要少,依然要求整个存储空间都为该 PersistentVolumeClaim 所用,这有可能会造成资源的浪费。

Dynamic Provisioning

对于中小规模的 Kubernetes 集群,PersistentVolume 已经能够满足有状态应用的存储需求。PersistentVolume 依靠人工介入来分配空间的设计虽然简单直观,却算不上是先进,一旦应用规模增大,PersistentVolume 很难被自动化的问题就会凸显出来。

这是由于 Pod 创建过程中需要去挂载某个 Volume 时,都要求该 Volume 必须是真实存在的,否则 Pod 启动可能依赖的数据(如一些配置、数据、外部资源等)都将无从读取。Kubernetes 虽然有能力随着流量压力和硬件资源状况,自动扩缩 Pod 的数量,但是当 Kubernetes 自动扩展出一个新的 Pod 后,并没有办法让 Pod 去自动挂载一个还未被分配资源的 PersistentVolume。

想解决这个问题,要么允许多个不同的 Pod 都共用相同的 PersistentVolumeClaim,这种方案确实只靠 PersistentVolume 就能解决,却损失了隔离性,难以通用;要么就要求每个 Pod 用到的 PersistentVolume 都是已经被预先建立并分配好的,这种方案靠管理员提前手工分配好大量的存储也可以实现,却损失了自动化能力。

Dynamic Provisioning 方案是指在用户声明存储能力的需求时,不是期望通过 Kubernetes 撮合来获得一个管理员人工预置的 PersistentVolume,而是由特定的资源分配器(Provisioner)自动地在存储资源池或者云存储系统中分配符合用户存储需要的 PersistentVolume,然后挂载到 Pod 中使用,完成这项工作的资源被命名为 StorageClass,它的具体工作过程如下:

  1. 管理员根据储系统的实际情况,先准备好对应的 Provisioner。Kubernetes 官方已经提供了一系列预置的 In-Tree Provisioner,放置在kubernetes.io的 API 组之下。
  2. 管理员不再是手工去分配 PersistentVolume,而是根据存储去配置 StorageClass。Pod 是可以动态扩缩的,而存储则是相对固定的,哪怕使用的是具有扩展能力的云存储,也会将它们视为存储容量、IOPS 等参数可变的固定存储来看待,比如你可以将来自不同云存储提供商、不同性能、支持不同访问模式的存储配置为各种类型的 StorageClass,这也是它名字中“Class”(类型)的由来。
  3. 用户依然通过 PersistentVolumeClaim 来声明所需的存储,但是应在声明中明确指出该由哪个 StorageClass 来代替 Kubernetes 处理该 PersistentVolumeClaim 的请求。
  4. 如果 PersistentVolumeClaim 中要求的 StorageClass 及它用到的 Provisioner 均是可用的话,那这个 StorageClass 就会接管掉原本由 Kubernetes 撮合的 PersistentVolume 和 PersistentVolumeClaim 的操作,按照 PersistentVolumeClaim 中声明的存储需求,自动产生出满足该需求的 PersistentVolume 描述信息,并发送给 Provisioner 处理。
  5. Provisioner 接收到 StorageClass 发来的创建 PersistentVolume 请求后,会操作其背后存储系统去分配空间,如果分配成功,就生成并返回符合要求的 PersistentVolume 给 Pod 使用。
    在这里插入图片描述
    相较于 Dynamic Provisioning,Static Provisioning 的主要使用场景就局限于管理员能够手工管理存储的小型集群,它符合很多小型系统,尤其是私有化部署系统的现状,但并不符合当今运维自动化所提倡的思路。Static Provisioning 的存在,某种意义上也可以视为是对历史的一种兼容,在可见的将来,Kubernetes 肯定还是会把 Static Provisioning 作为用户分配存储的一种主要方案,来供用户选用。

此文章为3月Day09学习笔记,内容来源于极客时间《周志明的软件架构课

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值