kubevirt在360的探索之路(k8s接管虛擬化)
來(lái)源:360云計(jì)算
KubeVirt是一個(gè)Kubernetes插件,在調(diào)度容器之余也可以調(diào)度傳統(tǒng)的虛擬機(jī)。它通過使用自定義資源(CRD)和其它 Kubernetes 功能來(lái)無(wú)縫擴(kuò)展現(xiàn)有的集群,以提供一組可用于管理虛擬機(jī)的虛擬化的API。本文作者經(jīng)過長(zhǎng)時(shí)間對(duì)kubevirt的調(diào)研和實(shí)踐,總結(jié)了kubevirt的一些關(guān)鍵技術(shù)和使用經(jīng)驗(yàn),現(xiàn)在就跟隨作者一起探討下吧。

背景簡(jiǎn)介
OpenStack轉(zhuǎn)型K8S
?
技術(shù)選型
有了以上想法以后,就開始調(diào)研,發(fā)現(xiàn)業(yè)界在從openstack轉(zhuǎn)型k8s的過程中涌現(xiàn)了這么一部分比較好的項(xiàng)目,例如,kubevirt,virtlet,rancher/vm等,但是社區(qū)活躍度最高,設(shè)計(jì)最好的還是kubevirt。
https://kubevirt.io/2017/technology-comparison.html
文章核心談了幾個(gè)點(diǎn):
kubevirt是不是一個(gè)vm管理平臺(tái)的替代品,和OpenStack還有ovirt等虛擬化管理平臺(tái)的區(qū)別。 簡(jiǎn)單來(lái)說(shuō):kubevirt只是用k8s管vm,其中會(huì)復(fù)用k8s的cni和csi,所以只是用operator的方式來(lái)操作vm,他不去管網(wǎng)絡(luò)和存儲(chǔ)等。所以和OpenStack中包含nova,neutron,cinder等不一樣,可以理解成kubevirt是一個(gè)k8s框架下的,用go寫的nova vm管理組件。 kubevirt和kata的區(qū)別。
簡(jiǎn)單來(lái)說(shuō):kata是有著vm的安全性和隔離性,以容器的方式運(yùn)行,有著容器的速度和特點(diǎn),但不是一個(gè)真正的vm,而kubevirt是借用k8s的擴(kuò)展性來(lái)管vm,你用到的是一個(gè)真正的vm。
kubevirt和virtlet的區(qū)別。
簡(jiǎn)單來(lái)說(shuō):virtlet是把vm當(dāng)成一個(gè)cri來(lái)跑了,是按pod api來(lái)定義一個(gè)vm,所以vm的很多功能比如熱遷移等,virtlet是沒法滿足vm的全部特性的,算是一個(gè)70%功能的vm。
?
為啥要用k8s管vm,而不是用OpenStack管容器。
簡(jiǎn)單來(lái)說(shuō):k8s+容器是未來(lái)的主流方向,但是由于歷史和業(yè)務(wù)需要,vm也會(huì)存在很長(zhǎng)時(shí)間,所以我們一套支持vm的容器管理平臺(tái)k8s,而不是需要一套支持容器的vm管理平臺(tái)例如OpenStack管容器Magnum這種類似項(xiàng)目。
選型插曲
所以kubevirt這種項(xiàng)目也是在很多從iaas OpenStack轉(zhuǎn)型paas k8s的人群中有更多共鳴,年輕k8s原住民可能對(duì)這個(gè)項(xiàng)目沒有太多感知。因?yàn)閗ubevirt的發(fā)起方redhat,和核心開發(fā)者以前也是OpenStack社區(qū)的項(xiàng)目owner等。所以kubevirt的一些測(cè)試公司和用戶也都是有此類共同轉(zhuǎn)型背景的人和公司。
?
基于如上考慮,最終技術(shù)選型確定了kubevirt,接下來(lái)對(duì)kubevirt的一些概念和邏輯架構(gòu),還有在360的測(cè)試和驗(yàn)證之路做一個(gè)簡(jiǎn)單介紹。
1
Kubevirt 是什么
Kubevirt 是 Redhat 開源一套以容器方式運(yùn)行虛擬機(jī)的項(xiàng)目,通過 kubernetes 云原生來(lái)管理虛擬機(jī)生命周期。
2
Kubevirt CRD
在介紹kubevirt 前我們先了解一下CRD,在kubernetes里面有一個(gè)核心思想既一切都是資源,如同Puppet 里面一切都是資源思想。CRD 是kubernetes 1.7之后添加的自定義資源二次開發(fā)來(lái)擴(kuò)展kubernetes API,通過CRD 可以向API 中添加資源類型,該功能提升了 Kubernetes 的擴(kuò)展能力,那么KUBEVIRT 有哪些需要我們理解的CRD資源,這些資源會(huì)在我們的學(xué)習(xí)和理解過程中都是需要注意的,大概簡(jiǎn)介紹如下幾種:

3
Kubevirt 組件介紹
與OpenStack 類似, kubevirt 每個(gè)組件負(fù)責(zé)不同的功能,不同點(diǎn)是資源調(diào)度策略由k8s 去管理,其中主要組件如下: virt-api,virt-controller,virt-handler,virt-launcher。

4
Kubevirt 常見操作
type DomainManager interface {//SyncVMI 為創(chuàng)建虛擬機(jī)SyncVMI(*v1.VirtualMachineInstance, bool, *cmdv1.VirtualMachineOptions) (*api.DomainSpec, error)//暫停VMIPauseVMI(*v1.VirtualMachineInstance) error//恢復(fù)暫停的VMIUnpauseVMI(*v1.VirtualMachineInstance) errorKillVMI(*v1.VirtualMachineInstance) error//刪除VMIDeleteVMI(*v1.VirtualMachineInstance) errorSignalShutdownVMI(*v1.VirtualMachineInstance) errorMarkGracefulShutdownVMI(*v1.VirtualMachineInstance) errorListAllDomains() ([]*api.Domain, error)//遷移VMIMigrateVMI(*v1.VirtualMachineInstance, *cmdclient.MigrationOptions) errorPrepareMigrationTarget(*v1.VirtualMachineInstance, bool) errorGetDomainStats() ([]*stats.DomainStats, error)//取消遷移CancelVMIMigration(*v1.VirtualMachineInstance) error//如下需要啟用Qemu guest agent,沒啟用會(huì)包VMI does not have guest agent connectedGetGuestInfo() (v1.VirtualMachineInstanceGuestAgentInfo, error)GetUsers() ([]v1.VirtualMachineInstanceGuestOSUser, error)GetFilesystems() ([]v1.VirtualMachineInstanceFileSystem, error)SetGuestTime(*v1.VirtualMachineInstance) error}
5
kubevirt 虛機(jī)VMI
[root@openstack825 ~]# kubectl get vmi -o wideNAME AGE PHASE IP NODENAME LIVE-MIGRATABLEtest100.foo.demo.example.com 8d Running 192.168.10.30 10.10.67.244 Truetest200.foo.demo.example.com 8d Running 192.168.10.31 10.10.67.245 True
獲取已安裝的kubevirt pod[root@openstack825 ~]# kubectl -n kubevirt get podNAME READY STATUS RESTARTS AGEvirt-api-68c958dd-6sx4n 1/1 Running 0 14dvirt-api-68c958dd-sldgr 1/1 Running 0 14dvirt-controller-647d666bd5-gsnzf 1/1 Running 1 14dvirt-controller-647d666bd5-hshnz 1/1 Running 1 14dvirt-handler-4g7ck 1/1 Running 3 14dvirt-handler-kzv86 1/1 Running 0 14dvirt-handler-m2ppb 1/1 Running 0 14dvirt-handler-v6fgt 1/1 Running 0 14dvirt-operator-65ccf74f56-b82kz 1/1 Running 0 14dvirt-operator-65ccf74f56-zs2xq 1/1 Running 0 14dvirtvnc-947874d99-hn7k5 1/1 Running 0 6d19h
總結(jié):同時(shí)我們?cè)谡{(diào)研過程遇到一些問題,比如重啟數(shù)據(jù)丟失、VMI 重啟和熱遷移后IP 改變、鏡像導(dǎo)入數(shù)據(jù)緩慢、VMI 啟動(dòng)調(diào)度緩慢、熱遷移網(wǎng)絡(luò)與存儲(chǔ)支持等等。Kubevirt 通過CRD 方式將 VM 管理接口接入到k8s集群,而 POD 使用 libvirtd 管理VMI,如容器一樣去管理VMI,最后通過標(biāo)準(zhǔn)化插件方式管理調(diào)度網(wǎng)絡(luò)和存儲(chǔ)資源對(duì)象,將其整合在一起形成一套 具有 K8s 管理虛擬化的技術(shù)棧。
6
kubevirt 存儲(chǔ)
cloudInitNoCloud/cloudInitConfigDrive:用于提供 cloud-init 初始化所需要的 user-data,使用 configmap 作為數(shù)據(jù)源,此時(shí)VMI 內(nèi)部將出現(xiàn)第二塊大約為356KB的第二塊硬盤。 devices:disks:disk:bus: virtioname: cloudinitcloudInitNoCloud:userData: |#cloud-configpassword: kubevirt~]$ lsblkNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTvda 253:0 0 47G 0 disk253:1 0 47G 0 part /vdb 253:16 0 366K 0 diskdataVolume:虛擬機(jī)啟動(dòng)流程中自動(dòng)將虛擬機(jī)磁盤導(dǎo)入 pvc 的功能,在不使用 DataVolume 的情況下,用戶必須先準(zhǔn)備帶有磁盤映像的 PVC,然后再將其分配給 VM 或 VMI。dataVolume 拉取鏡像的來(lái)源可以是HTTP、PVC。
spec:pvc:accessModes:ReadWriteManyvolumeMode: Blockresources:requests:storage: 55GstorageClassName: csi-rbd-scsource:http:url: http://127.0.0.1:8081/CentOS7.4_AMD64_2.1PersistentVolumeClaim: PVC 做為后端存儲(chǔ),適用于數(shù)據(jù)持久化,即在虛擬機(jī)重啟或關(guān)機(jī)后數(shù)據(jù)依然存在。PV 類型可以是 block 和 filesystem,為 filesystem 時(shí),將使用 PVC 上的 disk.img,格式為 RAW 格式的文件作為硬盤。block 模式時(shí),使用 block volume 直接作為原始?jí)K設(shè)備提供給虛擬機(jī)。缺點(diǎn)在于僅支持RAW格式鏡像,若鏡像較大CDI 導(dǎo)入鏡像會(huì)比較慢(如果是QCW2 CDI 內(nèi)部機(jī)制qemu.go 會(huì)將其進(jìn)行格式轉(zhuǎn)換為RAW并導(dǎo)入PVC中),因此降低快速創(chuàng)建 VMI 體驗(yàn)感。當(dāng)然社區(qū)目前支持一種較smart-clone 方式導(dǎo)入,目前筆者還沒進(jìn)行測(cè)試。
spec:pvc:accessModes:ReadWriteManyvolumeMode: Blockresources:requests:storage: 55GstorageClassName: csi-rbd-scsource:pvc:namespace: "default"name: "q18989v.cloud.bjyt.qihoo.net"
ephemeral、containerDisk: 數(shù)據(jù)是無(wú)法持久化,故在存儲(chǔ)選型上,我們采用 CEPH 作為后端存儲(chǔ),通過調(diào)用Ceph CSI 插件創(chuàng)建 PVC 卷方式管理虛機(jī)磁盤設(shè)備。Ceph CSI 插件實(shí)現(xiàn)了容器存儲(chǔ)編排與Ceph集群交互的接口,它可以為容器應(yīng)用分配 存儲(chǔ)集群中的存儲(chǔ)空間,同時(shí)在選擇 Ceph-CSI 版本需要考慮到當(dāng)前 K8S 版本、及 CEPH 版本號(hào)。
當(dāng)前支持的版本列表:
Dynamically provision, de-provision Block mode RWX volume
?
支持RBD 塊 RWX 的模式,使用此模式主要涉及到Kubevirt 熱遷移場(chǎng)景,虛擬機(jī)調(diào)用 VirtualMachineInstanceMigration CRD 資源,熱遷移時(shí)會(huì)檢測(cè)Volume 模式,此時(shí)塊設(shè)備必須 RWX 模式,代碼如下. ?
?
位置:pkg/vm-handler/vm.go
//主要通過調(diào)用磁盤、網(wǎng)絡(luò)相關(guān)函數(shù),來(lái)判斷當(dāng)前VMI 是否適合遷移func (d *VirtualMachineController) calculateLiveMigrationCondition(vmi *v1.VirtualMachineInstance, hasHotplug bool) (*v1.VirtualMachineInstanceCondition, bool) {liveMigrationCondition := v1.VirtualMachineInstanceCondition{Type: v1.VirtualMachineInstanceIsMigratable,Status: k8sv1.ConditionTrue,}//調(diào)用 checkvolume 方法isBlockMigration, err := d.checkVolumesForMigration(vmi)if err != nil {//如果返回錯(cuò)誤信息則會(huì)限制遷移liveMigrationCondition.Status = k8sv1.ConditionFalseliveMigrationCondition.Message = err.Error()liveMigrationCondition.Reason = v1.VirtualMachineInstanceReasonDisksNotMigratablereturn &liveMigrationCondition, isBlockMigration}//調(diào)用網(wǎng)絡(luò)模式檢查方法err = d.checkNetworkInterfacesForMigration(vmi)if err != nil {liveMigrationCondition = v1.VirtualMachineInstanceCondition{Type: v1.VirtualMachineInstanceIsMigratable,Status: k8sv1.ConditionFalse,Message: err.Error(),Reason: v1.VirtualMachineInstanceReasonInterfaceNotMigratable,}return &liveMigrationCondition, isBlockMigration}if hasHotplug {liveMigrationCondition = v1.VirtualMachineInstanceCondition{Type: v1.VirtualMachineInstanceIsMigratable,Status: k8sv1.ConditionFalse,Message: "VMI has hotplugged disks",Reason: v1.VirtualMachineInstanceReasonHotplugNotMigratable,}return &liveMigrationCondition, isBlockMigration}return &liveMigrationCondition, isBlockMigration}
//checkvolume 定義/檢查所有VMI卷共享可以在源和實(shí)時(shí)遷移的目的地之間熱遷移//當(dāng)所有卷均已共享且VMI沒有本地磁盤時(shí),blockMigrate才返回True//某些磁盤組合使VMI不適合實(shí)時(shí)遷移, 在這種情況下,將返回相關(guān)錯(cuò)誤func (d *VirtualMachineController) checkVolumesForMigration(vmi *v1.VirtualMachineInstance) (blockMigrate bool, err error) {for _, volume := range vmi.Spec.Volumes {volSrc := volume.VolumeSourceif volSrc.PersistentVolumeClaim != nil || volSrc.DataVolume != nil {var volName stringif volSrc.PersistentVolumeClaim != nil {volName = volSrc.PersistentVolumeClaim.ClaimName} else {volName = volSrc.DataVolume.Name}//pvcutils.IsSharedPVCFromClient_, shared, err := pvcutils.IsSharedPVCFromClient(d.clientset, vmi.Namespace, volName)if errors.IsNotFound(err) {return blockMigrate, fmt.Errorf("persistentvolumeclaim %v not found", volName)} else if err != nil {return blockMigrate, err}if !shared {return true, fmt.Errorf("cannot migrate VMI with non-shared PVCs")}} else if volSrc.HostDisk != nil {shared := volSrc.HostDisk.Shared != nil && *volSrc.HostDisk.Sharedif !shared {return true, fmt.Errorf("cannot migrate VMI with non-shared HostDisk")}} else {blockMigrate = true}}return}func IsSharedPVCFromClient(client kubecli.KubevirtClient, namespace string, claimName string) (pvc *k8sv1.PersistentVolumeClaim, isShared bool, err error) {pvc, err = client.CoreV1().PersistentVolumeClaims(namespace).Get(claimName, v1.GetOptions{})if err == nil {//IsPVCSharedisShared = IsPVCShared(pvc)}return}//IsPVCShared Shared 判斷,函數(shù)返回bool 類型,成功則返回truefunc IsPVCShared(pvc *k8sv1.PersistentVolumeClaim) bool {//循環(huán)PVC的accessModesfor _, accessMode := range pvc.Spec.AccessModes {if accessMode == k8sv1.ReadWriteMany {return true}}return false}
Ceph CSi 啟動(dòng)的POD 進(jìn)程
[root@kubevirt01 ~]# kubectl get podNAME READY STATUS RESTARTS AGEcsi-rbdplugin-7bprd 3/3 Running 0 14dcsi-rbdplugin-fl5c9 3/3 Running 0 14dcsi-rbdplugin-ggj9q 3/3 Running 0 14dcsi-rbdplugin-provisioner-84bb9bdd56-7qtnh 6/6 Running 0 14dcsi-rbdplugin-provisioner-84bb9bdd56-sdscf 6/6 Running 0 14dcsi-rbdplugin-provisioner-84bb9bdd56-xjz2r 6/6 Running 0 14dcsi-rbdplugin-svfv2
? ? ? ??
已創(chuàng)建的VMI 對(duì)應(yīng)的 PVC卷
---apiVersion: v1kind: PersistentVolumeClaimmetadata:name: testzhangsanlisispec:accessModes:ReadWriteManyvolumeMode: Blockresources:requests:storage: 10GistorageClassName: csi-rbd-sckubectl apply -f pvc-test.yaml~]# kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEtestzhangsanlisi Bound pvc-2c98391d-a2eb-4dd1-a1f0-2a8ef27d4ca3 10Gi RWX csi-rbd-sc 3s
CEPH 架構(gòu)相關(guān),使用三副本策略,不同交換機(jī)下及高容量 SATA 盤 作為 OSD 數(shù)據(jù)載體,保證數(shù)據(jù)的可用性
/]# ceph -scluster:id: d8ab2087-f55c-4b8f-913d-fc60d6fc455dhealth: HEALTH_OKservices:mon: 3 daemons, quorum 192.168.10.100 192.168.20.100 192.168.30.100 (age 4d)mgr: ceph100(active, since 4d), standbys: ceph200, ceph300osd: 27 osds: 27 up (since 2w), 27 in (since 2w)data:pools: 1 pools, 1024 pgsobjects: 55.91k objects, 218 GiBusage: 682 GiB used, 98 TiB / 98 TiB availpgs: 1024 active+cleanio:client: 2.2 KiB/s wr, 0 op/s rd, 0 op/s wr/]# ceph dfRAW STORAGE:CLASS SIZE AVAIL USED RAW USED %RAW USEDhdd 98 TiB 98 TiB 655 GiB 682 GiB 0.68TOTAL 98 TiB 98 TiB 655 GiB 682 GiB 0.68
7
kubevirt 網(wǎng)絡(luò)

VMI 通信流程
kubernetes是Kubevirt 底座,提供了管理容器和虛擬機(jī)的混合部署的方式,存儲(chǔ)和網(wǎng)絡(luò)也是通過集成到kubernetes中, VMI 使用了POD進(jìn)行通信。為了實(shí)現(xiàn)該目標(biāo),KubeVirt 的對(duì)網(wǎng)絡(luò)做了特殊實(shí)現(xiàn)。虛擬機(jī)具體的網(wǎng)絡(luò)如圖所示, virt-launcher Pod 網(wǎng)絡(luò)的網(wǎng)卡不再掛有 Pod IP,而是作為虛擬機(jī)的虛擬網(wǎng)卡的與外部網(wǎng)絡(luò)通信的交接物理網(wǎng)卡。
在當(dāng)前的場(chǎng)景我們使用經(jīng)典的大二層網(wǎng)絡(luò)模型,用戶在一個(gè)地址空間下,VM 使用固定IP,在OpenStack社區(qū),虛擬網(wǎng)絡(luò)方案成熟,OVS 基本已經(jīng)成為網(wǎng)絡(luò)虛擬化的標(biāo)準(zhǔn)。所以我門選擇目前靈雀云(alauda) 開源的網(wǎng)絡(luò)方案:Kube-OVN,它是基于OVN的Kubernetes網(wǎng)絡(luò)組件,提供了大量目前Kubernetes不具備的網(wǎng)絡(luò)功能,并在原有基礎(chǔ)上進(jìn)行增強(qiáng)。通過將OpenStack領(lǐng)域成熟的網(wǎng)絡(luò)功能平移到Kubernetes,來(lái)應(yīng)對(duì)更加復(fù)雜的基礎(chǔ)環(huán)境和應(yīng)用合規(guī)性要求。?

