[转载] Kubernetes中应用的数据保护
原文链接
转载注解:
- PowerProtect Data Manager (PPDM) 基于 Operator 模式在K8S集群中创建 PowerProtect controller 来集成管理 K8S 资源的备份与恢复
- PowerProtect controller 使用 Velero 来备份 K8S 原生资源,比如 pod, service, 用户自定义资源等
- 基于 K8S CSI snapshot 接口,对 PV 进行快照,并通过辅助cProxy Pod 将 PV快照中的文件同步到K8S集群外的备份存储中
- 使用Velero 对备份的 K8S 资源进行恢复,通过cProxy 将备份存储中的数据恢复到新建的PV中
- 扩展阅读: 云原生时代,如何构建开箱即用的数据保护方案?
作者:戴尔科技中国研发集团 于靖 车弘毅
于靖:DELL EMC 数据保护部门架构师,技术委员会、数据科学委员会以及专利委员会成员。主要负责云平台Backup-as-a-Service的构建及虚拟化下的数据保护解决方案。在数据保护、虚拟化、容器、IaaS/PaaS/SaaS等领域有着丰富的经验。
车弘毅:DELL EMC数据保护部门工程师。主要参与数据保护服务向Kubernetes和云平台迁移的设计与实现。在微服务开发与治理,Kubernetes相关实践上有丰富的经验。
简介:
随着越来越多的IT基础设施向基于公有和私有云迁移,而Kubernetes(以下使用K8S),作为一个在云环境广泛使用的容器编排工具,为云环境的应用部署,实施和运维带来更多便捷。针对这样一个基于K8S的软件服务运行环境。数据保护服务也迎来了更多的使用场景和性能要求。K8S定义了新的软件的生命周期,也包含了新的存储模型,需要更有针对性的,更高效的备份还原解决方案来保护运行在K8S里的软件和数据。
本文将介绍PowerProtect系列产品,在数据保护的数据面(data path)如何结合K8S平台本身提供的扩展接口,提供原生的数据保护解决方案。
保护K8S中的应用
我们讨论数据保护,往往都围绕被保护对象来讨论相关的应用场景和技术实现。常见的保护对象有文件系统,比如Windows PC上的 C盘;有数据库的数据,比如Oracle,MySQL;还有特殊的应用,比如Outlook邮箱。针对不同的被保护对象,数据保护系统会利用对应的技术实现对于相关数据的保护,包括备份,还原,迁移,检索等等。
K8S本身作为一个运行的软件系统,包含在K8S里运行的系统,在使用的过程中必然会存在风险,其中包括硬件环境相关的灾难和故障。而现在成上升趋势的是人为因素,比如破坏,误操作,代码中的bug等等。这些情况都会导致他们无法使用,数据丢失。而且并不会因为某种容错良好的系统设计而改善。
我们先看看,我们到底要保护K8S的什么东西。从这个为出发点,了解面对的风险,保护的场景,PowerProtect的解决方案和技术实现。
保护什么
说到保护K8S,可能很多读者会觉得诧异。首先K8S被大家广泛接纳的原因就是它有着天生的容错能力和自动的修复能力。K8S的最核心组件是etcd, etcd是一个分布式数据库,它实现了CAP理论中的CP,它保证数据在集群中的强一致性和小于Quorum的节点失败。它是K8S保存状态(state)的地方,而其它的组件都是无状态的(stateless),只要etcd没有被破坏,部分的硬件损坏,网络的断联,都不会影响K8S和在其中部署运行的应用。
基于K8S开发和部署的系统,也继承了K8S的这个特性。Pod,作为计算的实体,常常被部署为多个副本(replica)。Pod的调度,启停,都自动由K8S完成。Service或ingress又把多个Pod的实现隐藏起来,对外保持一致的接口。即使排除这些特性,一个成熟的云原生服务,常常被设计成无状态的,服务本身失败了,那重新在可用的环境里启动它就可以了。
似乎K8S已经把自己和运行其上的应用保护的很好了。那么问题在哪里呢?
刚才提到了,K8S里那些无状态的组件都是可遗弃的(disposable)。需要保护的是那些保存状态的组件,更进一步说应该是这些“状态”本身。那这些状态在哪里呢?实际上只有两个。
· etcd中的资源定义(Resource Definition)
· Persistent Volume (PV)中的数据
我们都知道,K8S上的应用由多个资源(Resource)组成,比如Service,Pod。这些资源常常是由一个yaml文件来声明,然后利用kubectl来部署到K8S的名字空间(namespace)。而在这背后,发生的事情是,kubectl是一个K8S API Server 的客户端,一个Pod.yaml是一个Resource 的实例的描述文件,yaml是它的一种表现方式,它也可以是json或xml。Kubectl把它序列化后作为调用API Server的请求,把这个Pod实例保存到etcd的数据库里。扩展来说,除了Pod,Service,Deployment这些预定义的资源,还包含自定义的资源(Custom Resource Definition,CRD)。而客户端也不限于kubectl,这些资源的声明可以从不同的地方产生并上传,但它的实体是在etcd中,这也是我们要保护的东西。
虽然etcd具有很强的容错能力,但仍然避免不了其运行的硬件或虚拟环境的问题。更常见的是人为破坏或误操作,导致部署的资源丢失或损坏。而这也意味着部署的应用无法恢复。所以这也成了K8S数据保护的目标。简单的说一下这里的保护,也就是把这些资源在备份存储设备上进行备份,并且在需要时,再还原到回复的etcd的数据库中。K8S会把剩下的工作完成,把应用重新部署运行起来。后面会详细描述这个过程在PowerProtect里的实现细节。
第二个要保护的对象是Persistent Volume中的数据。部署在K8S中的应用常常会需要保存自己的状态,比如一个数据库的服务,数据文件需要一个持久化的存储,而不是像Pod那样只有一个易失性的存储。K8S中对应的资源类型称作Persistent Volume(PV)。而这种存储对象的实际提供者并不是K8S,而是由不同的存储厂商,通过实现(Container Storage Interface,CSI),然后由K8S来调用这些接口来产生存储资源并绑定到申请存储资源的Pod。这个就像操作系统和不同硬盘厂商之间的关系,操作系统希望厂商实现统一的驱动接口,这样操作系统就能控制不同的硬件,向上提供统一的文件系统,CSI的实现就是K8S里的硬盘驱动。
在实际的应用场景中,PV并不是静态的产生和绑定,它常常是动态地、按需地产生和绑定。一个典型的方式是:K8S的管理员声明一些全局的存储类型(StorageClass,SC),不同的类型包含对于存储介质的特性的描述,比如是否SSD,是否加密等等,这些都与K8S实际的存储解决方案和存储供应商的特性相关。K8S应用的开发者负责声明一些(Persistent Volume Claim,PVC),PVC一边关联着SC,另一边一个Pod通过关联PVC来实现对PV的请求。而K8S则通过这些关系,利用CSI调用存储设备,产生存储实体,然后以文件系统的方式挂载到Pod中。对Pod中的进程来说,系统中有一个目录,所有写进这个目录的数据不会因为Pod的消失而消失,当Pod在另一个节点启动后,同样的目录下,数据还是刚才的样子。
回到我们说的要保护的PV中的数据,指的就是那些被写进PV挂载的文件系统中的文件。而其它的PVC,SC的声明则属于刚才说的资源定义(Resource Definition)。PV的生命周期独立于Pod,它的产生和销毁常常和PVC的生命周期相关,也和CSI的具体实现相关。但综合各种因素都有可能导致PV中的数据彻底损坏。而这时就需要引入对于这类特殊存储的数据保护。
如何保护
了解了K8S的数据保护对象,我们就可以介绍一下如何去保护这些特定数据和保护数据的特定技术实现。针对上节所述的两种不同的保护对象(Resource Definition和Persistent Volume上的数据),稍后会有详细的介绍。
PowerProtect深度集成和扩展了K8S的接口,通过自定义K8S资源(Custom Resource Definition,CRD)来实现数据备份与还原,使得数据保护成为K8S的一部分,就像那些原生的Pod,Deployment一样。所以在介绍PowerProtect的具体实现前,先要介绍一下K8S的工作原理。
K8S通过不同的资源定义(Resource Definition)和对应的控制器(Controller),来完成不同的编排任务。如图3,客户端将某类资源实例创建到K8S的数据库中,对应的控制器会被通知到资源实例的期望状态,然后去使得这个实例和期望一致。比如,我新建一个K8S的Pod,对应的docker image是centos,K8S的Pod控制器就会收到这个新Pod的定义信息,而后它会协调其他K8S组件比如Kubelet,Scheduler等去产生一个Pod。
这个模式几乎适用于所有的K8S组件,而扩展一个K8S没有的功能,也是用同样的模式,这种自定义资源(CRD)和控制器(Controller)的模式也被称为Operator。而PowerProtect也是利用了这种模式来实现数据的备份与还原,是一种更加K8S原生的实现。下面我们就来看一下PowerProtect的各个组件是如何来实现PV中的数据的。
图3中显示了PowerProtect对于K8S数据保护的主要组件。让我们仔细看一下各个组件的职责。
· PPDM(PowerProtect Data Manager): 它是数据保护的控制管理服务。用户通过PPDM的UI来管理K8S的保护资源并设置数据保护的策略,调度备份与还原的任务。
· Data Domain:它是保存数据备份的存储,我们的备份数据都在这里。
· BackupJob,RestoreJob:这两个是PowerProtect定义的CRD,也就是前文提到的用来扩展K8S的自定义资源,用来描述备份和还原的任务。PPDM通过向K8S新建对应资源的实例来请求备份与还原。资源的定义中保护了必要的信息,比如要备份还原的K8S namespace,备份存储的位置等信息
· PowerProtect Controller: 它是一个PowerProtect的自定义控制器,对应刚才的CDR,来处理具体的备份还原业务。它主要控制完成PV数据的备份与还原。
· cProxy Pod:它是个被PowerProtect Controller动态加载的Pod,每个备份还原一个PV都会对应地加载一个cProxy,他会读写PV,完成对里面数据的保护。
· Velero Controller:它是另一个开源的K8S扩展Operator,用于备份用户的K8S资源定义。PowerProtect Controller会和它交互完成对用户namespace里的除PV外的其它资源的保护。
介绍了各个组件,让我们再来看看一次完整的备份和还原是什么样的。
用户登录PPDM UI,配置添加要保护的K8S集群。添加对应的备份策略。PPDM会自动部署对应的组件到用户的K8S集群里。
当一次备份发生时,PPDM会向K8S新建一个BackupJob对象, 里面包含了要备份的用户名字空间(namespace)。
PowerProtect Controller会被通知到这个备份请求,他会用类似的形式通知Velero Controller开始备份目标名字空间里的所有资源(Resource)
Velero Controller把这些用户资源仍然以yaml文件的形式导出,然后压缩打包后上传到Data Domain里。
PowerProtect Controller会检测上一步的状态,当完成后,它会向K8S为每个PV对象都申请一个快照(VolumeSnapshot,VS)。并且运行cProxy Pod,并把这些快照内容(VolumeSnapshotContent, VSC),挂载到Pod里,这样cProxy就能以普通文件系统的访问方式读取到需要备份的文件。而这些文件也会通过DDBoost协议备份到Data Domain里。
到这里一个就完成了对用户名字空间里的所有对象都做了个完整的备份,而上述过程中的备份源和目标的信息都会保存在PPDM里,用户可以查询一个名字空间的多个备份,在数据需要还原时选择合适的版本。接下来再看看还原的过程。
当用户需要还原某次备份时,需要再PPDM UI上选择备份并开始还原
PPDM会新建一个RestoreJob对象到K8S
PowerProtect Controller同样会被通知到这个请求,开始对RestoreJob里描述的备份进行还原。它首先和Velero Controller交互,先还原部分的用户资源,这些资源不包含和PV有关的Pod, Deployment等等
Velero Controller 会读取Data Domain里对应的备份,当初备份时它是个压缩包,这里就把他解压并重新部署到K8S里
当PowerProtect Controller观察到上一步已经完成后,他会通过资源声明里的PVC去新建PV,并动态加载cProxy,去挂载对应的PV,并从Data Domain里下载备份写入这些空的PV里。然后再通知Velero Controller继续还原剩余的资源
Velero Controller会向K8S新建剩余的资源,这些资源都会关联PV,而当这些PV挂载起来后里面的数据已经时备份发生时的状态了。
到这里,用户的应用里无论时那些无状态的服务,还是文件系统里的文件都恢复到备份时的状态了。
总结
以上介绍了PowerProtect是怎么保护K8S里的应用和数据。整个解决方案深度集成了K8S这个平台,用K8S的原生方式去解决K8S的数据保护问题。其中有些是PowerProtect对数据保护领域独有的概念,但有很多的关于K8S原生应用开发及架构的内部原理的介绍和分析。希望能给原生K8S应用的开发者带去一些有用的启发和建议。