2020年CNCF中国云原生考察邀你一起来参加!

问卷链接(https://www.wjx.cn/jq/9714648...)


廖旋威:目前就任于新华三云计算,次要从事云原生行业,对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函数中的内容。

  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](https://mmbiz.qpic.cn/mmbiz_png/GpkQxibjhkJwJqTYd1jNuyHSNgCkX8WpeRSCLglMQGDomqmiajjPCUVAslUmkW4hVic1L4CH6XswjTBPVjdticKgXA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)

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微信公众号。