K8s & K3s 集群中持久化存储方案选型
存储架构
1 三个概念: pv , pvc ,storageclass
- pv - 持久化卷, 支持本地存储和网络存储, 例如hostpath,ceph rbd, nfs等,只支持两个属性, capacity和accessModes。其中capacity只支持size的定义,不支持iops等参数的设定,accessModes有三种,ReadWriteOnce(被单个node读写), ReadOnlyMany(被多个nodes读), ReadWriteMany(被多个nodes读写)
- pvc - 对pv或者storageclass资源的请求, pvc 对 pv 类比于pod 对不同的cpu, mem的请求。
- storageclass-另外一种提供存储资源的方式, 提供更多的层级选型, 如iops等参数。 但是具体的参数与提供方是绑定的。 如aws和gce它们提供的storageclass的参数可选项是有不同的。
2 三种PV的访问模式
- ReadWriteOnce:是最基本的方式,可读可写,但只支持被单个Pod挂载。
- ReadOnlyMany:可以以只读的方式被多个Pod挂载。
- ReadWriteMany:这种存储可以以读写的方式被多个Pod共享。
不是每一种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是NFS。在PVC绑定PV时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式。
3 三个重声明策略(reclaim policy)
- Retain – 手动重新使用
- Recycle – 基本的数据擦除 (“rm -rf /thevolume/*”)
- Delete – 相关联的后端存储卷删除, 后端存储比如AWS EBS, GCE PD, Azure Disk, or OpenStack Cinder
需要特别注意的是只有本地盘和nfs支持数据盘Recycle 擦除回收, AWS EBS, GCE PD, Azure Disk, and Cinder 存储卷支持Delete策略
4 四个阶段(volumn phase)
一个存储卷会处于下面几个阶段中的一个阶段:
- Available –资源可用, 还没有被声明绑定
- Bound – 被声明绑定
- Released – 绑定的声明被删除了,但是还没有被集群重声明
- Failed – 自动回收失败
5 四个PV选择器
在PVC中绑定一个PV,可以根据下面几种条件组合选择
- Access Modes, 按照访问模式选择pv
- Resources, 按照资源属性选择, 比如说请求存储大小为8个G的pv
- Selector, 按照pv的label选择
- Class, 根据StorageClass的class名称选择, 通过annotation指定了Storage Class的名字, 来绑定特定类型的后端存储
6 五个可移植性建议
- 把你的 pvc,和 其它一系列配置放一起, 比如说deployment,configmap
- 不要把你的pv放在其它配置里, 因为用户可能没有权限创建pv
- 初始化pvc 模版的时候, 提供一个storageclass
- 在你的工具软件中,watch那些没有bound的pvc,并呈现给用户
- 集群启动的时候启用DefaultStorageClass, 但是不要指定某一类特定的class, 因为不同provisioner的class,参数很难一致
7 六个生命周期: Provisioning, Binding, Using, Releasing, Reclaiming, Recycling
k8s对pv和pvc之间的交互的生命周期进行管理。
- provisioning- 配置阶段, 分为static, dynamic两种方式。静态的方式是创建一系列的pv,然后pvc从pv中请求。 动态的方式是基于storageclass的。
- Binding - 绑定阶段, pvc根据请求的条件筛选并绑定对应的pv。 一定pvc绑定pv后, 就会排斥其它绑定,即其它pvc无法再绑定同一个pv,即使这个pv设定的access mode允许多个node读写。 此外 ,pvc 如何匹配不到相应条件的pv, 那么就会显示unbound状态, 直到匹配为止。 需要注意的是,pvc请求100Gi大小的存储,即使用户创建了很多50Gi大小的存储, 也是无法被匹配的。
- Using- 使用阶段, pods 挂载存储, 即在pod的template文件中定义volumn使用某个pvc。
- Releasing - 释放阶段, 当pvc对象被删除后, 就处于释放阶段。 在这个阶段, 使用的pv还不能被其它的pvc请求。 之前数据可能还会留存下来, 取决于用户在pv中设定的policy, 见persistentVolumeReclaimPolicy。
- Reclaiming - 重声明阶段。 到这个阶段, 会告诉cluster如何处理释放的pv。 数据可能被保留(需要手工清除), 回收和删除。动态分配的存储总是会被删除掉的。
- Recycling - 回收阶段。回收阶段会执行基本的递归删除(取决于volumn plugins的支持),把pv上的数据删除掉, 以使pv可以被新的pvc请求。 用户也可以自定义一个 recycler pod , 对数据进行删除。
8 九个PV Plugins
pv是以plugin的形式来提供支持的, 考虑到私有云的使用场景, 排除掉azure, aws,gce等公有云厂商绑定的plugin, 有9个插件值得关注。这些plugin所支持的accessmode是不同的。 分别是
image
存储方案
共享存储为分布式系统非常重要的一部分,存储一般要求稳定、可用、性能、可靠。
1 用户角度
存储就是一块盘或者一个目录,用户不关心盘或者目录如何实现,用户要求非常“简单”,就是稳定,性能好。为了能够提供稳定可靠的存储产品,各个厂家推出了各种各样的存储技术和概念。
2 存储介质
存储介质分为机械硬盘和固态硬盘(SSD)。机械硬盘泛指采用磁头寻址的磁盘设备,包括SATA硬盘和SAS硬盘。由于采用磁头寻址,机械硬盘性能一般,随机IOPS一般在200左右,顺序带宽在150MB/s左右。固态硬盘是指采用Flash/DRAM芯片+控制器组成的设备,根据协议的不同,又分为SATA SSD,SAS SSD,PCIe SSD和NVMe SSD。
3 产品定义
存储分为本地存储(DAS),网络存储(NAS),存储局域网(SAN)和软件定义存储(SDS)四大类
- DAS就是本地盘,直接插到服务器上
- NAS是指提供NFS协议的NAS设备,通常采用磁盘阵列+协议网关的方式
- SAN跟NAS类似,提供SCSI/iSCSI协议,后端是磁盘阵列
- SDS是一种泛指,包括分布式NAS(并行文件系统),ServerSAN等
4 应用场景
存储分为文件存储(Posix/MPI),块存储(iSCSI/Qemu)和对象存储(S3/Swift)三大类
Kubernetes是如何给存储定义和分类呢?Kubernetes中跟存储相关的概念有PersistentVolume (PV)和PersistentVolumeClaim(PVC),PV又分为静态PV和动态PV。静态PV方式如下:
image
动态PV需要引入StorageClass的概念,使用方式如下:
image
社区列举出PersistentVolume的in-tree Plugin,如下图所示。从图中可以看到,Kubernetes通过访问模式给存储分为三大类,RWO/ROX/RWX。这种分类将原有的存储概念混淆,其中包含存储协议,存储开源产品,存储商业产品,公有云存储产品等等。 image
如何将Kubernetes中的分类和熟知的存储概念对应起来呢?本文选择将其和应用场景进行类比。
块存储通常只支持RWO,比如AWSElasticBlockStore,AzureDisk,有些产品能做到支持ROX,比如GCEPersistentDisk,RBD,ScaleIO等
文件存储(分布式文件系统)支持RWO/ROX/RWX三种模式,比如CephFS,GlusterFS和AzureFile
对象存储不需要PV/PVC来做资源抽象,应用可以直接访问和使用
多种多样的应用场景,介绍完存储概念之后,选择哪种存储仍然悬而未决。这个时候,请问自己一个问题,业务是什么类型?选择合适的存储,一定要清楚自己的业务对存储的需求。本文整理了使用容器存储的场景及其特点。
-
配置
无论集群配置信息还是应用配置信息,其特点是并发访问,也就是前边提到的ROX/RWX,在不同集群或者不同节点,都能够访问同样的配置文件,分布式文件存储是最优选择。 -
日志
在容器场景中,日志是很重要的一部分内容,其特点是高吞吐,有可能会产生大量小文件。如果有日志分析场景,还会有大量并发读操作。分布式文件存储是最优选择。 -
应用(数据库/消息队列/大数据)
Kafka,MySQL,Cassandra,PostgreSQL,ElasticSearch,HDFS等应用,本身具备了存储数据的能力,对底层存储的要求就是高IOPS,低延迟。底层存储最好有数据冗余机制,上层应用就可以避免复杂的故障和恢复处理。以HDFS为例,当某个datanode节点掉线后,原有逻辑中,会选择启动新的datanode,触发恢复逻辑,完成数据副本补全,这段时间会比较长,而且对业务影响也比较大。如果底层存储有副本机制,HDFS集群就可以设置为单副本,datanode节点掉线后,启动新的datanode,挂载原有的pv,集群恢复正常,对业务的影响缩短为秒级。高性能分布式文件存储和高性能分布式块存储是最优选择。
- 备份
应用数据的备份或者数据库的备份,其特点是高吞吐,数据量大,低成本。文件存储和对象存储最优。
综合应用场景,高性能文件存储是最优选择,形形色色的存储产品
市面上的存储产品种类繁多,但是对于容器场景,主要集中在4种方案:分布式文件存储,分布式块存储,Local-Disk和传统NAS。
分布式块存储包括开源社区的Ceph,Sheepdog,商业产品中EMC的Scale IO,Vmware的vSAN等。分布式块存储不适合容器场景,关键问题是缺失RWX的特性。
分布式文件存储包括开源社区的Glusterfs,Cephfs,Lustre,Moosefs,Lizardfs,商业产品中EMC的isilon,IBM的GPFS等。分布式文件存储适合容器场景,但是性能问题比较突出,主要集中在GlusterFS,CephFS,MooseFS/LizardFS。
这里简单对比下开源项目的优缺点:
image
Local-Disk方案有明显的缺点,尤其是针对数据库,大数据类的应用。节点故障后,数据的恢复时间长,对业务影响范围广。
传统NAS也是一种文件存储,但是协议网关(机头)是性能瓶颈,传统NAS已经跟不上时代发展的潮流。
多样的评估策略:
存储的核心需求是稳定,可靠,可用。无论是开源的存储项目还是商业的存储产品,评估方法具有普适性,
-
数据可靠性
数据可靠性是指数据不丢失的概率。通常情况下,存储产品会给出几个9的数据可靠性,或者给出最多允许故障盘/节点个数。评估方式就是暴力拔盘,比如说存储提供3副本策略,拔任意2块盘,只要数据不损坏,说明可靠性没问题。存储采用不同的数据冗余策略,提供的可靠性是不一样的。 -
数据可用性
数据可用性和数据可靠性很容易被混淆,可用性指的是数据是否在线。比如存储集群断电,这段时间数据是不在线,但是数据没有丢失,集群恢复正常后,数据可以正常访问。评估可用性的主要方式是拔服务器电源,再有查看存储的部署组件是否有单点故障的可能。 -
数据一致性
数据一致性是最难评估的一项,因为大部分场景用户不知道程序写了哪些数据,写到了哪里。该如何评估数据一致性呢?普通的测试工具可以采用fio开启crc校验选项,最好的测试工具就是数据库。如果发生了数据不一致的情况,数据库要么起不来,要么表数据不对。具体的测试用例还要细细斟酌。 -
存储性能
存储的性能测试很有讲究,块存储和文件存储的侧重点也不一样。 -
容器存储功能
除了存储的核心功能(高可靠/高可用/高性能),对于容器存储,还需要几个额外的功能保证生产环境的稳定可用。 -
Flexvolume/CSI接口的支持,动态/静态PV的支持
-
存储配额。对于Kubernetes的管理员来说,存储的配额是必须的,否则存储的使用空间会处于不可控状态
-
服务质量(QoS)。如果没有QoS,存储管理员只能期望存储提供其他监控指标,以保证在集群超负荷时,找出罪魁祸首
拓展阅读
Kubernetes持久化存储方案的重点在存储和容器支持上。因此首要考虑存储的核心功能和容器的场景支持。综合本文所述,将选择项按优先级列举:
1、存储的三大核心,高可靠,高可用和高性能
2、业务场景,选择分布式文件存储
3、扩展性,存储能横向扩展,应对业务增长需求
4、可运维性,存储的运维难度不亚于存储的开发,选择运维便捷存储产品
5、成本