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 函数中的内容。
- 获取 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 状态转换为:
![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 文件中。
- 监听 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 组件进行剖析。
点击达到 KubeVirt 网站。
CNCF (Cloud Native Computing Foundation) 成立于 2015 年 12 月,隶属于 Linux Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培养和保护一个厂商中立的开源生态系统,来推广云原生技术。咱们通过将最前沿的模式民主化,让这些翻新为公众所用。扫描二维码关注 CNCF 微信公众号。