Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1520445
  • 博文数量: 230
  • 博客积分: 474
  • 博客等级: 下士
  • 技术积分: 1955
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-19 18:40
文章分类

全部博文(230)

文章存档

2020年(3)

2019年(3)

2018年(12)

2017年(13)

2016年(11)

2015年(55)

2014年(74)

2013年(39)

2012年(2)

2011年(18)

我的朋友

分类: 云计算

2015-10-30 11:09:07

学习 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 节点

(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 实例(蓝色部分是注释说明):

"qemu">
  8352e969-0a25-4abf-978f-d9d0ec4de0cd
  instance-0000002f
  51200 # guest.memory = flavor.memory_mb * units.Ki 即 50 * 1024 = 51200 "0">1 #flavor.vcpus 
    "">
      "2014.2.2"/>
      vm11 #input.name 2015-06-09 23:54:04
      "tiny2"> #input.flavor 50
        1
        30
        1
        1
      
      
        "bcd37e6272184f34993b4d7686ca4479">admin
        "74c8ada23a3449f888d9e19b76d13aab">admin
      
      "image" uuid="bb9318db-5554-4857-a309-268c6653b9ff"/> #input.source 
  
  "smbios"> # Nova 中写死的 
      "manufacturer">OpenStack Foundation
      "product">OpenStack Nova
      "version">2014.2.2
      "serial">03bb1a0f-ae04-4765-9f3c-d200a2540675
      "uuid">8352e969-0a25-4abf-978f-d9d0ec4de0cd
    
  
  
    hvm #表示 Guest OS 需要 full virtualiaiton 支持 "hd"/> #指定启动盘 "sysinfo"/> #去读取  的定义 
  
     # Soft Reboot 需要 ACPI 的支持,否则只能使用 Hard reboot。   # 没 APIC 的话,Windows Guest 会在 Xen 或者 KVM 上崩溃。  
  "utc"/> #如果Guest OS 是 MS,则是 localtime,否则都是 utc "host-model" match="exact"> # 对于 KVM,如果 CONF.libvirt.cpu_mode 是 none,mode 则设为 "host-model"。具体可参考   "1" cores="1" threads="1"/> #默认的时候,sockets 数目设为 vcpu 的数目,cores 和 threads 都设为 1. 可以通过设置 image 的 hw_cpu_topology 属性来改变这里的设置,具体请参考  以及  
  
    "file" device="disk"> # 从 image 启动时候的启动盘(flavor.root_disk) "qemu" type="qcow2" cache="none"/>
      "/var/lib/nova/instances/8352e969-0a25-4abf-978f-d9d0ec4de0cd/disk"/>
      "virtio" dev="vda"/> #对于 KVM,disk 的 bus 为 "virtio",cdrom 的 bus 为 "ide",floppy 的 bus 为 "fdc" 
    "file" device="disk"> #临时分区 (falvor.ephemeral_disk) "qemu" type="qcow2" cache="none"/>
      "/var/lib/nova/instances/8352e969-0a25-4abf-978f-d9d0ec4de0cd/disk.local"/>
      "virtio" dev="vdb"/>
    
    "file" device="disk"> #swap 分区 (flavor.swap_disk) "qemu" type="qcow2" cache="none"/>
      "/var/lib/nova/instances/8352e969-0a25-4abf-978f-d9d0ec4de0cd/disk.swap"/>
      "virtio" dev="vdc"/>
    
    <interface type="bridge"> # 虚机通过网桥连接到 OVS "fa:16:3e:e0:30:e7"/>
      "virtio"/> #该 type 可以由 image metadata hw_vif_type 指定。未指定的话,如果配置了 conf.libvirt.use_virtio_for_bridges = true (默认就是 true)的话,QEMU/KVM 会使用 virtio 类型。 "qemu"/>
      "qbr59cfa0b8-2f"/> #qbr59cfa0b8-2f 连接虚机的 vNIC tap59cfa0b8-2f 和 qvb59cfa0b8-2f ,而 qvb59cfa0b8-2f 练到 OVS 的 br-int 上。 "tap59cfa0b8-2f"/>
    interface>
    "file"> 当 CONF.serial_console.enabled = true 时,type 为 "tcp",使用 config 配置,其 XML 为     ;当为 false 时,使用 console.log 文件,type 为 file。 "/var/lib/nova/instances/8352e969-0a25-4abf-978f-d9d0ec4de0cd/console.log"/>
    
    "pty"/> #每个domain都有 type 为 "pty" 的 serial 配置。 "tablet" bus="usb"/> #当 CONF.vnc_enabled = true 或者 CONF.spice.enabled = true 并且 CONF.spice.agent_enabled = false 时添加 tablet,type 和 bus 都是固定的。 "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 配置 "cirrus"/> #如果 CONF.spice.enabled,则 type 为 qxl;否则为 cirrus。 
    "virtio"> #如果 CONF.libvirt.mem_stats_period_seconds >0 则添加 memballoon;对 KVM,model 固定为 "virtio" "10"/>
    
  

从 bootable volume 启动的话,disk 部分为:

"file" device="disk">
      "qemu" type="qcow2" cache="none"/>
      "/var/lib/nova/instances/02699155-940f-4401-bc01-36220db80639/disk.local"/>
      "virtio" dev="vdb"/>
    
    "file" device="disk">
      "qemu" type="qcow2" cache="none"/>
      "/var/lib/nova/instances/02699155-940f-4401-bc01-36220db80639/disk.swap"/>
      "virtio" dev="vdc"/>
     
     
     
     
     26446902-5a56-4c79-b839-a8e13a66dc7a
    

(5). 启动 domain (调用 libvirt Python createWithFlags API)

2.2 添加 volume 到虚机 (nova volume-attach

(1)通过 domain name 来找到指定 domain 对象 (通过调用 lookupByName API

(2)调用 volume driver 来建立主机和 Volume 之间的连接

(3)生成 volume 连接的配置 xml,比如:

"block" device="disk">
  "qemu" type="raw" cache="none"/>
  "/dev/disk/by-path/ip-10.0.2.41:3260-iscsi-iqn.2010-10.org.openstack:volume-31367039-0da5-4dac-bf9a-40303b869126-lun-1"/>
  "virtio" dev="vdd"/>
  31367039-0da5-4dac-bf9a-40303b869126

(4)调用 attachDeviceFlags API 将 volume 挂载到该虚机

2.3 添加连接到新的网络的 interface 给虚机 (nova interface-attach

(1)将 Neutron 分配的 port 连接到 OVS

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

<interface type="bridge">
  "fa:16:3e:3b:ba:72"/>
  "virtio"/>
  "qemu"/>
  "qbr61fb4206-ae"/>
  "tap61fb4206-ae"/>
interface>

(3)调用 attachDeviceFlags API 来挂载该 interface 到虚机


又纠结了几天,终于到了可以写文章记录下来的时刻了。

简单的讲,nova最核心的功能就是对一大堆的虚拟机进行管理,虚拟机可以是各种各样(kvm, qemu, xen, vmware...),而且管理的方法也可以是各种各样(libvirt, xenapi, vmwareapi...),因为我的电脑不支持CPU的VT,而且以前在visualbox中装openstack,也只能使用qemu,所以这次测试的主要是qemu的使用,另外nova中默认使用的管理虚拟机的API是libvirt,所以这里的测试使用libvirt。

首先来简单说一下我对libvirt和qemu这两个的理解:

1. libvirt

libvirt是一套用c语言写的API,旨在为各种虚拟机提供一套通用的编程接口,而且支持与java,python等语言的绑定。基于libvirt的虚拟机管理工具也有很多:virt-manager(GUI工具),virsh(命令行工具)。其架构示意图如下:

(左图是没有使用libvirt的情况)

这里涉及到几个概念:

(1)Domain:虚拟机的一个运行实例,简单的理解,就是一个虚拟机虚拟出来的操作系统。它的叫法可是多种多样:instance,guest OS,virsual machine,其实都指的同一个概念。

(2)Hypervisor:指的就是虚拟机本身,比如qemu, kvm, xen...

libvirt 由几个不同的部分组成,其中包括应用程序编程接口 (API) 库、一个守护进程 (libvirtd),以及一个默认命令行实用工具 (virsh),libvirtd守护进程负责对虚拟机的管理工作,在用各种工具对虚拟机进行管理的时候,这个守护进程一定要跑起来,而且这个进程可以分为两种,一种是root权限的libvirtd,一种是普通用户权限的libvirtd,前者权限大,可以虚拟计算机的各种设备。

开启root权限的libvirtd守护进程要以root身份去运行:sudo libvirtd  --daemon


2. qemu

qemu是一个仿真器,即可用于来宾操作系统的虚拟化,也可以作为完整的机器仿真器使用,运行使用主机 CPU 或其他 CPU 架构的操作系统。

qemu 支持两种操作模式:用户模式仿真和系统模式仿真。用户模式仿真 允许一个 CPU 构建的进程在另一个 CPU 上执行(执行主机 CPU 指令的动态翻译并相应地转换 Linux 系统调用)。系统模式仿真 允许对整个系统进行仿真,包括处理器和配套的外围设备,这时就应该使用root权限的libvirtd。

qemu相关的命令:


[python] view plaincopy
  1. $ qemu-img create -f qcow disk.img 128M  
创建一个名为disk.img的128M大小的qcow格式的磁盘映像文件,这个文件充当来宾操作系统的硬盘。



[plain] view plaincopy
  1. $ qemu -hda disk.img -cdrom /root/cflinux-1.0.iso -boot d  
-hda指定磁盘映像文件,-cdrom指定光盘镜像文件,-boot指定从哪里引导系统,d是从CD-ROM引导,c表示从硬盘引导



[plain] view plaincopy
  1. $ qemu -hda disk.img  
开始启动来宾操作系统



接下来,使用visual manager工具来模仿一下openstack中Flat模式的网络,因为我在安装openstack的时候,最后一步总是无法ping或ssh上实例,所以这里通过对实例的直接操作来进行演示,其网络拓扑图如下:

(网络是我的一大浩劫,一遇到和网络相关的东西,立马就纠结了,网桥,路由,网关,网段,交换机,nat,dhcp等等,这些东西不实践一下,完全弄不明白他们是干什么的,还好,通过这一段时间的学习,基本上知道了怎么回事,开学之后,一定要补一下网络知识。)

从开始安装,到今晚之前,在这个拓扑图里,一直有一个不懂的东西,就是那个br100!原来它就是传说中的网桥,网卡可以桥接到这个网桥上,来连接两个局域网。网桥工作在物理链路层,相当于一个“低层”的路由器,通过mac帧来识别主机,所以桥接到这个网桥上的网卡是不需要配ip的,这解开了我“多年”的疑惑:为什么那个eth1不需要配ip啊?那两个局域网是怎么连到一块的?原来如此!

还有一个困惑就是多网卡的问题,一直不明白,为什么一台电脑要多个网卡,一个网卡不够用吗?原来真的不够用!一个网卡只能负责接入到一个网络,如果一个电脑要同时接入多个网络的话,那么就得用多个网卡了,也就是说一台电脑可以同时处于不同的局域网中。那这样的话,以前在我脑海中,一台电脑在网络中的身份是唯一的,这样的概念就不成立了啊,一台电脑也可以有多个身份,是由网卡决定的。


好了,吐槽完毕,下面是我模拟的简单的拓扑图:

我的目的就是让host能ping通任意一个虚拟机,虚拟机之间能够相互ping通,并且host能ssh上任意一个虚拟机。

1.  首先要做的就是建立br100网桥,在安装nova时,这个网桥是自动创建的,这里来手动创建,创建网桥使用到的工具是bridge-utils,即使用brctl相关的命令:

[plain] view plaincopy
  1. $ brctl addbr br100   #添加一个网桥  
  2. $ brctl addif br100 eth0   #把网卡桥接到网桥上  
  3. $ ifconfig eth0 0.0.0.0   
  4. $ ifconfig br100 10.0.0.1   #给网桥配ip  

eth0的ip可配可不配。这样创建的网桥不是永久的,系统重启的话,就会销毁了。


2.  建立虚拟机:

用visual manager建立3个虚拟机,我用的系统镜像是cflinux-1.0.iso,一个只有几兆的linux发行版,磁盘映像是用virtual manager创建的raw格式的image。

需要注意的是在第5步选择网络的时候,要选“specify shared device name”,然后在下面的输入框中输入刚刚创建好的网桥的名字:br100,如下图:


3.  改虚拟机的ip

不知道为什么visual manager创建的虚拟机初识状态的ip都是一样的,都是10.0.0.2,使用ifconfig命令把3个虚拟机的ip改为:

10.0.0.2       10.0.0.3        10.0.0.4

让他们在同一个网段。


这样,主机可以ping通实例,实例之间也可以相互ping通了,通过ssh root@10.0.0.2也能连上虚拟机了!


还未明白的问题:

每次虚拟机启动之后,用ifconfig在主机上查询网络信息,会看到vnet0, vnet1等这些信息,还有virbr0, virbr1等,后者我知道表示的是一个网段,但是前者是做什么用的呢?是虚拟机的虚拟出来的网卡吗?

阅读(4861) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~