天天看點

【KVM系列06】Nova 通過 libvirt 管理 QEMU/KVM 虛機

                                                                  第六章 Nova 通過 libvirt 管理 QEMU/KVM 虛機

1. Libvirt 在 OpenStack 架構中的位置

2. Nova 中 libvirt 的使用

2.1 建立 QEMU/KVM 虛機

2.2 添加 volume 到虛機 (nova volume-attach)

2.3 添加連接配接到新的網絡的 interface 給虛機 (nova interface-attach)

【KVM系列文章】https://blog.csdn.net/baidu_37107022/article/details/88812463

1. Libvirt 在 OpenStack 架構中的位置

在 Nova Compute 節點上運作的 nova-compute 服務調用 Hypervisor API 去管理運作在該 Hypervisor 的虛機。Nova 使用 libvirt 管理 QEMU/KVM 虛機,還使用别的 API 去管理别的虛機。

【KVM系列06】Nova 通過 libvirt 管理 QEMU/KVM 虛機
【KVM系列06】Nova 通過 libvirt 管理 QEMU/KVM 虛機

libvirt 的實作代碼在 /nova/virt/libvirt/driver.py 檔案中。

這裡是 OpenStack Hypervisor Matrix。

這裡是 每個 Linux 發行版裡面 libvirt, QEMU/KVM 的版本号。

請注意Juno 版本 Nova 對 libvirt 和 QEMU 的各種最低版本要求:

功能 最低 libvirt 版本 最低 QEMU 版本 不支援的後果
所有  0.9.11  Nova 不能使用 libvirt driver
支援 device callback  1.1.1 不支援的話,就無法支援 Detach PCI/SR-IOV 裝置
Live snapshot 1.3.0 1.3.0  隻能使用 Clod Snapshot
挂載卷時設定卷的 block 大小(Block IO) 0.10.2 不能使用的話,就不能設定卷的特定 block size,隻能使用其預設的 block size。
Block Job Info 1.1.1 不能線上删除卷的快照 (online deletion of volume snapshots)
Discard 1.0.6 1.6.0
不支援 image 設定 hw_disk_discard 屬性,具體參考 BluePrint
           
NUMA topology 1.0.4  無法擷取 node 的 NUMA topology 資訊,就無法将虛機的 vCPU 指定到特定的 node CPU 上,會影響虛機的性能

2. Nova 中 libvirt 的使用

Nova 使用 libvirt 來管理虛機,包括:

  • 建立虛機
  • 虛機的生命周期管理(參考這篇文檔)
  • 添加和删除連接配接到别的網絡的網卡 (interface)
  • 添加和删除 Cinder 卷 (volume)

2.1 建立 QEMU/KVM 虛機

建立虛機的配置有幾個來源:

  • 使用者的選項,包括虛機的基本資訊,比如 name,flavor,image,network,disk等。
  • image 的屬性,比如 hw_vif_model,hw_scsi_model 等。完整的供 libvirt API 使用的屬性清單 在這裡。
  • 管理者在 nova.conf 中的配置

(注意:image 的中繼資料屬性的優先級高于 nova.conf 中的配置。隻有在沒有property的情況下才使用nova.conf中的配置)

建立虛機的過程的幾個主要階段:

(1)消息由 nova-api 路由到某個 nova compute 節點 (API -> Scheduler -> Compute (manager) -> Libvirt Driver)

(2)調用 Neutron REST API 去準備網絡。其傳回的資料類似:

[VIF({'profile': {}, 'ovs_interfaceid': u'59cfa0b8-2f5c-481a-89a8-7a8711b368a2', 'network': Network({'bridge': 'br-int', 'subnets': [Subnet({'ips': [FixedIP({'meta': {}, 'version': 4, 'type': 'fixed', 'floating_ips': [], 'address': u'10.0.10.14'})], 'version': 4, 'meta': {'dhcp_server': u'10.0.10.11'}, 'dns': [], 'routes': [], 'cidr': u'10.0.10.0/24', 'gateway': IP({'meta': {}, 'version': 4, 'type': 'gateway', 'address': u'10.0.10.1'})})], 'meta': {'injected': False, 'tenant_id': u'74c8ada23a3449f888d9e19b76d13aab'}, 'id': u'a924e87a-826b-4109-bb03-523a8b3f6f9e', 'label': u'demo-net2'}), 'devname': u'tap59cfa0b8-2f', 'vnic_type': u'normal', 'qbh_params': None, 'meta': {}, 'details': {u'port_filter': True, u'ovs_hybrid_plug': True}, 'address': u'fa:16:3e:e0:30:e7', 'active': False, 'type': u'ovs', 'id': u'59cfa0b8-2f5c-481a-89a8-7a8711b368a2', 'qbg_params': None})]
           