Kube-OVN 是一款基于 OVS/OVN 的 Kubernetes網(wǎng)絡(luò)項(xiàng)目
網(wǎng)絡(luò) VLAN underlay
在網(wǎng)絡(luò)平面,管理網(wǎng)和 VMI 虛擬機(jī)流量分開,其中使用Vlan 模式的 underlay 網(wǎng)絡(luò),容器網(wǎng)絡(luò)可以直接通過 vlan 接入物理交換機(jī)
Yaml地址段來(lái)自源與網(wǎng)絡(luò)物理設(shè)備分配時(shí)spec:cidrBlock: 192.168.10.0/23default: trueexcludeIps:192.168.10.1gateway: 192.168.10.1gatewayNode: ""gatewayType: distributed需要設(shè)置成falsenatOutgoing: falseprivate: falseprotocol: IPv4provider: ovn//需要設(shè)置成true,若為false,會(huì)在主機(jī)側(cè)加上route,導(dǎo)致net不通underlayGateway: truevlan: ovn-vlan
[root@kubevirt01 ~]# kubectl -n kube-system get podNAME READY STATUS RESTARTS AGEcoredns-65dbdb44db-8bxlr 1/1 Running 33 17dkube-ovn-cni-4v4xb 1/1 Running 0 18dkube-ovn-cni-kvgrj 1/1 Running 0 18dkube-ovn-cni-nj2pr 1/1 Running 0 18dkube-ovn-cni-xv476 1/1 Running 0 18dkube-ovn-controller-7f6db69b48-6c7w8 1/1 Running 0 18dkube-ovn-controller-7f6db69b48-82kjt 1/1 Running 0 18dkube-ovn-controller-7f6db69b48-mhkfc 1/1 Running 0 18dkube-ovn-pinger-n2rn4 1/1 Running 0 18dkube-ovn-pinger-s4hrz 1/1 Running 0 18dkube-ovn-pinger-tccz5 1/1 Running 0 18dkube-ovn-pinger-x2tqq 1/1 Running 0 18dovn-central-775c4ff46d-4nqjw 1/1 Running 1 18dovn-central-775c4ff46d-822v2 1/1 Running 0 18dovn-central-775c4ff46d-txkn8 1/1 Running 0 18dovs-ovn-mbpv2 1/1 Running 0 18dovs-ovn-r9mvc 1/1 Running 0 18dovs-ovn-wkxld 1/1 Running 0 18dovs-ovn-z89hw 1/1 Running 0 18d
虛擬機(jī)固定IP
k8s的資源是在運(yùn)行時(shí)才分配ip的,但是筆者希望能夠?qū)μ摂M機(jī)的ip進(jìn)行綁定從而實(shí)現(xiàn)固定ip的目的。為此,我們首先正常創(chuàng)建虛擬機(jī),在虛擬機(jī)運(yùn)行時(shí)k8s會(huì)為之分配ip,當(dāng)檢測(cè)到虛擬機(jī)的ip后,我們通過替換vmi的配置文件的方式將ip綁定改虛擬機(jī)中。但是在實(shí)際操作時(shí)會(huì)報(bào)出如下錯(cuò)誤:
Invalid value: 0x0: must be specified for an update實(shí)際上 Kubernetes API Server是支持樂觀鎖(Optimistic concurrency control)的機(jī)制來(lái)防止并發(fā)寫造成的覆蓋寫問題,因此在修改的body中需要加入metadata.resourceVersion,筆者的做法是首選調(diào)用 read_namespaced_virtual_machine方法獲取metadata.resourceVersion,其次再修改body。具體方案可參考:
https://www.codeleading.com/article/27252474726/8
kubevirt SDK
kubevirt sdk現(xiàn)狀 ? ?當(dāng)前kubevirt提供了Python版本以及Golang版本的SDK,具體的信息參考如下:
https://github.com/kubevirt/client-pythonhttps://github.com/kubevirt/client-go
筆者實(shí)際使用的是python的sdk,所以接下來(lái)重點(diǎn)敘述一下python版本的sdk的使用心得,使用時(shí)發(fā)現(xiàn)了一些問題,并加以解決也將在下面的內(nèi)容中記錄。
sdk實(shí)現(xiàn)的功能本章筆者詳細(xì)介紹一下使用到的一些sdk中的功能,在初體驗(yàn)的過程中筆者只是用了部分功能,完整的功能可以詳見github。
創(chuàng)建使用實(shí)例
sdk主要使用的是kubevirt.apis.default_api中的DefaultApi對(duì)象,進(jìn)行接口調(diào)用個(gè)的。DefaultApi對(duì)象需要ApiClient對(duì)象,該對(duì)象實(shí)際上是連接k8s的實(shí)例。因此在使用之前,需要在底層的k8s中起一個(gè)proxy。通過創(chuàng)建DefaultApi對(duì)象即可調(diào)用后續(xù)的接口了,具體的創(chuàng)建方法如下:
import kubevirtdef get_api_client(host):api_client = kubevirt.ApiClient(host=host, header_name="Content-Type", header_value="application/json")return api_clientapi_client = get_api_client(host="http://127.0.0.1:8001")api_instance = kubevirt.DefaultApi(api_client)kubvirt sdk 的本質(zhì)
實(shí)際上我們知道,kubevirt是在k8s中定義了集中CRD,那么調(diào)用kubevirt的sdk實(shí)際上也是調(diào)用k8s中CRD相關(guān)接口,通過查看k8中CRD的接口我們知道,具體的url表示為:/apis/{group}/{version}/namespaces/{namespace}/{plural}/{name}因此重要的是找到group以及plural參數(shù)具體是什么。通過下圖可以看出group都是kubevirt.io,plural根據(jù)需要的不同可以定義不同的類型

