2020年CNCF中国云原生调查邀你一起来参与!

Image

问卷链接(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的部署架构,如图:

Image

从架构图中可以看出:

  • 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函数中的内容。

  1. 获取leaderElectionConfiguration
  2. 获取KubevirtClient
  3. 获取informerFactory,并实例化一系列具体资源类型的Informer,例如crdInformer、kubeVirtInformer、vmiInformer、kvPodInformer、nodeInformer、vmInformer、migrationInformer等
  4. 初始化一系列controller,包括vmiController、nodeController、migrationController、vmController、evacuationController、snapshotController、restoreController、replicaSetController、disruptionBudgetController
  5. 通过leaderElector来启动virt-controller,并在leaderElector中启动各个controller的Run函数。

VMController分析

代码位于kubevirt/pkg/virt-controller/watch/vm.go文件中。

  1. 监听VM对象、VMI对象、DataVolume对象并添加对应的EventHandler。
  2. 收到Event事件之后加入到workQueue。
    • VM对象的Event事件直接加入workQueue。
    • VMI对象的Event事件先判断是否由VM对象所控制,如果是则将该VM对象加入workQueue,否则找到匹配的VM,将匹配的VM加入到workQueue,尝试收养孤儿的VMI对象。
    • DataVolume对象的Event事件先判断是否由VM对象所控制,如果是则将该VM对象加入workQueue,否则不处理。
  3. 通过Run()->runWorker()->Execute()->execute(),从workQueue中取出对象的key,然后在execute中处理。
  4. 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文件中。

  1. 监听VMI对象、Pod对象、DataVolume对象并添加对应的EventHandler。
  2. 收到Event事件之后加入到workQueue。
    • VMI对象的Event事件直接加入workQueue。
    • Pod对象的Event事件先判断是否由VM对象所控制,如果是则将该VM对象加入workQueue,否则不处理。
    • DataVolume对象的Event事件,根据DataVolume的Namespace和Name获取匹配的vmis,然后将vmis对象依次加入到workQueue。
  3. 通过Run()->runWorker()->Execute()->execute(),从workQueue中取出对象的key,然后在execute中处理。
  4. execute()函数的处理逻辑
    • 根据key,从Informer的本地缓存中获取VM对象。
    • 获取和当前vmi对象匹配的Pod。
    • 根据vmi.Spec.Volumes,获取匹配的DataVolumes对象。
    • 同步sync,若Pod不存在,则创建lanucher所在的Pod。
    • 更新vmi对象的status。

MigrationController分析

代码位于kubevirt/pkg/virt-controller/watch/migration.go文件中。

  1. 监听Migration对象、VMI对象、Pod对象并添加对应的EventHandler。
  2. 收到Event事件之后加入到workQueue。
    • VMI对象的Event事件直接加入workQueue。
    • Pod对象的Event事件,根据Pod的Annotation中的migrationJonName来找到对应的migration对象,然后加入workQueue。
    • VMI对象的Event事件,根据vmi的Namespace和Name获取匹配的Migration对象,然后加入到workQueue。
  3. 通过Run()->runWorker()->Execute()->execute(),从workQueue中取出对象的key,然后在execute中处理。
  4. execute()函数的处理逻辑
    • 根据key,从Informer的本地缓存中获取Migration对象。
    • 根据Migration.namespace和Migration对象.Spec.VMIName来获取VMI对象。
    • 获取迁移目标Pod。
    • 同步sync。
    • 更新Migration对象的status,Migration.Status.Phase状态转换为:
      Image

ReplicaSetController分析

代码位于kubevirt/pkg/virt-controller/watch/replicaset.go文件中。

  1. 监听replicaSet对象、VMI对象并添加对应的EventHandler。
  2. 收到Event事件之后加入到workQueue。
    • VMI对象的Event事件直接加入workQueue。。
    • VMI对象的Event事件,先判断是否由replicaSet对象控制,如果是则将该replicaSet加入到workQueue,否则找到与该VMI对象匹配的replicaSets,然后将replicaSets依次加入workQueue,尝试将该VMI对象收养。
  3. 通过Run()->runWorker()->Execute()->execute(),从workQueue中取出对象的key,然后在execute中处理。
  4. 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组件进行分析。

点击到达KubeVirt网站


CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。扫描二维码关注CNCF微信公众号。
在这里插入图片描述

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