本文来自微信公众号“twt企业IT社区(talkwithtrend.com)”,【作者】汪照辉,架构师,专注于容器云、微服务、DevOps、数据治理、数字化转型等领域,对相关技术有独特的理解和见解。擅长于软件规划和设计,提出的“平台融合”的观点越来越得到认同和事实证明。发表了众多技术文章探讨容器平台建设、微服务技术、DevOps、数字化转型、数据治理、中台建设等内容,受到了广泛关注和肯定。
云原生是一种思想方法论,是借助云计算的思想和特性实现应用的云端构建、部署、运行等。信创云原生是采用国产化的CPU、存储、网络设备、操作系统、中间件等构建的信创云之上实现云原生应用的构建、部署、运行等,这些云原生应用构建、部署、运行、管理等的环境也是国产化的。虽然云原生的概念、理念、思想和技术等基本上都是自国外,并且云原生体系中的微服务、容器、DevOps、ServiceMesh等也是源于国外的开源项目,不过由于其开源开放性,不涉及硬件设施,因此信创体系下,把云原生的这些思想和技术应用适配到信创环境,就可以实现信创云原生。不过在信创容器运行时、服务治理、存储管理、API网关等技术方面还是需要持续努力的。
一、信创云原生是体系工程
信创云原生是在信创云环境下运用云原生的理念、技术、思想、方法等来实现信创云上的云原生应用研发、部署、测试、运行、运维、运营,实现信创云原生应用的弹性和可扩展性、敏捷性等。信创云原生应用的构建和运行离不开信创云的建设。信创云建设方案是一项复杂的系统性工程,不是简单的局部国产化替代,而是从CPU/GPU芯片、存储、网络到信创操作系统、中间件等,以及支撑云原生应用的研发平台、测试平台、部署运行运维平台和工具等,都需要一个拥有自主技术,且经过国内多业务场景的大规模验证和实践的技术体系。因此,信创云原生的关键在于信创云的建设和基于信创云支撑云原生应用的体系建设,是一项并不简单的体系工程。不过目前国内云原生方案依然采用的是开源的技术和组件,如SpringCloud、Docker、Kubernetes、Istio等,信创云通过一云多芯等方案支撑不同技术路线的系统,封装异构细节,从而可以实现信创云原生的低成本迁移,甚至无缝迁移。
二、信创云原生和存储的结合
由于云原生容器有一旦被删除其在运行时容器内部产生的所有文件数据也会随着容器销毁被清理掉的特点,所以Docker提供了逻辑存储卷Volume方式将容器产生的数据持久化到Volume卷上保存下来。作为容器管理和调度框架Kubernetes提供了多种存储卷Volume管理方式支持数据持久化,如本地存储、Static Volume、StorageClass、CSI(Container Storage Interface,容器存储接口)插件方式等。
存储的类型很多,比如块存储、文件存储、对象存储等,每种存储又有多种的协议类型、接口类型、存储架构、存储技术等,所以存储细分非常庞杂。在云原生容器和Kubernetes中,可使用支持的各种类型的Volume来完成数据的持久化,比如本地存储(emptyDir、hostPath)、网络存储(如NFS)、对象存储(Ceph、GlusterFS)等。Kubernetes还允许其他类型的外部服务以如CSI插件等方式接入到Kubernetes系统中。
信创云原生和存储的结合往往意味着存储的选型。不同业务对存储的读写速度、并发性能等的需求是不一样的,所以通常需要基于业务的功能、性能要求选择信创存储设备,同时考虑是否满足信创合规要求等。
从业务角度通常考虑功能和性能需求两个方面。不同业务对存储的需求是不一样的,比如说Jenkins容器可以使用本地存储,容器云平台上业务传输应用文件、日志等可以使用NAS存储卷,音频视频则适合选用对象存储等。还有需要考虑业务对存储性能的要求。我们曾经有个信创集群连接的存储性能比较差,导致整个集群性能很差,etcd健康检查服务都经常失败,不得不更换存储。另外需要考虑合规性、安全性等一些要求。很多业务数据是需要备份的,从合规性和安全性等方面,往往采用两地三中心等模式,云原生Kubernetes集群通常也需要部署于不同安全域,实现集群之间的互备或双活高可用等。另外,云原生平台本身的一些数据和组件也需要进行灾备,以满足等保、安全等要求。
三、存储和云原生容器的结合方式
云原生场景中,Kubernetes提供了本地存储、静态卷和动态存储类StorageClass以及插件的方式来使用存储。
1.本地存储方式
本地存储方式是指将容器运行时产生的数据存储在其运行节点的本地存储介质上。一般情况下容器云平台不用本地存储方式,因为使用本地存储会限制pod的资源调度。如果简单用Docker在本地启动和运行一些服务,比如说Jenkins。数据库等,可以使用本地存储的方式。它通常用于需要快速访问数据或者需要高性能存储的场景,使用本地存储性能通常要好于NAS等网络存储。
Kubernetes提供了多种本地存储方式,包括EmptyDir、HostPath和Local Persistent Volume等。EmptyDir是Kubernetes自带的,它创建一个空目录,作为容器内部的存储。HostPath允许Pod将节点上的文件系统挂载到容器内部,Local Persistent Volume则是使用本地存储介质作为持久化存储,允许Pod挂载本地存储介质作为卷。
2.静态存储方式
在静态模式下,企业内的各种类型的存储、存储资源池等由存储管理员来进行维护和运营(属于基础设施资源层),为云原生容器云平台(PaaS层)等提供存储资源服务。云原生容器云平台通过平台管理员为每个集群配置存储连接信息。容器云平台是一个存储资源消费方,同时需要为用户提供存储的配置管理和PV、PVC、存储资源使用情况、PV使用情况等的查询服务能力。当用户创建的Pod申请PVC时,PVC绑定已创建的PV。由于需要提前创建好PV,如果由平台管理员或平台集群管理员来维护PV,则需要不断跟租户用户进行交互,比较繁琐,因此可以将PV创建、删除和维护的权限交给租户,平台可以管理和限制租户的最大存储资源使用量,避免浪费;或者也可以用虚拟计费等方式来优化资源分配占用和使用,以提升资源的使用率。
容器云平台的定位会影响存储的使用方式。如果容器云是以容器为中心进行管理(侧重于IaaS层),则关注的是基础设施容器,而不是容器中运行的业务服务或应用。如果将容器云台作为容器化的PaaS平台(PaaS层)实现以应用为中心进行管理,则应用的管理和治理、API、日志、监控、链路、存储、网络等将都围绕应用而展开,容器只是个运行时引擎工具(可被无感替换)。这样就将业务数据和存储直接关联起来,根据业务需求进行存储选型,如图1所示。
图1 静态持久化存储资源PV供应模式
3.动态存储StorageClass方式
在大规模Kubernetes集群中,可能会生成成百上千的PVC,需要创建成百上千个PV,如果由人工来维护,效率可能非常低。容器的动态变化也可能不断创建、删除PVC,人工的响应往往难以满足需求。Kubernetes提供了一套自动创建PV的机制,也就是Dynamic Provisioning,核心在于StorageClass对象。StorageClass对象包含PV定义和创建PV的存储制备器,根据用户提交的P VC,找到对应的StorgaeClass,使用该StorageClass声明的存储插件来创建PV,Pod通过PVC动态绑定PV。要使用StorageClass,就需要安装对应的自动配置程序,比如我们使用NAS存储,后端使用的是NFS,就需要安装一个NFS-client的自动配置程序Provisioner,这个程序使用后端的NFS服务器来自动创建PV。通过StorageClass定义,可以将存储资源定义为某种类型的资源,比如高性能存储、通用存储、分布式GlusterFS、Ceph等,用户根据StorageClass的描述可以非常直观的知道各种存储资源的具体特性,就可以根据业务应用需求申请合适的存储资源。
使用StorageClass主要在一些场景中在运行时动态绑定存储资源,比如说某个容器进程在运行时需要启动其他容器进程并需要绑定PV。这种场景下,无法通过手工来创建PV,然后由PVC绑定,就需要使用定义好的StorageClass,来动态创建PV,如图2所示。
图2 动态持久化存储资源PV供应模式
4.CSI存储插件
容器存储接口(Container Storage Interface,简称CSI)是一种行业标准,用将块和文件存储暴露给Kubernetes等容器管理调度系统。CSI插件存储架构由两部分组成:External Components和Custom Components。External Components是从Kubernetes中的存储体系中剥离出来的存储管理功能,与Custom Components即CSI存储插件交互。CSI存储插件通常由存储厂商来实现并提供下载支持。有些旧的存储可能不支持CSI插件。如果想使用CSI时,需要确认存储是否支持CSI,是否能提供相应的CSI驱动和插件。在使用CSI插件时,每个集群需要部署一个CSI Controller,包含provisioner、attacher和csi插件,以StatefulSet或deployment方式部署,集群中每个节点部署一个CSI node,以DaemonSet方式部署,包含Driver registrar和CSI插件。
比如说华为存储提供的CSI接口中,有csi node和csi controller组件,node以daemonset方式部署在每个K8s节点上,controller以deployment部署。其中Node Pod中有3个容器/组件,Controller Pod中有7个容器/组件。
图3 csi node和csi controller组件
5.备份
备份可能是信创云原生平台使用存储最多的场景。需要备份的数据有很多,比如说镜像备份、容器备份、日志备份、业务文件备份、数据库备份、虚拟机备份等。我们也曾经发生过不小心删除了某个应用的情况,应用下有多个服务,意识到删错服务后也是惊出一身冷汗,好在快速恢复了过来。如果没有备份,只能重新部署,就可能需要花费更多的时间。
目前使用的备份软件主要还是针对Docker容器做备份,对集群管理组件目前还不支持直接备份。对于部署在Linux环境的api-server、controlmanager、scheduler之类的组件,备份软件可以通过文件备份的方式备份相应的配置文件,或者对节点虚机进行备份的方式进行保护。不过备份并不是做到实时备份,如果出现意外,可能会面临着一些数据的丢失。备份恢复只能恢复到最新的备份时点,备份间隔越长,丢失的数据就可能越多,选择合适的备份间隔也是一项重要的事情。
厂商提供的云原生容器云平台备份主要有两种方式,基于CSI的快照备份和Non-CSI的备份。对于支持CSI的容器,备份工具调用CSI进行快照,对指定的容器进行快照,然后再把快照数据备份到备份存储,数据恢复的时候可以直接从快照恢复,也可以从备份存储进行恢复;对于不支持CSI的容器,备份工具会采用“导出应用文件到持久卷”+“文件备份”的方式,把需要备份的数据备份到备份存储,数据恢复的时候把备份文件恢复到容器所在的持久卷上。
备份还是主要以保护数据为主。为保障数据安全和完整性,还需要结合其他手段,比如说断点重发等。
6.存储容量评估
容量规划是云原生体系重要的内容之一。存储容量评估通常分几个层次,一是节点的存储需求,二是备份需求。
基于CPU、内存容量和可承载的Pod数量及每个Pod的平均存储需求量。节点上的存储使用量通常用于服务日志,有些服务在打开debug时可能会短时间产生大量的日志,从而把节点空间占满。这种情况就不能无限扩展存储资源,而是需要限制日志文件的数量和每个文件的大小,使一个服务的总日志占用量有个最大值。
备份容量评估通常是按“实际有效数据量”和“重删后的数据量”来计算的。比如说:300TB分配空间,实际有效数据是100TB,100TB经过重删后(重删率按80%计算),实际落盘的备份容量大概是20TB。虽然有重删技术可以减少后端存储空间,但是考虑到备份数据都要保留一段时间,需要保留多个备份副本,所以,一般建议至少要准备2倍的存储容量,备份源端要和备份存储容量的空间保持一致。比如有1T的源端备份需求,需要采购2T备份容量,也就是1:2。
四、容器云平台对NAS存储支持设计实践
在当前需求和Kubernetes对NAS存储有限支持的情况下,我们在想是否可以找到一种简单的方式来更好的在容器云平台支持NAS存储,而不用带来巨大的定制化开发工作,同时又保持和以Kubernetes为基础的容器调度管理平台的松耦合。我们和UCloud等多位存储专家讨论过不同的实现方案,但也没有什么好的共识。不过对我们来说,首先要考虑先支持业务需求,因此我们考虑先用下面的思路实现。
1.存储管理的两个视角:平台管理员视角和租户视角。平台管理员维护容器云平台的所有存储资源,比如Mount存储到平台,分配一块存储给租户,回收分配给租户的资源等。租户只是使用分配的资源。租户可以申请多块存储资源,一旦申请成功(平台管理员分配完成),租户就可以在自己的存储管理界面查看到自己的存储资源列表。
对分布式存储比如Ceph等,这些需求的实现可能相对简单,不过对于NAS存储,可能无法通过调用NAS存储的接口实现,而且NAS存储种类、厂商众多,实现对不同厂商、不同种类的支持也不太现实。所以我们考虑在存储之上通过文件目录结构来实现,不管什么存储,只要支持文件结构,就可以通过这种软的类似插件的方式进行管控,虽然不完美,但目前来说可能是一种比较简单的方式。
2.平台管理员向NAS存储管理员申请一大块容器云平台使用的存储。比如说500G。在资源整合之前,通常NAS存储会有专人负责管理,容器云平台也是独立的,比如我们存储资源池、虚拟机、容器等彼此独立但又相互联系,都作为基础设施资源。
3.平台管理员拿到NAS存储之后需要根据申请分配给租户。比如租户A申请100G的存储空间,租户B需要20G的存储空间。这里有两种实现方式。第一种是在NAS存储上建立“文件夹A”和“文件夹B”,然后分别mount这两个文件夹给租户A和租户B。第二种方式是整块存储mount到容器云平台,然后直接分配给租户一个子文件夹。
存储卷大小管理需要借助平台保存这些存储卷的信息。不管这些信息是在文件、数据库或etcd中,需要持久化保存。同时要监控文件夹的大小变化,到达存储分配的最大值时禁止继续写入(当然也可以实现存储自动扩展能力),并及时在资源不足时提醒。这可能需要一个进程来完成这项任务。
4.在租户的存储管理界面,列出该租户所有的存储卷信息,包括卷名称(或文件夹名)、容量、使用量、详情(存储的文件目录信息)等。
租户不能通过终端命令行访问这些信息和其他租户的文件,屏蔽租户对宿主机命令行访问能力,只提供租户管理界面存储卷上的文件目录结构访问权限。
5.存储文件的管理也可以借助操作系统用户、组的管理能力。也可不考虑那么复杂,只实现文件目录结构管理,屏蔽终端命令行,做到相对的安全,这样也就只是实现对文件的管理,与具体的存储类型没有关系,但可以满足目前大部分采用容器云平台为不是分布式存储或对分布式存储需求不大的仅使用NAS存储的客户的需求。
6.租户可以申请共享存储卷(共享目录),然后共享给其他租户,这些租户都可以访问共享存储,读写其中的文件,共享卷通过卷标签标识。
这种思路秉承我们容器云平台“三视角四层次一回环”的设计思想,各组件之间尽可能的松耦合,同时简化一些繁琐的设计,尝试采用简单的方法来满足需求。实际的实现过程中也许还需要做一些调整,不过在容器云平台更好支持NAS存储,更好地提供存储服务,这可能是一种比较简单快捷的实现方法。
五、总结
当前国内云原生的技术体系基本上没有太大变化,信创云原生主要在于支撑云原生的信创云的建设和云原生支撑体系的建设。信创存储以多种方式支持着信创云原生不同业务场景和管理场景数据持久化需求。