(3)從 image 啟動話,nova 會調用 Glane REST API 後者 image metadata 和準備本地啟動盤

image metadata:

{u'status': u'active', u'deleted': False, u'container_format': u'bare', u'min_ram': 0, u'updated_at': u'2015-04-26T04:34:40.000000', u'min_disk': 0, u'owner': u'74c8ada23a3449f888d9e19b76d13aab', u'is_public': False, u'deleted_at': None, u'properties': {}, u'size': 13167616, u'name': u'image', u'checksum': u'64d7c1cd2b6f60c92c14662941cb7913', u'created_at': u'2015-04-26T04:34:39.000000', u'disk_format': u'qcow2', u'id': u'bb9318db-5554-4857-a309-268c6653b9ff'}
           

本地啟動盤:

{'disk_bus': 'virtio', 'cdrom_bus': 'ide', 'mapping': {'disk': {'bus': 'virtio', 'boot_index': '1', 'type': 'disk', 'dev': u'vda'}, 'root': {'bus': 'virtio', 'boot_index': '1', 'type': 'disk', 'dev': u'vda'}, 'disk.local': {'bus': 'virtio', 'type': 'disk', 'dev': 'vdb'}, 'disk.swap': {'bus': 'virtio', 'type': 'disk', 'dev': 'vdc'}}} 
           

本地啟動盤的檔案資訊:

[email protected]:/home/s1# qemu-img info /var/lib/nova/instances/02699155-940f-4401-bc01-36220db80639/disk.local

image: /var/lib/nova/instances/02699155-940f-4401-bc01-36220db80639/disk.local

file format: qcow2

virtual size: 1.0G (1073741824 bytes) #由 flavor.ephemeral_disk 指定其 size disk size: 324K

cluster_size: 65536

backing file: /var/lib/nova/instances/_base/ephemeral_1_default

Format specific information:

compat: 1.1

lazy refcounts: false


[email protected]:/home/s1# qemu-img info /var/lib/nova/instances/02699155-940f-4401-bc01-36220db80639/disk.swap

image: /var/lib/nova/instances/02699155-940f-4401-bc01-36220db80639/disk.swap

file format: qcow2

virtual size: 30M (31457280 bytes) # 由 flavor.swap_disk 指定其size disk size: 196K

cluster_size: 65536

backing file: /var/lib/nova/instances/_base/swap_30

Format specific information:

compat: 1.1

lazy refcounts: false
           

(4)根據這些資訊,生成 domain xml,然後生成其配置使得它是一個持久性虛機 (調用 libvirt Python DefineXML API)。

一個從 image 啟動的 Domain 的配置 XML 執行個體(藍色部分是注釋說明):

<domain type="qemu">

8352e969-0a25-4abf-978f-d9d0ec4de0cd

instance-0000002f

51200 # guest.memory = flavor.memory_mb * units.Ki 即 50 * 1024 = 51200 <vcpu cpuset="0">1 #flavor.vcpus

<nova:instance xmlns:nova="http://openstack.org/xmlns/libvirt/nova/1.0">

<nova:package version="2014.2.2"/>

vm11 #input.name 2015-06-09 23:54:04

<nova:flavor name="tiny2"> #input.flavor 50

1

30

1

1



<nova:user uuid="bcd37e6272184f34993b4d7686ca4479">admin

<nova:project uuid="74c8ada23a3449f888d9e19b76d13aab">admin


<nova:root type="image" uuid="bb9318db-5554-4857-a309-268c6653b9ff"/> #input.source


<sysinfo type="smbios"> # Nova 中寫死的

<entry name="manufacturer">OpenStack Foundation

<entry name="product">OpenStack Nova

<entry name="version">2014.2.2

<entry name="serial">03bb1a0f-ae04-4765-9f3c-d200a2540675

<entry name="uuid">8352e969-0a25-4abf-978f-d9d0ec4de0cd




hvm #表示 Guest OS 需要 full virtualiaiton 支援 <boot dev="hd"/> #指定啟動盤 <smbios mode="sysinfo"/> #去讀取 的定義


# Soft Reboot 需要 ACPI 的支援,否則隻能使用 Hard reboot。 https://bugs.launchpad.net/horizon/+bug/1346741 # 沒 APIC 的話,Windows Guest 會在 Xen 或者 KVM 上崩潰。 https://bugs.launchpad.net/nova/+bug/1086352

