kubevirt 提供很多种存储方式,存储就决定了你使用虚拟机镜像到底什么内核、什么版本,以下主要讲述我看到三种比较常用的形式
虚拟机镜像(磁盘)是启动虚拟机必不可少的部分,目前 KubeVirt 中提供多种方式的虚拟机磁盘。
dataVolume:虚拟机启动流程中自动将虚拟机磁盘导入 pvc 的功能,在不使用 DataVolume 的情况下,用户必须先准备带有磁盘映像的 PVC,然后再将其分配给 VM 或 VMI。dataVolume 拉取镜像的来源可以是HTTP、PVC。
PersistentVolumeClaim: PVC 做为后端存储,适用于数据持久化,即在虚拟机重启或关机后数据依然存在。PV 类型可以是 block 和 filesystem,为 filesystem 时,将使用 PVC 上的 disk.img,格式为 RAW 格式的文件作为硬盘。block 模式时,使用 block volume 直接作为原始块设备提供给虚拟机。缺点在于仅支持RAW格式镜像,若镜像较大CDI 导入镜像会比较慢(如果是QCW2 CDI 内部机制qemu.go 会将其进行格式转换为RAW并导入PVC中),因此降低快速创建 VMI 体验感
ephemeral、containerDisk: 数据是无法持久化,故在存储选型上,我们采用 CEPH 作为后端存储,通过调用Ceph CSI 插件创建 PVC 卷方式管理虚机磁盘设备。Ceph CSI 插件实现了容器存储编排与Ceph集群交互的接口,它可以为容器应用分配 存储集群中的存储空间,同时在选择 Ceph-CSI 版本需要考虑到当前 K8S 版本、及 CEPH 版本号
定义image来创建虚拟机的root disk。 virt-controller会在pod定义中创建registryVolume的container,container中的entry服务负责 将spec.volumes.registryDisk.image转化为qcow2格式,路径为pod根目录。
kubevirt 提供了registryDIsk的基础镜像: registry-disk-v1alpha, 根据Dockerfile形式去创建虚拟机镜像,以下是window镜像demo Dockerfile
FROM kubevirt/registry-disk-v1alpha
COPY Windows---server-2012-datacenter-64bit-cn-syspreped---2018-01-15.qcow2 /disk/windows2012dc.img
这个最终我们构建成镜像名:windows2012dc:latest , 最终在CRD表现形式是这样的
kind: VirtualMachineInstance
...
spec:
domain:
devices:
disks:
- disk:
bus: virtio
name: registrydisk
volumeName: registryvolume
... - name: registryvolume
registryDisk:
image: windows2012dc:latest
PVC是持久化存储镜像的形式,它会被挂在到pod中,且格式必须满足/disk/*.img,这样kubevirt才能够实现虚拟机存储
CDI是kubevirt自己提供的一种形式, 把registryDisk 转换为PVC,这个需要消耗时间去讲镜像转换为PVC持久化存储下
虚拟机网络就是pod网络,virt-launcher pod网络的网卡不再挂有pod ip,而是作为虚拟机的虚拟网卡的与外部网络通信的交接物理网卡,virt-launcher实现了简单的单ip dhcp server,就是需要虚拟机中启动dhclient,virt-launcher 服务会分配给虚拟机。
kubernetes是Kubevirt 底座,提供了管理容器和虚拟机的混合部署的方式,存储和网络也是通过集成到kubernetes中, VMI 使用了POD进行通信。为了实现该目标,KubeVirt 的对网络做了特殊实现。虚拟机具体的网络如图所示, virt-launcher Pod 网络的网卡不再挂有 Pod IP,而是作为虚拟机的虚拟网卡的与外部网络通信的交接物理网卡
在当前的场景我们使用经典的大二层网络模型,用户在一个地址空间下,VM 使用固定IP,在OpenStack社区,虚拟网络方案成熟,OVS 基本已经成为网络虚拟化的标准。所以我门选择目前灵雀云(alauda) 开源的网络方案:Kube-OVN,它是基于OVN的Kubernetes网络组件,提供了大量目前Kubernetes不具备的网络功能,并在原有基础上进行增强。通过将OpenStack领域成熟的网络功能平移到Kubernetes,来应对更加复杂的基础环境和应用合规性要求
在网络平面,管理网和 VMI 虚拟机流量分开,其中使用Vlan 模式的 underlay 网络,容器网络可以直接通过 vlan 接入物理交换机
k8s的资源是在运行时才分配ip的,但是笔者希望能够对虚拟机的ip进行绑定从而实现固定ip的目的。为此,我们首先正常创建虚拟机,在虚拟机运行时k8s会为之分配ip,当检测到虚拟机的ip后,我们通过替换vmi的配置文件的方式将ip绑定改虚拟机中。但是在实际操作时会报出如下错误:
Invalid value: 0x0: must be specified for an update
实际上 Kubernetes API Server是支持乐观锁(Optimistic concurrency control)的机制来防止并发写造成的覆盖写问题,因此在修改的body中需要加入metadata.resourceVersion,笔者的做法是首选调用 read_namespaced_virtual_machine方法获取metadata.resourceVersion,其次再修改body。具体方案可参考:
https://www.codeleading.com/article/27252474726/
Kube-handler会去调用当前节点下所有虚拟机的libvirt API,获取虚拟机的监控指标,并提供metrics 接口,最后通过kubevirt-prometheus-metrics聚合所有节点的kube-handler的指标数据,提供给prometheus使用