题图摄于北京798艺术区
本文作者系VMware云原生实验室工程师景晨,KubeFATE开源项目维护者。
一、背景介绍
KubeFATE v1.9.0版本中发布了升级功能,该功能可以帮助FATE集群的使用者使用一个KubeFATE命令来一键升级自己的FATE集群并完成数据迁移。在此之前只能通过“先卸载,再安装,手动迁移数据”来完成“升级”。本篇文章会对此新功能的使用提供示例并解释其背后的实现原理。
二、 使用示例
1
有关KubeFATE和FATE版本的迷思
KubeFATE的发布版本和FATE保持一致,即FATE发布v1.9.0,KubeFATE也会随之发布v1.9.0。这是因为KubeFATE的其中一个重要组成部分是FATE的Helm Chart(https://helm.sh/)。我们使用Helm Chart来封装FATE繁琐的部署配置,并将FATE的组件部署到K8s上。随着FATE的迭代,其Helm Chart也需要相应地迭代,Helm Chart的版本就会和FATE保持一致。KubeFATE的另外一个组成部分是KubeFATE服务,它是一个联邦学习框架的生命周期管理工具。KubeFATE服务同时发布的版本是v1.4.5。
KubeFATE服务和FATE是解耦的。使用KubeFATE服务v1.4.5,可以部署任何一个版本的FATE集群。假设有用户使用KubeFATE服务v1.4.5部署了一个v1.8.0的FATE集群,那么现在此用户可以一键将FATE集群升级到v1.9.0。这就是我们实现的KubeFATE升级功能。
2
升级过程演示
a.为集群创建PV和PVC
当FATE集群没有开启数据持久化时,升级必然会导致数据丢失,此时升级从本质上来说,就是终止旧版本的pod并启动新版本的pod。在实际生产环境中一般会开启数据持久化。KubeFATE的cluster.yaml中提供了persistence配置,当它被设为true时,KubeFATE会使FATE的pod通过pvc来绑定pv,来持久化pod产生的生产数据。pv和pvc可以通过existingClaim字段来进行手动配置,也可以通过storageClass来配置。下面我们使用existingClaim来进行演示。先在K8s集群上先提前创建好了pv和pvc:
这四个pv/pvc分别是给FATE集群的四个模块:Jupyter notebook(client),MySQL,fateflow(python)和eggroll(nodemanager)准备的。
b.安装一个v1.8.0的FATE集群
我们对示例的配置(https://github.com/FederatedAI/KubeFATE/blob/develop-1.8.0/k8s-deploy/examples/party-9999/cluster.yaml)进行修改,把persistence配置成true,然后将四个模块的existingClaim 配置设成我们准备好的pvc名字。然后执行“kubefate cluster install -f cluster.yaml”进行安装。
安装成功之后,可以使用”kubefate cluster list”命令来查看FATE集群的uuid,使用”kubefate cluster describe”命令可以查看此FATE集群的状态。这里可以看到所有的pod和deployments都是处于就绪状态。
c.留下一些持久化数据
为了演示升级后的数据迁移,我们首先让v1.8.0的FATE集群产生一些持久化的数据。我们进入到了client的容器内部跑了一个toy example,具体步骤是:
i.kubectl exec -n fate-9999 -itbash
ii.flow init --ip fateflow --port 9380
iii.flow test toy -gid 9999 -hid 9999
然后我们打开了jupyter notebook的UI,跑了“Pipeline Upload Data Tutorial”这个上传数据的示例Python程序。
然后打开fateboard UI,观察到5个成功的任务,上面三个是上传了3个数据集,下面两个是toy example的任务记录:
fateboard中展示的数据是从FATE的MySQL数据库中读取的。
d.升级到v1.9.0
我们只需要修改cluster.yaml文件中的chartVersion配置,从v1.8.0改成v1.9.0。然后执行“kubefate cluster update -f cluster.yaml”命令对集群进行升级。之后用户不再需要任何操作,只需要等待集群升级完毕即可。
e.检查集群的状态
升级之后,可以使用“kubefate cluster describe”来再次查看v1.9.0的FATE集群的状态:
可以看到v1.9.0 FATE集群的pod,deployment和statefulSets均处于就绪状态。(注:在v1.9.0版本中我们将所有需要数据持久化的FATE组件改为了更为合适的StatefulSets形式,https://github.com/FederatedAI/KubeFATE/pull/681)
升级到v1.9.0之后我们再一次进入client容器跑了toy example,然后查看fateboard,会发现之前跑过的任务记录都还在:
进入eggroll nodemanager容器中,发现升级之前上传过的数据集也还在:
这表示升级到v1.9.0已经成功了,且在v1.8.0时代产生的所有持久化数据都已经成功地挂载到了v1.9.0的FATE的各个pod上。
三、原理解析
1
Helm的利用
KubeFATE服务使用Helm sdk来部署FATE系统在K8s集群上。FATE系统由很多组件构成,例如fateboard,fateflow,MySQL等 。每个组件的配置都是比较繁琐的。因此在单机上直接安装FATE是一件麻烦的事情。通过Helm chart,我们把这些繁琐的配置都提前预置到了Helm模版中,只暴露了最重要/常变的配置给用户。因此用户可以非常容易的将FATE系统在K8s上部署。关于在K8s上部署FATE的教程,可以参考https://github.com/FederatedAI/KubeFATE/blob/master/docs/tutorials/Build_Two_Parties_FATE_Cluster_in_One_Linux_Machine_with_MiniKube.md。
不仅是安装,在升级的过程中KubeFATE仍然利用了Helm SDK。当用户把cluster.yaml文件中的chartVersion从v1.8.0改成v1.9.0并执行安装指令时,给到 KubeFATE的信号是下载v1.9.0版本的Helm Chart(我们每一次发布都会将Helm Chart上传到Github仓库的gh-pages分支中)。然后KubeFATE通过调用Helm SDK中的升级API,将K8s集群中v1.8.0版本的计算资源停止,再启动v1.9.0版本的计算资源。
2
持久化数据的自动迁移
FATE集群是由多个pod组成的,其中一部分pod需要挂载持久化卷,即pv,来存储化一些生产数据。当我们选择使用existingClaim方式挂载持久化卷时,这些持久化的数据是不在Helm的管辖范围之内的。因此当KubeFATE操纵Helm来摧毁v1.8.0版本的资源时(pod,service,ingress)等,这些pv/pvc可以被保留。又因为我们在v1.9.0的版本中继续指定这些pv/pvc作为existingClaim。因此下个版本的pod在启动时会直接挂载这些存储卷。从用户的角度来看就是FATE升级了,且以前老数据还在的效果。
除了existingClaim的方式,KubeFATE还允许FATE用户使用storageClass(https://kubernetes.io/docs/concepts/storage/storage-classes/)的方式来创建存储卷。使用这种方式创建的存储卷同样也不在Helm的管辖范围之内。因此我们也可以支持使用storageClass的FATE用户用KubeFATE来升级FATE。当pod的形式StatefulSets时,pod的命名是固定的。因此v1.9.0的mysql-0 pod所绑定的存储卷,也必定会被v1.10.0的mysql-0 pod所绑定。为了支持这种更为简便的数据迁移,我们在v1.9.0版本中把所有可能挂载存储卷的FATE组件都改成了StatefulSets 的形式。只有100%无状态的组件还保留Deployments的形式,例如Spark Worker。
使用KubeFATE部署的FATE,如果版本小于v1.9.0且使用了storageClass来实现持久化,不推荐使用KubeFATE来直接进行升级。建议手动备份数据后,安装v1.9.0的FATE后手动完成数据迁移。具体原因可以参考https://github.com/FederatedAI/KubeFATE/blob/master/docs/FATE_Upgrade.md。如果从v1.9.0向未来的版本升级,KubeFATE可以完美支持storageClass和existingClaim两种方式。
3
使用K8s单次任务来更新FATE的元数据表
在FATE系统中,MySQL是一个非常重要的模块。里面存储了很多FATE系统的重要数据。例如:
随着FATE版本的迭代和新功能的增加,存储在MySQL数据库中的表和schema可能会发生变化。因此从v1.8.0的MySQL里的数据表可能无法让v1.9.0版本FATE正常启动或运行。我们必须要升级数据表至新版本。
为了能在用户使用KubeFATE对FATE集群进行升级的过程中, 帮助用户无感地升级MySQL数据库,我们开发了FUM(FATE Upgrade Manager)。并在FUM中放置了任意两个连续FATE版本的数据库升级脚本。
FUM是KubeFATE的一个插件。当用户升级FATE时,KubeFATE会自动从DockerHub或上拉取FUM的镜像并使用Helm SDK来安装FUM。FUM会启动一个K8s job。这个job是一个一次性的任务,会按顺序执性以下操作:
•终止旧版本fateflow pod的运行,切断对数据库表的修改
•根据旧版本的chartVerison和新版本的chartVersion,计算所有需要顺序执行的脚本
•对MySQL按顺序依次执行升级脚本
当以上步骤完成后,KubeFATE会调用Helm SDK来完成所有资源的升级,包括StatefulSets, Deployment, Ingress等资源。在所有的pod都升级到新版本之后。KubeFATE会调用Helm SDK来卸载掉FUM,因为作为一个单次任务,FUM的生命周期已经可以结束了。此时用户再去观察FATE集群,看到的就是升级完成的状态。中间的过程无需用户干预。
利用这种方式KubeFATE实现了跨多版本升级。假设用户现在要从v1.7.2直接升级到v1.9.0。FUM会计算出需要顺序执行的脚本是1.7.2-1.8.0.sql和1.8.0-1.9.0.sql。两个脚本依次执行完成之后,我们终止所有v1.7.2的pod再启动v1.9.0的pod,从用户的角度来看就是无损地完成了整个FATE系统的升级,跨过了v1.8.0版本。
四、未来可以进一步解决的问题
1
数据库自动备份
如上所述,FUM会帮助用户自动升级MySQL数据库的schema(模式)。但在此之前,用户必须先手动备份自己的数据库。未来一个工作的方向是升级前自动帮助用户完成数据库的备份。一个值得思考的点是当MySQL的pv剩余存储空间不足时,如何解决备份文件放置在哪里的问题。
2
数据库自动回滚
如果Helm升级失败,Helm会将所有的pod回滚到上一个版本。但是如果产生这种状态,表示FUM已经升级过数据库的schema了。那么此时回滚到上个状态FATE有可能不能正常工作。未来我们可以通过逆向SQL语句的方式,将对数据库的改变也回滚。目前通过备份数据库也能暂时解决这个问题。
3
Docker Compose模式的支持
本文所介绍的升级只适用于使用K8s部署的FATE集群,如果是使用KubeFATE项目中的Docker Compose模式部署的FATE,目前尚不支持自动升级。我们对Docker Compose部署方式的定位是一个体验版,我们更推荐K8s的部署方式。
五、总结
KubeFATE的最新发布v1.4.5帮助用户解决了FATE的升级问题,目前是FATE自动升级的唯一解决方案。
在KubeFATE服务代码(https://github.com/FederatedAI/KubeFATE/blob/master/k8s-deploy/pkg/job/fate_upgrade_manager.go)中,我们使用了可扩展的代码编写方式。未来当KubeFATE进一步支持更多的联邦学习框架时,进一步以插件方式支持其他框架的Upgrade Manager也会比较容易 。
KubeFATE和FATE都是FederateAI社区(https://github.com/FederatedAI)中的开源项目,我们欢迎社区贡献者帮助我们进一步优化KubeFATE的升级功能。
要想了解联邦学习、隐私计算、云原生和区块链等技术原理,请立即长按以下二维码,关注本公众号亨利笔记 ( henglibiji ),以免错过更新。