KVM 介紹(6):Nova 通過 libvirt 管理 QEMU/KVM 虛機 [Nova Libvirt QEMU/KVM Domain]


學習 KVM 的系列文章:

1. Libvirt 在 OpenStack 架構中的位置

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

       

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'}}} 

本地啟動盤的文件信息:

root@compute2:/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
root@compute2:/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">
  <uuid>8352e969-0a25-4abf-978f-d9d0ec4de0cd</uuid>
  <name>instance-0000002f</name>
  <memory>51200</memory> # guest.memory = flavor.memory_mb * units.Ki 即 50 * 1024 = 51200
  <vcpu cpuset="0">1</vcpu> #flavor.vcpus
  <metadata>
    <nova:instance xmlns:nova="http://openstack.org/xmlns/libvirt/nova/1.0">
      <nova:package version="2014.2.2"/>
      <nova:name>vm11</nova:name> #input.name
      <nova:creationTime>2015-06-09 23:54:04</nova:creationTime>
      <nova:flavor name="tiny2"> #input.flavor
        <nova:memory>50</nova:memory>
        <nova:disk>1</nova:disk>
        <nova:swap>30</nova:swap>
        <nova:ephemeral>1</nova:ephemeral>
        <nova:vcpus>1</nova:vcpus>
      </nova:flavor>
      <nova:owner>
        <nova:user uuid="bcd37e6272184f34993b4d7686ca4479">admin</nova:user>
        <nova:project uuid="74c8ada23a3449f888d9e19b76d13aab">admin</nova:project>
      </nova:owner>
      <nova:root type="image" uuid="bb9318db-5554-4857-a309-268c6653b9ff"/> #input.source
    </nova:instance>
  </metadata>
  <sysinfo type="smbios"> # Nova 中寫死的
    <system>
      <entry name="manufacturer">OpenStack Foundation</entry>
      <entry name="product">OpenStack Nova</entry>
      <entry name="version">2014.2.2</entry>
      <entry name="serial">03bb1a0f-ae04-4765-9f3c-d200a2540675</entry>
      <entry name="uuid">8352e969-0a25-4abf-978f-d9d0ec4de0cd</entry>
    </system>
  </sysinfo>
  <os>
    <type>hvm</type> #表示 Guest OS 需要 full virtualiaiton 支持
    <boot dev="hd"/> #指定啟動盤
    <smbios mode="sysinfo"/> #去讀取 <sysinfo> 的定義
  </os>
  <features>
    <acpi/> # Soft Reboot 需要 ACPI 的支持,否則只能使用 Hard reboot。 https://bugs.launchpad.net/horizon/+bug/1346741
    <apic/> # 沒 APIC 的話,Windows Guest 會在 Xen 或者 KVM 上崩潰。 https://bugs.launchpad.net/nova/+bug/1086352
  </features>
  <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
  </cpu>
  <devices>
    <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>
    <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>
    <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"/>
    </disk>
    <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 為 <serial type="tcp"> <source host="127.0.0.1" mode="bind" service="10000"/>   </serial>;當為 false 時,使用 console.log 文件,type 為 file。
      <source path="/var/lib/nova/instances/8352e969-0a25-4abf-978f-d9d0ec4de0cd/console.log"/>
    </serial>
    <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
    <video> #如果 CONF.vnc_enabled 或者 CONF.spice.enabled,則添加該 video 配置
      <model type="cirrus"/> #如果 CONF.spice.enabled,則 type 為 qxl;否則為 cirrus。
    </video>
    <memballoon model="virtio"> #如果 CONF.libvirt.mem_stats_period_seconds >0 則添加 memballoon;對 KVM,model 固定為 "virtio"
      <stats period="10"/>
    </memballoon>
  </devices>
</domain>

從 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>
    <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"/>
    </disk>
    <disk type="block" device="disk">
     <driver name="qemu" type="raw" cache="none"/>
     <source dev="/dev/disk/by-path/ip-10.0.2.41:3260-iscsi-iqn.2010-10.org.openstack:volume-26446902-5a56-4c79-b839-a8e13a66dc7a-lun-1"/>
     <target bus="virtio" dev="vda"/>
     <serial>26446902-5a56-4c79-b839-a8e13a66dc7a</serial>
    </disk>

(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 在主機上的磁盤為:

root@compute2:/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,比如:

<disk type="block" device="disk">
    <driver name="qemu" type="raw" cache="none"/>
    <source dev="/dev/disk/by-path/ip-10.0.2.41:3260-iscsi-iqn.2010-10.org.openstack:volume-51da0d1f-0a17-4e7f-aeff-27438963348a-lun-1"/>
    <target bus="virtio" dev="vdd"/>
    <serial>51da0d1f-0a17-4e7f-aeff-27438963348a</serial>
</disk>

(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,比如:

<interface type="bridge">
    <mac address="fa:16:3e:14:32:d9"/>
    <model type="virtio"/>
    <driver name="qemu"/>
    <source bridge="qbr0142efee-73"/>
    <target dev="tap0142efee-73"/>
</interface>

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

 

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM