KubeVirt深度剖析系列之:virt-controller源码分析
2020年CNCF中国云原生调查邀你一起来参与!问卷链接(https://www.wjx.cn/jq/97146486.aspx)廖旋威:目前就职于新华三云计算,主要从事云原生行业,对k8s和拟化相关有深入研究,擅长Go/Java语言。曾小波:一个十年一线架构研发工作的技术人员,目前在新华云计算从事云原生产品及社区相关工作。kubevirt 简介kubevirt 是一个围绕kubernetes构建
问卷链接(https://www.wjx.cn/jq/97146486.aspx)
廖旋威:目前就职于新华三云计算,主要从事云原生行业,对k8s和拟化相关有深入研究,擅长Go/Java语言。
曾小波:一个十年一线架构研发工作的技术人员,目前在新华云计算从事云原生产品及社区相关工作。
kubevirt 简介
kubevirt 是一个围绕kubernetes构建的虚拟机管理架构,主要用于技术原因无法将虚拟机应用迁移到容器平台的场景,它提供了完善的虚拟机生命周期管理、在kubernetes上虚拟机调度等能力。
。新华三云原生团队在kubevirt项目成立初期就进行了研究,并对kubevirt进行了改造实践,同时鉴于目前kubevirt深度分析资料较为缺乏,因此我们决定对kubevirt源码进行剖析,以飨读者。本文是系列的第一篇:virt-controller源码分析。
kubevirt 部署架构介绍
由virt-controller,virt-api,virt-handler,virt-launcher四大组件组成,其核心思想是在通过kubernetes原生来管理虚拟机,为开发团队处理只能使用虚拟机的应用程序提供了可能。为了让读者能够更好理解virt-controller,我们首先介绍一下kubevirt的部署架构,如图:
从架构图中可以看出:
- virt-controller,virt-api:集群层面上全局唯一,主要作用是通过与k8s api server 通信完成vmi资源创建、virt-lanucher pod 的创建及状态更新等。
- virt-handler:节点层面上唯一,负责与k8s api server、virt-lanucher通信来完成虚拟机的生命周期管理。
- virt-launcher:根据vmi 定义生成虚拟机模板,通过与libvirt api 通信提供虚拟机生命周期管理。
下面我们对virt-controller的源码进行分析,加深大家对实现细节的理解。
kubevirt 资源类型
VirtualMachineInstance
- 简称VMI,可以简单与实际虚拟机一一对应。
- 会创建一个包含virt-launcher的Pod,该Pod里面通过libvirt创建真实虚拟机。
- VMI的Spec字段指定虚拟机运行参数,Status字段记录虚拟机运行情况。
VirtualMachine
- 简称VM,可以管理和操作VMI对象。
- 一个VM对象只能管理一个VMI对象
VirtualMachineInstanceReplicaSet
简称replicaset或rs,一个replicaset可以管理多个VMI对象,即一个ReplicaSet可以创建、修改、删除多个虚拟机。
VirtualMachineInstanceMigration
简称Migration,在Migration对象的Spec字段里面指定要迁移的VMI,然后kubevirt自动对该VMI完成迁移。
virt-controller 源码分析
启动流程
入口在kubevirt/cmd/virt-controller/virt-controller.go
func main() {
watch.Execute()
}
直接调用kubevirt/pkg/virt-controller/watch/application.go中的Execute函数启动virt-controller。下面主要分析Execute函数中的内容。
- 获取leaderElectionConfiguration
- 获取KubevirtClient
- 获取informerFactory,并实例化一系列具体资源类型的Informer,例如crdInformer、kubeVirtInformer、vmiInformer、kvPodInformer、nodeInformer、vmInformer、migrationInformer等
- 初始化一系列controller,包括vmiController、nodeController、migrationController、vmController、evacuationController、snapshotController、restoreController、replicaSetController、disruptionBudgetController
- 通过leaderElector来启动virt-controller,并在leaderElector中启动各个controller的Run函数。
VMController分析
代码位于kubevirt/pkg/virt-controller/watch/vm.go文件中。
- 监听VM对象、VMI对象、DataVolume对象并添加对应的EventHandler。
- 收到Event事件之后加入到workQueue。
- VM对象的Event事件直接加入workQueue。
- VMI对象的Event事件先判断是否由VM对象所控制,如果是则将该VM对象加入workQueue,否则找到匹配的VM,将匹配的VM加入到workQueue,尝试收养孤儿的VMI对象。
- DataVolume对象的Event事件先判断是否由VM对象所控制,如果是则将该VM对象加入workQueue,否则不处理。
- 通过Run()->runWorker()->Execute()->execute(),从workQueue中取出对象的key,然后在execute中处理。
- execute()函数的处理逻辑
- 根据key,从Informer的本地缓存中获取VM对象。
- 创建VirtualMachineControllerRefManager。
- 根据key,从Informer的本地缓存中获取VMI对象
- 如果获取VMI对象成功,则VirtualMachineControllerRefManager尝试收养或遗弃VMI。
- 根据Spec.DataVolumeTemplates,从Informer的本地缓存中获取dataVolumes。
- 检查dataVolumes是否已经ready,若已经ready则调用startStop()
- RunStrategy==Always:虚拟机实例VMI应该总是存在,如果虚拟机实例VMI crash,会创建一个新的虚拟机。等同于spec.running:true。
- RunStrategy==RerunOnFailure:如果虚拟机实例VMI运行失败,会创建一个新的虚拟机。如果是由客户端主动成功关闭,则不会再重新创建。
- RunStrategy==Manual:虚拟机实例VMI运行状况通过start/stop/restart手工来控制。
- RunStrategy==Halted:虚拟机实例VMI应该总是挂起。等同于spec.running:false。
- 更新VMStatus
- 修改vm.Status.Created,vm.Status.Ready
- 修改vm.Status.StateChangeRequests
- 修改vm.Status.Conditions
- 更新VMStatus
VMIController分析
代码位于kubevirt/pkg/virt-controller/watch/vmi.go文件中。
- 监听VMI对象、Pod对象、DataVolume对象并添加对应的EventHandler。
- 收到Event事件之后加入到workQueue。
- VMI对象的Event事件直接加入workQueue。
- Pod对象的Event事件先判断是否由VM对象所控制,如果是则将该VM对象加入workQueue,否则不处理。
- DataVolume对象的Event事件,根据DataVolume的Namespace和Name获取匹配的vmis,然后将vmis对象依次加入到workQueue。
- 通过Run()->runWorker()->Execute()->execute(),从workQueue中取出对象的key,然后在execute中处理。
- execute()函数的处理逻辑
- 根据key,从Informer的本地缓存中获取VM对象。
- 获取和当前vmi对象匹配的Pod。
- 根据vmi.Spec.Volumes,获取匹配的DataVolumes对象。
- 同步sync,若Pod不存在,则创建lanucher所在的Pod。
- 更新vmi对象的status。
MigrationController分析
代码位于kubevirt/pkg/virt-controller/watch/migration.go文件中。
- 监听Migration对象、VMI对象、Pod对象并添加对应的EventHandler。
- 收到Event事件之后加入到workQueue。
- VMI对象的Event事件直接加入workQueue。
- Pod对象的Event事件,根据Pod的Annotation中的migrationJonName来找到对应的migration对象,然后加入workQueue。
- VMI对象的Event事件,根据vmi的Namespace和Name获取匹配的Migration对象,然后加入到workQueue。
- 通过Run()->runWorker()->Execute()->execute(),从workQueue中取出对象的key,然后在execute中处理。
- execute()函数的处理逻辑
- 根据key,从Informer的本地缓存中获取Migration对象。
- 根据Migration.namespace和Migration对象.Spec.VMIName来获取VMI对象。
- 获取迁移目标Pod。
- 同步sync。
- 更新Migration对象的status,Migration.Status.Phase状态转换为:
ReplicaSetController分析
代码位于kubevirt/pkg/virt-controller/watch/replicaset.go文件中。
- 监听replicaSet对象、VMI对象并添加对应的EventHandler。
- 收到Event事件之后加入到workQueue。
- VMI对象的Event事件直接加入workQueue。。
- VMI对象的Event事件,先判断是否由replicaSet对象控制,如果是则将该replicaSet加入到workQueue,否则找到与该VMI对象匹配的replicaSets,然后将replicaSets依次加入workQueue,尝试将该VMI对象收养。
- 通过Run()->runWorker()->Execute()->execute(),从workQueue中取出对象的key,然后在execute中处理。
- execute()函数的处理逻辑
- 根据key,从Informer的本地缓存中获取Migration对象。
- 根据namespaces获取vmis。
- 根据获取replicaSet对象,创建VMControllerRefManager,然后尝试收养或遗弃vmis。
- 将vmis分成两组finishedVmis和activeVmis。
- 根据Spec.Replicas以及当前replicaset管理的activeVmis,对vmis进行扩容或者缩容。
- 更新replicaSet的Status。
总结
本文章基于kubevirt 0.35版本,重点讲解了kubevirt架构及对virt-controller源码设计进行分析。由于篇幅有限,本文主要帮助读者理清virt-controller的主要设计思路,起到穿针引线效果,下一篇我们将对handler组件进行分析。
CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。扫描二维码关注CNCF微信公众号。
更多推荐
所有评论(0)