目前在城商行使用了容器云的,更多是用于部署应用层的一些组件,在涉及一些需要进行弹性伸缩的业务场景,例如秒杀、活动优惠等敏态业务,则采用容器部署应用app层的一些纯Java程序、中间件、无状态的Redis集群等,此外也会逐步碰到一些场景,需要我们的容器平台能保存状态,我们部署MySQL、Redis等数据库,需要对这些数据库产生的数据做备份。
2.K8S 存储系统介绍:
说起容器的存储,需要先了解CSI/PV/PVC/StorageClass的几个基本概念。
2.1 CSI
CSI英文全称是Container Storage Interface,是容器编排系统(COS)上通用的容器存储接口,第三方存储厂商可以通过编写CSI插件来将其文件存储和块存储提供给K8S上容器化的工作负载,而无需修改K8S的核心代码。K8S作为事实上的容器编排(CO)标准,对CSI持久化存储接口的支持已经可以商用。K8S的V1.13版本已经支持了GA版本的CSI组件。目前K8S主要持久化存储主要通过该标准接口进行对接。
在Pod创建过程中,通过指定创建外部卷存储,PVC通过StorageClass的动态供给生成对应绑定的PV,PV的创建与绑定由CSI来进行。这时候CSI就可以自己定义如何加载一个卷,如何挂载一个卷。
2.2 PV以及PVC
PV全称叫做Persistent Volume,持久化存储卷。它是用来描述或者说用来定义一个存储卷的。PV一般由运维来创建。PV有2个重要的参数,分别是accessModes和PersistentVolumeReclaimPolicy。
accessModes:支持四种类型,第一种是ReadWriteMany多路读写,卷能被集群多个节点挂载并读写。第二种是ReadWriteOnce单路读写,卷只能被单一集群节点挂载读写。第三种是ReadOnlyMany多路只读,卷能被多个集群节点挂载且只能读。第四种是新增特性ReadWriteOncePod,该卷只能被被单一节点的单一Pod挂载为读写模式,当一个带有pvc访问模式为ReadWriteOncePod的Pod A时,K8S确保整个集群内只有一个Pod可读写该PVC,如再创建Pod B并引用了与Pod A相同的PVC(ReadWriteOncePod)时,Pod B则会由于该pvc被Pod A引用而启动失败。
PersistentVolumeReclaimPolicy:也有三种策略,这个策略是当与之关联的PVC被删除以后,这个PV中的数据如何被处理。
(1)Retain手动重新使用,生产系统中,因通常存储上都是需要保留的数据、日志等,最为常用。Retain当删除与之绑定的PVC时候,这个PV被标记为released(PVC与PV解绑但还没有执行回收策略)且之前的数据依然保存在该PV上,但是该PV不可用,需要手动来处理这些数据并删除该PV。
(2)Recycle,回收策略Recycle会在卷上执行一些基本的擦除 (rm -rf /thevolume/*)操作,之后允许该卷用于新的 PVC 申领。
(3)Delete对于支持Delete回收策略的卷插件,删除动作会将PersistentVolume对象从K8S中移除,同时也会从外部基础设施(如AWS EBS、GCE PD、Azure Disk或Cinder卷)中移除所关联的存储资产。动态制备的卷会继承其StorageClass中设置的回收策略, 该策略默认为Delete。
PVC是用来描述希望使用什么样的或者说是满足什么条件的存储,它的全称是Persistent Volume Claim,也就是持久化存储声明。开发人员使用这个来描述该容器需要一个什么存储。比如下面使用NFS的PVC:PV是已有存储,PVC是需要的存储,两者要形成配对需要下面2个条件:
PV和PVC中的spec关键字段要匹配,比如存储(storage)大小,PV里的存储容量不能小于PVC里声明的。
PV和PVC中的storageClassName字段必须一致。
2.3 StorageClass
StorageClass提供了一种描述存储类(class)的方法,不同的class可能会映射到不同的服务质量等级和备份策略或其他策略。PV是运维人员来创建的,用户操作PVC,可是大规模集群中可能会有很多PV,如果这些PV都需要运维手动来处理这也是一件很繁琐的事情,所以就有了动态供给(Dynamic Provisioning)概念,而动态供给的关键就是StorageClass,它的作用就是创建PV模板。创建StorageClass里面需要定义PV属性比如存储类型、大小等;另外创建这种PV需要用到存储插件。最终效果是,用户提交PVC,里面指定存储类型,如果符合我们定义的StorageClass,则会为其自动创建PV并进行绑定。
3.容器云存储类型选型需求分析
在容器云中,我们对K8S中部署的应用都是以Pod容器的形式运行的,因为Pod是无状态的,如果Pod不挂载数据卷,那Pod被删除或重启后这些数据会随之消失,如果想要长久的保留这些数据就要用到Pod数据持久化存储。针对业务场景不同进行分类,容器云对于存储的需求可以分为非持久化存储和持久化存储两种。
除了希望数据不在Pod重启后丢失,有时候也需要在Pod间共享文件。因此,衍生了Pod存储持久化的话题。在云平台的容器云中,都提供了一些方案来解决容器挂载持久化存储的问题,但是主要都是通过K8S提出的Volume对象方案进行封装来解决该问题。
3.1 容器云非持久化存储需求
容器云容器运行在物理或者虚拟服务器上,需要使用到容器应用的有镜像仓库和运行态容器实例,以及一些容器产生的日志等。容器云需要使用存储的场景有:
1、容器实例的创建和运行。容器创建实例时需要使用到一定的存储空间,每个容器需求空间的大小根据容器个数以及容器中部署的基础环境及容器应用确定。整体容器工作节点的存储空间大小根据运行的容器类型以及容器个数决定。值得注意的是,单个工作节点的大小要能覆盖可能运行在该节点上容器的空间的总和。用于存储运行态容器的存储空间,对性能要求要相对高,能支持容器的快速动态伸缩和文件的快速读写。
2、一些不需要持久化存储的文件,例如容器应用运行过程中生成的一些临时文件。
通常使用容器运行的是敏态业务,敏态业务的特点,总结起来通常是支持业务高并发、支持容器在多个工作节点上启动或者停止的弹性伸缩;针对以上特点,容器对非持久性存储的要求主要集中在性能层面,对于空间要求并不高,但是要求工作节点能便捷的识别并且具备较好的IOPS并发读写能力。非持久化存储采用本地硬盘或者集中式存储映射的块存储较多,只要工作节点能识别就可以满足要求。
3.2 容器云持久化存储需求
银行业中,过去主要运行一些内部管理或者业务量较少的边缘应用,近年随着容器技术成熟,银行中越来越多重要交易业务也开始使用容器来支撑生产交易,因此容器使用持久化存储的场景越来越多,主要使用场景有如下几类:(1)应用文件,例如图片、文档等持久化存储。此类存储在银行业务中,常见的是用于保存用户申请、填单、业务发生时录像等重要凭据的保存,在容器消亡后需要长期保存,并归档入库的。(2)业务日志持久化存储,容器中如果是重要业务,则业务产生的流水日志、操作日志等需要保存下来,便于进行一些后续系统故障分析、系统优化的依据。(3)kafka、Redis等组件数据持久化存储,例如多个容器需要同时读写一个消息队列,并且应用重启后,队列中的未消费消息需要处理完。或者redis数据库中的数据,需要长期保存。(4)镜像仓库,镜像仓库是用来保存所有创建好的镜像统一存储的位置,主要保存测试及生产中常用的容器镜像。容器镜像是一个个静态只读文件,其中包含有关创建Docker容器的说明。容器镜像仓库存储的要求主要是空间要求,对性能要求不高。
如果容器应用是需要使用持久化存储,对于持久化存储需求的主要特性如下:(1)持久化需求:生产系统业务日志,业务分析的基础,永久保存。(2)Pod漂移后,通过另外节点挂载同一块存储实现状态数据迁移。(3)共享存储需求:业务文件、图片分布式共享需求。(4)扩容需求:存储灵活扩容需求,容器节点灵活扩容、迁移能力需求。(5)性能需求:应用文件,例如图片、文档等写入性能直接关系到业务系统的并发支撑能力。(6)安全、高可用需求:须内网存储,保证双中心架构。
4.容器云支持的存储类型
容器的存储选型也包含持久化和非持久化两类,容器云支持的存储类型也比较丰富,包括ISCSI/FC等映射的块存储,NFS文件系统,对象存储系统,AWS等公有云存储服务,还有EmptyDir,HostPath等K8S内置存储类型。其中目前常见的主要是NFS映射文件系统,以及Hostpath内置存储。Cephfs等分布式对象存储系统,因其灵活扩容能力和海量存储特性,目前有部分用户用于进行容器备份。
其中HostPath Volume是指Pod挂载宿主机上的目录或文件。HostPath Volume使得容器可以使用宿主机的文件系统进行存储,Hostpath(宿主机路径)是节点级存储卷,在Pod被删除后存储卷仍然存在Pod运行worknode上不会被删除,只要同一个Pod被调度到该节点上,在 Pod 被删除重新被调度到这个节点之后,对应的数据依然是存在的。Hostpath存储卷缺点在于Pod删除之后重新创建必须调度到同一个node节点,数据才不会丢失,对于多个node的场景,是不合适采用的。
EmptyDir类型的Volume是在Pod分配到Node上时被创建,K8S会在Node上自动分配一个目录,因此无需指定宿主机Node上对应的目录文件。这个目录的初始内容为空,当Pod从Node上移除时,EmptyDir中的数据会被永久删除。EmptyDir Volume主要用于某些应用程序无需永久保存的临时目录,多个容器的共享目录等,但是如果是需要进行持久化存储,则不合适采用。
4.1 非持久化存储选型经验
如果采用非持久化存储,应用场景包括高IO、低延时场景,主要采用本地存储和块存储两种类型,考虑性能和连接方式,可以本地硬盘构建HostPath或者集中式块存储,相对来说IOPS以及带宽都较高,本地SAS接口硬盘组或者FC提供的LUN吞吐通常可以达到1GB以上,基本可以满足单台工作节点的容器集群io需求。如果采用工作节点的本地硬盘,则建议通过Raid卡配置Raid5以上保证存储一定的容错能力,虽然K8S集群本身具备单个容器实例的异常处理能力,但是因为工作节点单块硬盘故障导致整个工作节点的文件系统异常从而导致该节点上容器服务批量中断,在业务层面还是有所感知的,可能会带来用户的正常会话丢失,需要用户重新登录。建议配置Raid后,配置单硬盘的容错能力,提高整体业务系统的可靠性。
块存储设备适用于对IO、延迟要求较高的应用场景,例如:数据库、中间件等服务。在非共享场景中,块存储是独享模式,同时只能给一个Pod使用,在非共享数据业务场景可以考虑使用块存储。适合有状态应用,每个副本一个存储卷。如果采用块存储,可以选择集中式块存储,也可以选择分布式块存储。如果是采用集中式块存储,则与传统Iaas中的虚拟机或者裸机连接集中式存储使用差别不大,通常采用FC网络和ISCSI网络进行连接,但是在云平台中,更多的是采用分布式存储,通过IPSAN映射至计算虚拟化服务器。分布式存储可以提供块存储、对象存储、nas存储等多种存储服务类型,可以采用SSD+HDD或全闪存配置硬盘组的方式提高分布式存储的性能。
分布式块存储扩展能力较好,常见协议有:isCSI。还有本地存储,块存储通常只支持RWO,比如AWSElasticBlockStore,AzureDisk,有些产品能做到支持ROX,比如GCEPersistentDisk,RBD,ScaleIO等。
4.2 持久化存储选型建议
在选择持久化存储时,在选型过程中建议考虑容器适应业务场景、存储的性能、是否支持K8S CSI、是否支持扩容、是否支持克隆等角度进行选型。目前持久化存储常用的有NAS和对象存储两种。
(1)对象存储
容器选用对象存储的场景和选用NAS存储的场景有一定重合之处,例如对于容器实例需要进行文档、图片等小文件共享时,可以考虑NAS和对象存储两种。但是面临选择时有一定区别,例如应用如果是影像类系统、视频库管理类系统、图片采集、分析等系统的话,存储图片数据量达到数PB级别,单个文件大小为MB级别以上,文件数量数万或者更高,则更推荐采用对象存储。媒体、图片等媒体文件只读场景可以通过对象存储读取上述文件类型。对象存储使用的过程中,一般不需要配置CSI,对象存储不需要PV/PVC来做资源抽象,应用可以直接访问和使用只需要在应用中配置对象存储的地址,秘钥等进行读写。
(2)NAS存储
NAS存储支持多个容器读取一个共享目录并且长期保存,如日志保存,将不同Pod副本的日志存在同一个目录中,如共享文件,多个Pod同时读写问题。目前在城商行已有的案例中,较为常见的方案是采用集中式NAS存储或者分布式NAS存储提供持久化存储服务,划分文件系统给容器云挂载PV卷。目前采用集中式或分布式NFS存储提供持久化存储服务,能较好的满足在稳定性、高可用、灵活扩容能力、便捷管理几个方面的要求。其优点有如下几个:
a、使用NAS提供持久化存储,相比Hostpath实现分布式应用在多节点容器日志集中管理,降低日志管理复杂度,提高排障效率。
b、使用NAS存储平台,可采用端口绑定的方式提升带宽,保证高业务负载下的带宽性能,支持业务的高并发。
c、使用NAS存储平台,提供了具备高稳定性、高容错能力的存储服务。
容器在进行弹性伸缩或者进行故障恢复时,同时将频繁的发生存储卷的挂载和卸载,为了保证整个生产环境的稳定性,在进行卷的挂载和卸载操作中需要保证足够的稳定性,同时也需要PV卷服务端能保证较高的性能,避免应用延迟。采用专用的集中式存储NFS可以提供较为稳定、高性能的存储服务。集中式存储设备通过Raid、冗余存储机头、分布式集群多节点等能力,保证了硬件故障情况下的高稳定性;当NFS表现出性能不足的情况下,集中式存储可采用增加端口绑定的方式提升带宽,分布式存储也同样可以采用增加绑定端口提升带宽,扩容分布式节点提升整体集群存储性能。
a、切实的容灾方案:重要业务需进行多中心部署,通过使用NAS存储,实现多中心架构的容器集群数据同步构建,提供一种切实可行的重要业务容器化部署的容灾方案。通常银行业会要求重要业务进行两地三中心部署,通过集中式存储和分布式存储本身的双中心双活能力,也可以构建双中心架构的容器集群。
b、简易化运维管理:随着容器有状态应用的增长,对传统存储运维工作也会带来挑战,整体方案需要兼顾运维敏捷和安全。集中式和分布式NAS存储产品,均具备界面化、便捷的管理手段。采用NAS存储产品,具备直观的图形界面,能进行便捷的配置、切换管理,降低运维的复杂性。
c、客户端可以启用用户认证机制,且数据是通过明文或者密文传送,安全性相对较高(一般建议在局域网内使用)
虽然NAS存储有明显的优势,但是与其他类型对比时,也有一定的缺点:
a、NAS存储在高并发下iops效率/性能,相比块存储是处于劣势,如果承载的容器数量过多,IOPS性能相比块存储要弱。
b、在K8S场景中,一个NAS目录如果配置给K8S集群中,则无配额限制,所有用户申请资源等于申请了所有NFS的存储池。
4.3 案例分享
在我们的环境中,目前有多个业务系统各采用独立的K8S容器集群承载业务程序,其中较大业务系统一个K8S集群中部署有12个Pod,主要是运行业务系统的Java应用以及Web应用,该持久化存储场景主要是为了保存业务运行日志,容器集群的持久化存储通过OceanStor系列存储配备双中心复制的存储集群提供,通过配置双活NAS存储发布服务至容器云集群,作为PV映射给Pod使用。另一套集群则是采用冷备方案配置,主中心K8S集群使用主中心的分布式存储(可读写),SDS分布式集群将数据异步复制到备中心,灾备中心的冷备K8S灾备集群挂载备中心的分布式存储(不可读写),当主中心故障导致主中心的K8S集群以及存储集群失效时,手动拉起备中心的K8S集群并将备中心分布式存储集群拉起为可读写,以提供业务连续性。也有使用到华为OceanStor存储中的NAS功能进行承载此类业务,总结使用中,体现出以下一些优势:
(1)其相比Hostpath实现分布式应用在多节点容器日志集中管理,降低日志管理复杂度,提高排障效率;
(2)使用该存储平台,可采用端口绑定的方式提升带宽,保证高业务负载下的带宽性能,支持业务的高并发;
(3)使用该存储平台,提供了具备高稳定性、高容错能力的存储服务,集中式存储的Raid、冗余存储机头等硬件容错能力,支持容器日志的安全存储,保证了业务的持续稳定运行;
(4)使用该存储平台,切实的容灾方案:重要业务需进行多中心部署,通过使用华为NAS存储,实现多中心架构的容器集群数据同步构建,提供一种切实可行的重要业务容器化部署的容灾方案;
(5)使用该存储平台,具备简易化运维管理能力:采用NAS存储产品,具备直观的图形界面,能进行便捷的配置、切换管理,降低运维的复杂性。