<clock offset="utc"/> #如果Guest OS 是 MS,則是 localtime,否則都是 utc <cpu mode="host-model" match="exact"> # 對于 KVM,如果 CONF.libvirt.cpu_mode 是 none,mode 則設為 "host-model"。具體可參考 https://wiki.openstack.org/wiki/LibvirtXMLCPUModel <topology sockets="1" cores="1" threads="1"/> #預設的時候,sockets 數目設為 vcpu 的數目,cores 和 threads 都設為 1. 可以通過設定 image 的 hw_cpu_topology 屬性來改變這裡的設定,具體請參考 https://blueprints.launchpad.net/nova/+spec/support-libvirt-vcpu-topology 以及 https://wiki.openstack.org/wiki/VirtDriverGuestCPUMemoryPlacement


<disk type="file" device="disk"> # 從 image 啟動時候的啟動盤(flavor.root_disk) <driver name="qemu" type="qcow2" cache="none"/>

<source file="/var/lib/nova/instances/8352e969-0a25-4abf-978f-d9d0ec4de0cd/disk"/>

<target bus="virtio" dev="vda"/> #對于 KVM,disk 的 bus 為 "virtio",cdrom 的 bus 為 "ide",floppy 的 bus 為 "fdc"

<disk type="file" device="disk"> #臨時分區 (falvor.ephemeral_disk) <driver name="qemu" type="qcow2" cache="none"/>

<source file="/var/lib/nova/instances/8352e969-0a25-4abf-978f-d9d0ec4de0cd/disk.local"/>

<target bus="virtio" dev="vdb"/>


<disk type="file" device="disk"> #swap 分區 (flavor.swap_disk) <driver name="qemu" type="qcow2" cache="none"/>

<source file="/var/lib/nova/instances/8352e969-0a25-4abf-978f-d9d0ec4de0cd/disk.swap"/>

<target bus="virtio" dev="vdc"/>


<interface type="bridge"> # 虛機通過網橋連接配接到 OVS <mac address="fa:16:3e:e0:30:e7"/>

<model type="virtio"/> #該 type 可以由 image metadata hw_vif_type 指定。未指定的話,如果配置了 conf.libvirt.use_virtio_for_bridges = true (預設就是 true)的話,QEMU/KVM 會使用 virtio 類型。 <driver name="qemu"/>

<source bridge="qbr59cfa0b8-2f"/> #qbr59cfa0b8-2f 連接配接虛機的 vNIC tap59cfa0b8-2f 和 qvb59cfa0b8-2f ,而 qvb59cfa0b8-2f 練到 OVS 的 br-int 上。 <target dev="tap59cfa0b8-2f"/>

</interface>

<serial type="file"> 當 CONF.serial_console.enabled = true 時,type 為 "tcp",使用 config 配置,其 XML 為 ;當為 false 時,使用 console.log 檔案,type 為 file。 <source path="/var/lib/nova/instances/8352e969-0a25-4abf-978f-d9d0ec4de0cd/console.log"/>


<serial type="pty"/> #每個domain都有 type 為 "pty" 的 serial 配置。 <input type="tablet" bus="usb"/> #當 CONF.vnc_enabled = true 或者 CONF.spice.enabled = true 并且 CONF.spice.agent_enabled = false 時添加 tablet,type 和 bus 都是固定的。 <graphics type="vnc" autoport="yes" keymap="en-us" listen="0.0.0.0"/> #如果 CONF.vnc_enabled = true,那麼 keymap=CONF.vnc_keymap;listen=CONF.vncserver_listen #如果 CONF.vnc_enabled 或者 CONF.spice.enabled,則添加該 video 配置 <model type="cirrus"/> #如果 CONF.spice.enabled,則 type 為 qxl;否則為 cirrus。

<memballoon model="virtio"> #如果 CONF.libvirt.mem_stats_period_seconds >0 則添加 memballoon;對 KVM,model 固定為 "virtio" <stats period="10"/>


           

從 bootable volume 啟動的話,disk 部分為:

<disk type="file" device="disk">

<driver name="qemu" type="qcow2" cache="none"/>

<source file="/var/lib/nova/instances/02699155-940f-4401-bc01-36220db80639/disk.local"/>

<target bus="virtio" dev="vdb"/>


<disk type="file" device="disk">

<driver name="qemu" type="qcow2" cache="none"/>

<source file="/var/lib/nova/instances/02699155-940f-4401-bc01-36220db80639/disk.swap"/>

<target bus="virtio" dev="vdc"/>



26446902-5a56-4c79-b839-a8e13a66dc7a
           

(5). 啟動 domain (調用 libvirt Python createWithFlags API)

2.2 添加 volume 到虛機 (nova volume-attach)

(1)使用 volume id 通過 volume driver 找到指定的 volume

(2)調用 volume driver 來建立主機和 Volume 之間的連接配接

主機資訊為: 