sdk部分功能以及注意事項(xiàng)
筆者主要使用了以下的功能:
創(chuàng)建虛擬機(jī)( create_namespaced_virtual_machine) 注意:body是json格式,官方sdk的example有誤刪除虛擬機(jī)( delete_namespaced_virtual_machine)展示某個(gè)namespace下的vm資源( list_namespaced_virtual_machine)展示某個(gè)namespace下的vmi資源( list_namespaced_virtual_machine_instance)展示所有namespace下的vm資源( list_virtual_machine_for_all_namespaces)展示所有namespace下的vmi資源( list_virtual_machine_instance_for_all_namespaces)獲取某個(gè)namespace某個(gè)name下的vm資源( read_namespaced_virtual_machine)獲取某個(gè)namespace某個(gè)name下的vmi資源( read_namespaced_virtual_machine_instance) 注意:在獲取vm資源時(shí)無(wú)法獲取到node_name,uuid,ip的數(shù)據(jù),獲取vmi資源時(shí)無(wú)法獲取到disk以及image_url的數(shù)據(jù),筆者認(rèn)為vm是虛擬機(jī)資源,vmi是虛擬機(jī)實(shí)例資源,只有在running狀態(tài)下的vm才是vmi,由于k8s中ip是動(dòng)態(tài)分配的,因此才會(huì)出現(xiàn)node_name,uuid,ip數(shù)據(jù)在vm中獲取不到啟動(dòng)虛擬機(jī)( v1alpha3_start)停止虛擬機(jī)( v1alpha3_stop)重啟虛擬機(jī)( v1alpha3_restart) 注意: 重啟虛擬機(jī)只能在虛擬機(jī)狀態(tài)是running是才能調(diào)用,否則會(huì)失敗修改虛擬機(jī)名稱( v1alpha3_rename)替換虛擬機(jī)的配置文件( replace_namespaced_virtual_machine_instance)
sdk使用注意事項(xiàng)
k8s版本問題
官方給出的kubevirt sdk中對(duì)于創(chuàng)建刪除以及替換配置文件等部分接口,k8s版本是固定的穩(wěn)定版v1版本,這顯然不滿足于sdk的靈活使用,因此筆者在使用時(shí)對(duì)api版本進(jìn)行了兼容,保證用戶可以通過傳參的形式正確的使用。
修改虛擬機(jī)名稱缺乏參數(shù)
誠(chéng)如標(biāo)題所述,修改虛擬機(jī)名稱接口官方給出的參數(shù)有誤,缺乏新名稱參數(shù)


