学习 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': , 'type': 'fixed', 'floating_ips': [], 'address': u'10.0.10.14'})], 'version': , 'meta': {'dhcp_server': u'10.0.10.11'}, 'dns': [], 'routes': [], 'cidr': u'10.0.10.0/24', 'gateway': IP({'meta': {}, 'version': , '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': , u'updated_at': u'2015-04-26T04:34:40.000000', u'min_disk': , u'owner': u'74c8ada23a3449f888d9e19b76d13aab', u'is_public': False, u'deleted_at': None, u'properties': {}, u'size': , 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></memory> # guest.memory = flavor.memory_mb * units.Ki 即 50 * 1024 = 51200
<vcpu cpuset=""></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>-- ::</nova:creationTime>
<nova:flavor name="tiny2"> #input.flavor
<nova:memory></nova:memory>
<nova:disk></nova:disk>
<nova:swap></nova:swap>
<nova:ephemeral></nova:ephemeral>
<nova:vcpus></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.</entry>
<entry name="serial">03bb1a0f-ae04--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="" cores="" threads=""/> #默认的时候,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=""/>
</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-
brctl stp qbr0142efee- off
tee /sys/class/net/qbr0142efee-/bridge/multicast_snooping ip link add qvb0142efee- type veth peer name qvo0142efee-
ip link set qvb0142efee-
ip link set qvb0142efee- promisc on #在 OVS 上添加端口
ovs-vsctl --timeout= -- --if-exists del-port qvo0142efee- -- add-port br-int qvo0142efee- -- set Interface qvo0142efee- external-ids:iface-id=0142efee--43ef-96e8-d0084ecc893c external-ids:iface-status=active external-ids:attached-mac=fa::3e:::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 到虚机

至于其他的虚机操作,会在另一篇文章中描述。

KVM 介绍(6):Nova 通过 libvirt 管理 QEMU/KVM 虚机 [Nova Libvirt QEMU/KVM Domain]的更多相关文章

  1. KVM 介绍(8):使用 libvirt 迁移 QEMU/KVM 虚机和 Nova 虚机 [Nova Libvirt QEMU/KVM Live Migration]

    学习 KVM 的系列文章: (1)介绍和安装 (2)CPU 和 内存虚拟化 (3)I/O QEMU 全虚拟化和准虚拟化(Para-virtulizaiton) (4)I/O PCI/PCIe设备直接分 ...

  2. qemu 对虚机的地址空间管理

    转载:http://huchh.com/2015/06/22/qemu-%E5%AF%B9%E8%99%9A%E6%9C%BA%E7%9A%84%E7%BA%BF%E6%80%A7%E5%9C%B0% ...

  3. KVM 介绍(7):使用 libvirt 做 QEMU/KVM 快照和 Nova 实例的快照 (Nova Instances Snapshot Libvirt)

    学习 KVM 的系列文章: (1)介绍和安装 (2)CPU 和 内存虚拟化 (3)I/O QEMU 全虚拟化和准虚拟化(Para-virtulizaiton) (4)I/O PCI/PCIe设备直接分 ...

  4. KVM(六)Nova 通过 libvirt 管理 QEMU/KVM 虚机

    1. Libvirt 在 OpenStack 架构中的位置 在 Nova Compute 节点上运行的 nova-compute 服务调用 Hypervisor API 去管理运行在该 Hypervi ...

  5. KVM 介绍(5):libvirt 介绍 [ Libvrit for KVM/QEMU ]

    学习 KVM 的系列文章: (1)介绍和安装 (2)CPU 和 内存虚拟化 (3)I/O QEMU 全虚拟化和准虚拟化(Para-virtulizaiton) (4)I/O PCI/PCIe设备直接分 ...

  6. KVM(八)使用 libvirt 迁移 QEMU/KVM 虚机和 Nova 虚机

    1. QEMU/KVM 迁移的概念 迁移(migration)包括系统整体的迁移和某个工作负载的迁移.系统整理迁移,是将系统上所有软件包括操作系统完全复制到另一个物理机硬件机器上.虚拟化环境中的迁移, ...

  7. nova系列二:kvm介绍

    一 什么是kvm KVM 全称 Kernel-Based Virtual Machine.也就是说 KVM 是基于 Linux 内核实现的,这就使得linux内核本身就相当于一个Hypervisor. ...

  8. KVM 介绍(1):简介及安装

    学习 KVM 的系列文章: (1)介绍和安装 (2)CPU 和 内存虚拟化 (3)I/O QEMU 全虚拟化和准虚拟化(Para-virtulizaiton) (4)I/O PCI/PCIe设备直接分 ...

  9. kvm介绍、安装及创建虚拟机

    kvm虚拟化介绍 一.虚拟化分类 1.虚拟化,是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机.在一台计算机上同时运行多个逻辑计算机,每个逻辑计算机可运行不同的操作系统,并且应用程序都可以在相互独立 ...

随机推荐

  1. 实用技巧:使用 jQuery 异步加载 JavaScript 脚本

    JavaScript 加载器在 Web 开发中是非常强大和有用的工具.目前流行的几个加载器,像 curljs.LABjs 和 RequireJS 使用都很广泛.他们功能强大的,但有些情况下可以有更简单 ...

  2. Java2_java入门时的一些基本概念的理解(j2ee,j2se,j2me,jdk,sdk,jre,jvm,跨平台)

    什么是SDK呢? Software Develop Kit的简称,顾名思义就是软件开发包.软件开发商实现底层模块,并对其进行类库封装,配置成高级别的开发环境,为程序员上层的程序开发提供支持.譬如Goo ...

  3. IOS 局域网发送信息

    基于ios 例子WiTap 1.创建本地的服务并设置监听时间检测是否有设备连接. NSNetService * server = [[NSNetService alloc] initWithDomai ...

  4. [html5+java]文件异步读取及上传核心代码

    html5+java 文件异步读取及上传关键代码段 功能: 1.多文件文件拖拽上传,file input 多文件选择 2.html5 File Api 异步FormData,blob上传,图片显示 3 ...

  5. 关于html页面head标签顺序

    基本上head就这几个标签么: <meta>.<link>.<title>.<script>.<style>.<base>. 它 ...

  6. Jquery在线引用地址

    Jquery在线引用地址: 1. 很多网站都是使用这种方式引入,客户的浏览器可能已经缓存过了 jquery.可以直接调用本地的,速度更快… 2. Google code 使用了 cdn 技术在很多地方 ...

  7. mysql不同版本和存储引擎选型的验证

    Mysql的版本和存储引擎较多,为了选择最适合业务使用的系统,需要进行一定的验证,本文描述mysql的验证过程和思路. 主要涉及: Mysql的版本 v Mariadb v Tokudb v Orac ...

  8. 虚拟机克隆以后出现“需要整合虚拟机磁盘”的解决方法

    问题描述 在虚拟机克隆完毕以后,原始虚拟机提示"需要整合虚拟机磁盘" 在"任务与事件"栏中看到以下信息 解决方法 从上面可以看到是因为整合失败导致的,那么我们只 ...

  9. JavaScriptSerializer序列化时间处理

    JavaScriptSerializer序列化时间后会把时间序列化成N进制的鬼数据,于是查了下质料坐下记录 假设list = News List<Text>(){new Text(){id ...

  10. JSON数据解析 基础知识及链接收集

    JSON数据解析学习 JSON介绍 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式. JSON 是存储和交换文本信息的语法.类似 XML.但是JSON 比 ...