{'ip': '192.168.1.15', 'host': 'compute2', 'initiator': 'iqn.1993-08.org.debian:01:a9f2b45c24f9'} 
           

建立的 iSCSI 連接配接資訊為:

{u'driver_volume_type': u'iscsi', u'data': {u'access_mode': u'rw', u'target_discovered': False, u'encrypted': False, u'qos_specs': None, u'target_iqn': u'iqn.2010-10.org.openstack:volume-51da0d1f-0a17-4e7f-aeff-27438963348a', u'target_portal': u'10.0.2.41:3260', u'volume_id': u'51da0d1f-0a17-4e7f-aeff-27438963348a', u'target_lun': 1, u'auth_password': u'hXG64qrzEjNt8MDKnERA', u'auth_username': u'fKSAe6vhgyeG88U9kcBV', u'auth_method': u'CHAP'}} 
           

volume 在主機上的磁盤為:

[email protected]:/home/s1# ls /dev/disk/by-path/ -ls

total 0

0 lrwxrwxrwx 1 root root 9 Jun 10 12:18 ip-10.0.2.41:3260-iscsi-iqn.2010-10.org.openstack:volume-51da0d1f-0a17-4e7f-aeff-27438963348a-lun-1 -> ../../sdc

Disk /dev/sdc: 1073 MB, 1073741824 bytes

34 heads, 61 sectors/track, 1011 cylinders, total 2097152 sectors

Units = sectors of 1 * 512 = 512 bytes

Sector size (logical/physical): 512 bytes / 512 bytes

I/O size (minimum/optimal): 512 bytes / 512 bytes

Disk identifier: 0x00000000

Disk /dev/sdc doesn't contain a valid partition table

(3)通過 domain name 來找到指定 domain 對象 (通過調用 lookupByName API)

(4)生成 volume 連接配接的配置 xml,比如: 51da0d1f-0a17-4e7f-aeff-27438963348a

(5)調用 attachDeviceFlags API 将 volume 挂載到該虛機

2.3 添加連接配接到新的網絡的 interface 給虛機 (nova interface-attach)

(1)運作 nova  interface-attach,傳入 network-id,Neutron 會配置設定如下network info 給 Nova

VIF({'profile': {}, 'ovs_interfaceid': u'0142efee-7382-43ef-96e8-d0084ecc893c', 'network': Network({'bridge': u'br-int', 'subnets': [Subnet({'ips': [FixedIP({'meta': {}, 'version': 4, 'type': u'fixed', 'floating_ips': [], 'address': u'10.0.0.40'})], 'version': 4, 'meta': {u'dhcp_server': u'10.0.0.3'}, 'dns': [], 'routes': [], 'cidr': u'10.0.0.0/24', 'gateway': IP({'meta': {}, 'version': 4, 'type': u'gateway', 'address': u'10.0.0.1'})})], 'meta': {u'injected': False, u'tenant_id': u'74c8ada23a3449f888d9e19b76d13aab'}, 'id': u'01630966-b21f-4a6d-95ff-10c4575f1fe2', 'label': u'demo-net'}), 'devname': u'tap0142efee-73', 'vnic_type': u'normal', 'qbh_params': None, 'meta': {}, 'details': {u'port_filter': True, u'ovs_hybrid_plug': True}, 'address': u'fa:16:3e:14:32:d9', 'active': True, 'type': u'ovs', 'id': u'0142efee-7382-43ef-96e8-d0084ecc893c', 'qbg_params': None})
           

(2)執行下面的指令,将 Neutron 配置設定的 port 連接配接到 OVS 

#添加 linux bridge

brctl addbr qbr0142efee-73 #名字是 devname 的後半部分 brctl setfd qbr0142efee-73 0 brctl stp qbr0142efee-73 off

tee /sys/class/net/qbr0142efee-73/bridge/multicast_snooping


ip link add qvb0142efee-73 type veth peer name qvo0142efee-73 ip link set qvb0142efee-73 ip link set qvb0142efee-73 promisc on


#在 OVS 上添加端口

ovs-vsctl --timeout=120 -- --if-exists del-port qvo0142efee-73 -- add-port br-int qvo0142efee-73 -- set Interface qvo0142efee-73 external-ids:iface-id=0142efee-7382-43ef-96e8-d0084ecc893c external-ids:iface-status=active external-ids:attached-mac=fa:16:3e:14:32:d9 external-ids:vm-uuid=8352e969-0a25-4abf-978f-d9d0ec4de0cd
           

(3)生成 interface 配置的xml,比如:

(4)調用 attachDeviceFlags API 來挂載該 interface 到虛機

 至于其他的虛機操作,會在另一篇文章中描述。