编辑推荐: |
本文介绍了采用Kubernetes管理虚拟机的起源、发展和具体实现技术,重点讲述了KubeVirt的原理、架构和实现方式,以及KubeVirt在OpenShift上面的企业级发行版——OpenShift虚拟化及其功能介绍。
本文来自于开源博客,由火龙果软件Linda编辑、推荐。 |
|
1 背景
随着这些年容器技术和云原生技术的发展,Kubernetes在2017年容器编排大战中击败Docker
Swarm和Mesos之后,进一步发展壮大,到现在为止,基本上一统公有云的容器服务(xKS服务)和私有云的容器云PaaS平台,成为事实上的容器编排标准。从这个意义上讲,我们可以称Kubernetes为云原生计算的操作系统。
但另外一方面,在企业的数据中心或私有云平台上,甚至是公有云平台上面,大部分应用还没有进行容器化,还是以传统二进制代码的方式运行在虚拟机上面。对于某些客户来讲,他们不希望在运营一个以管理传统虚拟机为主的IaaS平台或虚拟化平台(比如OpenStack或者VMWare)之外,在同时运营另外一个基于Kubernetes的容器平台。因此,一个自然而然的想法就是,既然Kubernetes在容器编排领域如此成功,能不能使用同一个Kubernetes平台同时编排和调度虚拟机?
早在容器编排大战尚未尘埃落定之前的2016年10月,红帽的3个工程师就创建了KubeVirt社区(https://kubevirt.io/)
, 期望能够用Kubernetes统一编排容器和虚拟机。KubeVirt社区的愿景就是将传统的虚拟机和最新的容器技术统一由Kubernetes进行管理和编排。这个愿景也体现在KubeVirt社区官方KubeVirt总体架构图中(图1
– KubeVirt总体架构, 来源:https://github.com/kubevirt/kubevirt/blob/master/docs/architecture.md
)。
图1
– KubeVirt总体架构
本文将主要介绍KubeVirt以及红帽基于Kubevirt发行的企业版即OpenShift虚拟化的原理和主要功能。
需要提到的是,希望使用Kubernetes编排和调度虚拟机的并不是只有KubeVirt一个社区。大概也是2016年左右,Mirantis建立了Virtlet社区(https://github.com/Mirantis/virtlet)。尽管目标相同,但Kubevirt和Virtlet社区采用了不同的实现方式:KubeVirt主要是采用Kubernetes的自定义资源CRD(Custom
Resource Definition)来管理虚拟机,而Virtlet是通过实现容器运行接口CRI(Container
Runtime Interface)的方式利用新建一个特殊的容器运行时来实现虚拟机的管理。
2 在容器里面跑虚拟机?
容器里面运行的应用程序本质上是一个进程。容器技术通过采用Linux的命名空间(namespace)和控制组(cgroup)等内核技术,可以通过容器实现进程隔离,并且可以对隔离的进程进行资源分配控制。既然,容器里面真正运行的是进程,那么,我们如何能让在容器里面跑虚拟机呢?
在采用KVM做hypervisor的Linux机器上面,从hypervisor的角度来看,虚拟机的的确确就是一个KVM进程。为了验证这一点,我们可以做一个小实验。在图2
中,我们在RHEL 上面通过执行virsh start命令启动了一个虚拟机。我们可以看到,这个虚拟机最后对应到一个qemu-kvm的进程。
图2 – Linux上面的虚拟机进程
在上面这个实验中,我们实际使用了Linux这么几个组件:
virsh - Linux提供管理虚拟机的命令行工具,它通过调用libvirt提供的API进行虚拟机的管理。
libvirt - libvirt是一组开源虚拟机管理API,可以支持多个hypervisor,包括QEMU和KVM。
QEMU - QEMU是一个VMM(Virtual Machine Monitor),用于进行硬件的模拟。本质上QEMU就是一个hypervisor,但是由于Linux内核的KVM模块使用了Intel和AMD芯片内置的硬件虚拟化功能。所以,QEMU和KVM实际上一起配合使用。在这种情况下,
QEMU一般被称为QEMU-KVM,具体负责除了CPU和内存之外的硬件模拟,比如模拟网卡,磁盘等;同时,QEMU还会将CPU和内存的虚拟化指令直接发送给核心态的KVM。
KVM – KVM是Linux内核提供的虚拟化架构,通过处理器硬件提供的虚拟化扩展功能,可以实现CPU和内存的虚拟化。
既然虚拟机本质是Linux用户空间的一个QEMU-KVM进程,那么,这个进程就可以在容器内部运行。图3是在OpenShift
上面运行的虚拟机pod里面的进程,我们可以看到,虚拟机进程以及其他一些辅助进程都存在。
图3 – 虚拟机pod里面的进程
本质上来讲,KubeVirt的虚拟化功能,除了没有直接使用virsh创建虚拟机(但pod里面也是可以运行virsh命令的),
本质上也是采用libvirt, QEMU和KVM等同样的虚拟化核心技术来实现的,如图4所示。
图4 – 虚拟机容器的架构
虚拟化一般包括计算、网络和存储的虚拟化,在解决了计算的虚拟化之后,接下来我们再来看一下网络虚拟化。
由于虚拟机是运行在pod里面,在一般情况下,pod使用的是动态分配的IP地址,这个跟虚拟机需要一个固定IP地址的要求不符合。在OpenShift中,我们采用了一个叫做Multus的功能模块,这个功能模块可以允许pod同时连接到多个网络中,如图5所示。
图5 – pod的多网卡功能
我们可以在上图的第二块网卡net0上指定一个静态的IP地址以实现固定IP地址的目标。
就存储而已,KubeVirt使用Kubernetes原生的存储资源:存储类(StorageClass),持久卷请求(PVC)和持久卷(PV)来挂载和管理虚拟机的磁盘。
3 KubeVirt的实现方式
KubeVirt充分采用了Kubernetes方式扩展了Kubernetes,主要在以下3个方面进行了扩展:
VM相关的自定义资源CRD被增加到Kubernetes API中间。新增的CRD包括VirtualMachine,
VirtualMachineInstance, VirtualMachineInstanceMigration,
DataVolume等。
新建的虚拟机控制器,用于实现上述相关CRD在增、删、改时应该执行的相关操作。
每个节点上面的守护进程virt-handler(具体实现方式是运行在Kubernetes集群里面的DaemonSet),可以认为是KubeVirt的kubelet。Virt-handler和kubelet一起,用于创建虚拟机实例(VMI),以达到CRD中期望的状态。
图6是KubeVirt社区官方的详细架构图,列出了KubeVirt对Kubernetes的扩展组件。
图6 – KubeVirt详细架构
以下是一个创建虚拟机的大致流程:
1. 客户端通过kubectl 创建一个VMI的CRD请求,该请求被K8S API Server收到。
2. K8S API Server转发到virt-api, virt-api经过验证之后创建一个VMI的CRD对象。
3. virt-controller检测到VMI的创建,引发创建一个pod。
4. Kubernetes调度该pod到某个节点。
5. virt-controller检测到对应VMI的pod已经启动,更新VMI的CRD定义里面nodeName字段。现在既然nodeName字段已经赋值,接下来由该节点上面的virt-handler进行相关操作。
6. virt-handler检测到一个VMI已经调度到它所在的节点,它会使用VMI中的定义内容跟virt-launcher通信。virt-launcher会在VMI
pod中创建一个虚拟机,并且负责该虚拟机的生命周期管理。
在VMI pod内部,virt-launcher是该pod的主要容器。virt-launcher的主要功能是为虚拟机进程准备控制组和命名空间。在接收到来virt-hander创建虚拟机的命令后,virt-launcher将会使用自己容器内部libvirtd创建一个虚拟机实例。
KubeVirt还有一个命令行工具virtctl, 可以用来管理虚拟机,比如启动,关机,暂停,迁移,重启以及连接文本或图形终端等功能。
KubeVirt采用Operator方式安装:首先安装Operator, 然后创建一个CRD。
使用kubectl部署KubeVirt Operator
export VERSION=$(curl -s https://api.github.com/repos/kubevirt/kubevirt/releases
| grep tag_name | grep -v -- '-rc' | head -1 | awk
-F': ' '{print $2}' | sed 's/,//' | xargs)
echo $VERSION
kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-operator.yaml
创建KubeVirt自定义资源
详细安装过程请参考KubeVirt官方文档https://kubevirt.io/quickstart_kind/。
值得注意的是,如果K8S集群本身运行在虚拟机里面,那么需要打开嵌套虚拟化。
kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-cr.yaml
4 OpenShift虚拟化
OpenShift虚拟化,是红帽基于上游社区KubeVirt推出的经过加固和增强的企业发行版,作为OpenShift的一个组件提供。OpenShift虚拟化原来名称为容器原生虚拟化(Container
Native Virtualization,以下简称CNV),最初在OpenShift 3.11作为一个附加组件以技术预览的方式发布。随着CNV和KubeVirt以及OpenShift的发展和完善,在2020年4月份发布的OpenShift
4.5中以组件名称“OpenShift虚拟化”作为生产就绪型附加功能正式推出,当时版本为2.4,现在在OpenShift
4.6中最新的版本为2.5。
OpenShift虚拟化的目标不是仅仅只提供传统虚拟化技术比如红帽虚拟化或VMWare vSphere之外的另一种选择,而是一种基于Kubernetes的全新技术,能够将传统的、基于虚拟机的应用与云原生的、容器化的应用进行整合(参见图7-OpenShift虚拟化总体架构)。Kubernetes能够为虚拟机提供高可用性、调度、安全、资源管理等功能,就像为容器提供这些功能一样。
图7 – OpenShift虚拟化总体架构
OpenShift虚拟化的大致业务场景包括这么三个:
客户尚未建立虚拟化环境,目前期望建立容器云平台,希望统一用容器云平台管理容器化应用和传统的应用。
客户在进行容器化转型,但原来的大型单体应用到现代微服务的应用改造不是一蹴而就的,需要通过一个比较长的周期,进行多次迭代才能完成的。在这个转型周期中,通过容器云平台统一管理传统的大型单体应用(基于虚拟机)和新创建的微服务应用有利于降低转型过程的复杂度。
5G时代的边缘计算场景。边缘计算场景新的应用基本都是按照容器化进行开发的,但另外一方面,也存在一些传统的基于虚拟机的应用。通过使用OpenShift虚拟化,就可以将两者结合起来,如果再结合OpenShift多集群的管理功能,就可以进行边缘计算的统一管理,实现云边协同的效果。
OpenShift虚拟化充分使用了OpenShift完整生态,在可靠性、稳定性、易用性以及生态友好性方面,大大超出了其上游社区KubeVirt。
除了支持类似KubeVirt命令行方式的安装,OpenShift虚拟化安装还可以采用OpenShift
OperatorHub软件商店的方式,从而可以做到一键式安装和部署,如图8、图9和图10所示。
图8 – OpenShift Operator Hub中的OpenShift Virtualization
Operator
图9 – 安装OpenShift Virtualization Operator
图10 – 创建OpenShift Virtualization CRD实例
在安装了OpenShift Virtualization之后,用户就可以在自己的项目里面通过OpenShift控制台或者命令行工具创建、查询、修改或删除虚拟机了,如图11、12、13所示。
图11 – 创建虚拟机
图12 – 管理虚拟机
图13 – 虚拟机信息显示
在创建虚拟机的时候,用户可以指定虚拟机的启动引导方式、虚拟机的规格、工作负载类型(用于设置KVM性能相关参数)、网络、存储、cloud-init设置等。OpenShift虚拟化也支持从红帽虚拟化或者VMWare中导入虚机。在管理虚拟机的时候,用户可以启动/停止/重启虚机,也可以进行虚机的热迁移(live
migration)、克隆、删除等操作。
如果用户需要连接到虚机内部,可以直接使用OpenShift控制台的内置终端,也可以采用virtctl命令行工具。
5 总结
KubeVirt提供的容器虚拟化技术,让Kubernetes统一管理容器技术和传统虚拟化变为可能,从应用编排进入了基础设施编排,从而为Kubernetes从以前单纯的容器编排工具到将来进化为企业数据中心和私有云的大一统编排引擎了打开了一扇大门。
OpenShift虚拟化在KubeVirt的基础上,为企业客户提供了生产级就绪环境所需要的功能和性能加固和增强,同时结合OpenShift良好的生态,包括裸机管理、GPU直通、软件定义网络、OpenShift容器原生存储,为客户提供了一个开箱即用的容器和虚拟化相融合的云平台。 |