筆者通過查看virtclt源碼找到了缺少的參數(shù)的具體名稱并添加至sdk中,具體代碼如下:
def v1alpha3_rename_with_http_info(self, name, newName, namespace, **kwargs):"""Rename a stopped VirtualMachine object.This method makes a synchronous HTTP request by default. To make anasynchronous HTTP request, please define a `callback` functionto be invoked when receiving the response.>>> def callback_function(response):>>> pprint(response)>>>>>> thread = api.v1alpha3_rename_with_http_info(name, namespace, newName, callback=callback_function):param callback function: The callback functionfor asynchronous request. (optional):param str name: Name of the resource (required):param str namespace: Object name and auth scope, such as for teams and projects (required):param str newName: NewName of the resource (required):return: strIf the method is called asynchronously,returns the request thread."""all_params = ['name', 'namespace', 'newName']all_params.append('callback')all_params.append('_return_http_data_only')all_params.append('_preload_content')all_params.append('_request_timeout')params = locals()for key, val in iteritems(params['kwargs']):if key not in all_params:raise TypeError("Got an unexpected keyword argument '%s'"" to method v1alpha3_rename" % key)params[key] = valdel params['kwargs']# verify the required parameter 'name' is setif ('name' not in params) or (params['name'] is None):raise ValueError("Missing the required parameter `name` when calling `v1alpha3_rename`")# verify the required parameter 'namespace' is setif ('namespace' not in params) or (params['namespace'] is None):raise ValueError("Missing the required parameter `namespace` when calling `v1alpha3_rename`")collection_formats = {}path_params = {}# if 'name' in params:# path_params['name'] = params['name']# if 'namespace' in params:# path_params['namespace'] = params['namespace']query_params = []header_params = {}form_params = []local_var_files = {}body_params = {"newName": params["newName"]}# Authentication settingauth_settings = []api_route = "/apis/subresources.kubevirt.io/v1alpha3/namespaces/{namespace}/virtualmachines/{name}/rename".format(namespace=params["namespace"], name=params["name"])return self.api_client.call_api(api_route, 'PUT',path_params,query_params,header_params,body=body_params,post_params=form_params,files=local_var_files,response_type='str',auth_settings=auth_settings,callback=params.get('callback'),_return_http_data_only=params.get('_return_http_data_only'),_preload_content=params.get('_preload_content', True),_request_timeout=params.get('_request_timeout'),collection_formats=collection_formats)
9
Ultron 平臺(tái)創(chuàng)建基于kubevirt 的虛擬機(jī)
奧創(chuàng)平臺(tái)是公司內(nèi)的私有云管理平臺(tái)(類似horizon),可以通過其管理openstack VM,本次我們同時(shí)納入到對(duì)Kubevirt 虛擬機(jī)的支持,創(chuàng)建方式和OpenStack方式一樣。最后用戶體驗(yàn)和功能特性也和OpenStack一致,用戶本身也是不關(guān)注底層實(shí)現(xiàn),性能特性方面后續(xù)文章會(huì)有對(duì)比。

10
總結(jié)
kubevirt作為一個(gè)兼容方案,當(dāng)前在cncf中孵化的也挺好,好像也要開始自己的KubeVirt Summit,主要是實(shí)際的解決了一些痛點(diǎn),但目前看,kubevirt還是適合在私有云,肯定滿足不了公有云,因?yàn)閗8s在iaas方面有先天劣勢(shì),所以kubevirt應(yīng)該是給大家在私有云領(lǐng)域落地虛擬化除了用OpenStack以外多了一種選擇方案。
相關(guān)文章
https://kubevirt.io/
https://xie.infoq.cn/article/9c911e195aa9b02a69f875489

關(guān)注「開源Linux」加星標(biāo),提升IT技能
