<转> Libvirt学习总结

感谢朋友支持本博客。欢迎共同探讨交流。因为能力和时间有限,错误之处在所难免,欢迎指正!
假设转载,请保留作者信息。
博客地址:http://blog.csdn.net/gaoxingnengjisuan
邮箱地址:dong.liu@siat.ac.cn


    这是本人之前在实验室做的一个LIBVIRT学习报告。

1.什么是libvirt

    虚拟云实现的三部曲:虚拟化技术实现-->虚拟机管理-->集群资源管理(云管理)。各种不同的虚拟化技术都提供了主要的管理工具。

比方。启动。停用,配置,连接控制台等。这样在构建云管理的时候就存在两个问题:

    1) 假设採用混合虚拟技术,上层就须要对不同的虚拟化技术调用不同管理工具。非常是麻烦。

    2) 虚拟化技术发展非常迅速,系统虚拟化和容器虚拟化均在发展和演化中。可能有新的虚拟化技术更加符合如今的应用场景,须要迁移过去。这样管理平台就须要大幅修改。
    为了适应变化,我们惯用的手段是分层。使之相互透明。在虚拟机和云管理中设置一个抽象管理层。

libvirt就是扮演的这个角色。有了它,上面两个问题就迎刃而解。

libvirt提供各种API,供上层来管理不同的虚拟机。


    Libvirt是管理虚拟机和其它虚拟化功能,比方存储管理,网络管理的软件集合。它包含一个API库,一个守护程序(libvirtd)和一个命令行工具(virsh)。libvirt本身构建于一种抽象的概念之上。

它为受支持的虚拟机监控程序实现的经常使用功能提供通用的API。

    libvirt的主要目标是为各种虚拟化工具提供一套方便、可靠的编程接口。用一种单一的方式管理多种不同的虚拟化提供方式。

2.Libvirt主要支持的功能
    虚拟机管理:包含不同的领域生命周期操作。比方:启动、停止、暂停、保存、恢复和迁移。

支持多种设备类型的热插拔操作,包含:磁盘、网卡、内存和CPU。
    远程机器支持:
仅仅要机器上执行了libvirt daemon,包含远程机器,全部的libvirt功能就都能够訪问和使用。

支持多种网络远程传输。使用最简单的SSH,不须要额外配置工作。
    存储管理:
不论什么执行了libvirt daemon的主机都能够用来管理不同类型的存储:创建不同格式的文件镜像(qcow2、vmdk、raw等)、挂接NFS共享、列出现有的LVM卷组、创建新的LVM卷组和逻辑卷、对未处理过的磁盘设备分区、挂接iSCSI共享。等等等等。由于libvirt能够远程工作。全部这些都能够通过远程主机使用。
    网络接口管理:不论什么执行了libvirt daemon的主机都能够用来管理物理和逻辑的网络接口。
    虚拟NAT和基于路由的网络:
不论什么执行了libvirt daemon的主机都能够用来管理和创建虚拟网络。



3.Libvirt语言绑定
    libvirt库用C(支持 C++)实现。且包括对Python的直接支持。

只是它还支持大量语言绑定。眼下已经对Ruby、Java语言,Perl和 OCaml实施了绑定。libvirt支持最流行的系统编程语言(C和C++)、多种脚本语言。因此。无论您側重何种语言。都能够方便的应用Libvirt。

4.Libvirt支持的虚拟机
    眼下支持的虚拟化技术包含:

    能够说是很丰富,主流的虚拟化技术都包括了。

5.Libvirt
体系结构

    没有使用libvirt的虚拟机管理方式例如以下图所看到的:

    为支持各种虚拟机监控程序的可扩展性。libvirt实施一种基于驱动程序的架构,该架构同意一种通用的API以通用方式为大量潜在的虚拟机监控程序提供服务。下图展示了libvirt API与相关驱动程序的层次结构。这里也须要注意,libvirtd提供从远程应用程序訪问本地域的方式。

    libvirt的控制方式有两种:
    1)管理应用程序和域位于同一节点上。管理应用程序通过libvirt工作,以控制本地域。

    2)管理应用程序和域位于不同节点上。该模式使用一种执行于远程节点上、名为libvirtd的特殊守护进程。当在新节点上安装libvirt时该程序会自己主动启动,且可自己主动确定本地虚拟机监控程序并为其安装驱动程序。

该管理应用程序通过一种通用协议从本地libvirt连接到远程libvirtd。



6.Libvirt相关工具介绍
    接下来介绍一种名为virsh(虚拟 shell)的应用程序,基于命令行的管理工具。能够实现简单的资源管理。

它构建于libvirt之上,同意以交互方式使用多个libvirt功能。

    以下我们通过一个应用virsh来实现对域的管理的样例来了解virsh这个工具:
    1).定义域配置文件。该代码指定了定义域所需的全部选项—从虚拟机监控程序(仿真器)到域使用的资源以及外围配置。

这仅仅是个简单的配置。libvirt真正支持的属性更加多样化。


    2).完毕了域配置文件之后。使用virsh工具启动域。

启动新域时,使用create命令和域配置文件:

    ld@ld-Lenovo :~/libvtest$ virsh create react-qemu.xml
    Connecting to uri: qemu:///system
    Domain ReactOS-on-QEMU created from react-qemu.xml
    ld@ld-Lenovo :~/libvtest$
    3).使用virsh内的list命令列出给定主机上的活动域、域ID以及状态:
    ld@ld-Lenovo :~/libvtest$ virsh list
    Connecting to uri: qemu:///system
    Id Name                 State
    ----------------------------------
    1 ReactOS-on-QEMU      running
    ld@ld-Lenovo :~/libvtest$
    4).也能够使用suspend命令中止域。该命令可停止处于调度中的域,只是该域仍存在于内存中。可高速恢复执行。

    ld@ld-Lenovo :~/libvtest$ virsh suspend 1
    Connecting to uri: qemu:///system
    Domain 1 suspended
    ld@ld-Lenovo :~/libvtest$ virsh list
    Connecting to uri: qemu:///system
    Id Name                 State
    ----------------------------------
    1 ReactOS-on-QEMU      paused
    ld@ld-Lenovo :~/libvtest$ virsh resume 1
    Connecting to uri: qemu:///system
    Domain 1 resumed
    ld@ld-Lenovo :~/libvtest$

7.Libvirt和Pythonn
    Python是受libvirt支持的脚本语言,它向libvirt API提供全然面向对象的接口。

如今我们看一个使用Python来控制域的样例。

    在本例中,从导入libvirt模块開始。然后连接到本地虚拟机监控程序。

对每一个 ID 创建一个域对象,然后中止,继续。最后删除该域。

  1. import libvirt  
  2. conn = libvirt.open('qemu:///system')# 连接  
  3. for id in conn.listDomainsID():  
  4.     dom = conn.lookupByID(id)  
  5.     print "Dom %s State %s"%(dom.name(), dom.info()[0])  
  6.     dom.suspend()# 停止  
  7.     print "Dom %s State%s(after suspend)"%(dom.name(), dom.info()[0])  
  8.     dom.resume()# 继续  
  9.     print "Dom %s State%s(after resume)"%(dom.name(), dom.info()[0])  
  10.     dom.destroy()# 删除   
    输出结果:
    ld@ld-Lenovo :~/libvtest$ python libvtest.py
    Dom ReactOS-on-QEMU  State 1
    Dom ReactOS-on-QEMU  State 3 (after suspend)
    Dom ReactOS-on-QEMU  State 1 (after resume)
    ld@ld-Lenovo :~/libvtest$
    尽管这仅仅是个简单演示样例,我们仍然可以看到 libvirt 通过 Python 提供的强大功能。通过一个简单的脚本就行管理本地域。发行有关域的信息,然后控制域。

8.Libvirt API介绍
    高级libvirt API可划分为5个API部分:虚拟机监控程序连接API、域API、网络API、存储卷API、存储池API。

1).连接API
    在libvirt中,连接是系统中的每个动作和对象的基础。

每个实体,要与libvirt互相作用,应用virsh, virt-manager或者使用libvirt库。都须要首先获得一个到主机上libvirt守护进程的连接。

    链接是与特定的hypervisor相关联的,它可能与libvirtclient程序同一时候执行在本地的一个节点上,也可能通过网络连接到远程的机器上。通常情况下,链接由virConnectPtr对象代表。而且由一个URI来定义。

    一个libvirt代理程序要做的第一件事就是调用libvirt连接函数获得virConnectPtr句柄。在兴许的操作中。该句柄作为全部其它管理功能的基础。

(1).连接函数
    libvirt库为连接到一个资源提供了三种不同的函数,三个函数之间的差别在于它们提供的验证方式以及由此产生的授权的方法。
    virConnectPtr virConnectOpen(const char *name)
    以实现全然的读写訪问,不包括不论什么认证机制,而只提供一种连接。
    演示样例:conn = virConnectOpen("qemu:///system");
    virConnectPtr virConnectOpenReadOnly(const char *name)
    virConnectOpenReadOnly API会打开一个仅仅读訪问的连接。
    演示样例:conn = virConnectOpenReadOnly("qemu:///system");
    virConnectPtr virConnectOpenAuth(const char *name, virConnectAuthPtr auth, int flags)
    提供了一种基于认证机制的连接;
    演示样例:conn = virConnectOpenAuth("qemu+tcp://localhost/system", virConnectAuthPtrDefault, 0);
(2).关闭连接
    virConnectClose
    当不再须要连接的时候。必须调用virConnectClose来断开连接。
    演示样例:
    virConnectPtr conn;
    conn = virConnectOpen("qemu:///system");
    virConnectClose(conn);
(3).URI格式
    Libvirt使用统一的资源标识符(URI)来识别管理连接。

连接本地和远程的hypervisor都是libvirt使用URI来进行处理。

    本地URI:
    Libvirt的本地URI具备下述格式之中的一个:
    driver:///system
    driver:///session
    driver+unix:///system
    driver+unix:///session
    远程URI:
    远程URI具有通用的格式("[...]"表示可选部分):
    driver[+transport]://[username@][hostname][:port]/[path][?extraparameters]
    參数解释:
    driver:libvirt 所连接的driver的名字。

如xen, qemu,lxc, openvz和test。

    transport:传输数据方式。可用的方式包含tls, tcp, unix, ssh和ext。

    hostname:远程机器的主机名。
    port:非常少使用。
    远程訪问URI的样例:
    应用SSH传输数据通道连接一个主机名为node.example.com上的远程Xen hypervisor,SSH的username根文件夹为:xen+ssh://root@node.example.com/
(4).获取虚拟机功能信息的API
    virConnectGetCapabilities的调用可以用于获取虚拟主机的功能信息。

返回虚拟机监控程序和驱动程序的功能描写叙述。它包括一个指针。假设调用成功,将返回一个字符串,当中包括了描写叙述功能信息的XML文件。

    capabilities XML格式提供了有关主机虚拟化技术的信息。特别的,他描写叙述了虚拟主机的功能、虚拟化驱动程序以及所採用的虚拟技术所可以启动的client的类型等等。
    详细样例不再描写叙述。
(5).获取主机信息的API
    各种不同的API能够用来获得虚拟主机的信息,包含主机名、最大支持的CPU个数等。

    virConnectGetHostname的调用能够获得虚拟主机的主机名。
    virConnectGetMaxVcpus的调用能够获得每一个域的虚拟CPU最大个数。
    virNodeGetFreeMemory调用可以获得虚拟主机中空暇内存的总量。
    virNodeGetInfo的调用能够用来获得虚拟主机的各种信息。

它採用了一个连接指针和一个virNodeInfo指针(由调用者分配)作为输入,假设成功。则会返回0。而且将获取信息填写在virNodeInfo结构体中。

    virNodeInfo结构体包含下面成员:
    char model[32]                表示CPU型号的字符串
    unsigned long memory          以kb为单位的内存大小
    unsigned int cpus              活跃的CPU数目
    unsigned int mhz               期望的CPU频率
    unsigned int nodes             NUMA节点数目。1表示一致性内存訪问
    unsigned int sockets           每个节点的CPU socket的数目
    unsigned int cores             每个socket的核数
    unsigned int threads           每个核的线程数
    virConnectGetType的调用可以获得处于连接使用中的虚拟机的类型。
    virConnectGetVersion能够获取使用中的主机上虚拟机软件的版本号。
    virConnectGetLibVersion能够获得正在使用中的主机上的libvirt软件的版本号。
    virConnectGetURI可以用来获取当前连接中的URI。
    virConnectIsEncrypted的调用可以查询一个给定的连接是否加密。
    virConnectIsSecure的调用可以查询一个给定的连接是否安全。
(6).错误处理API
    libvirt error API将会在一个正常的libvirt API调用返回错误标志的时候。

提供关于引发错误的很具体的信息。假设多个发生错误在没有错误监測机制的连接上的时候。错误信息有可能会丢失。由于这个原因。强烈建议常常对错误进行监測,并在libvirt API调用失败以后,马上进行错误收集。


2).域API
    域API用于虚拟机管理,包含创建,启动,停用,迁移。动态改动配置等。

    进入虚拟机监控程序后,便能够使用一组 API 调用函数反复使用该虚拟机监控程序上的各种资源。API实现大量针对域的函数。要探究或管理域,首先须要一个virDomainPtr对象。您可通过多种方式获得该句柄(使用ID、UUID或域名)。有了该域句柄,就能够运行非常多操作。从探究域(virDomainGetUUID、virDomainGetInfo、virDomainGetXMLDesc)到控制域(virDomainCreate 、virDomainSuspend 、virDomainResume 、virDomainDestroy)。
    域能够指不论什么正在执行的虚拟机或者是能够用来启动虚拟机的配置。链接对象提供了API用来枚举域、创建新域和管理现有域。域用virDomainPtr对象来表示,并有自己唯一的标示符。
    域能够是暂时的也能够是持久的。

一个暂时的域仅仅由当它在主机上执行的时候才干够被管理,一旦关闭。全部执行的迹象都会消失。

当一个持续的域被关闭时,仍然可能会管理这个域的无效的配置。当执行定义好的配置文件时。一个暂时的域能够转变成一个持续的域。

(1).域的标识符
    唯一标识符:
    ID:正整数类型。一个单节点上的若干域中,每一个域都有唯一的ID。无效的域没有ID号。
    name:字符串类型,在一个主机上的全部域中是唯一的,包含执行的域和无效的域。

    UUID:16比特无符号类型。保证在不论什么主机上的全部域之间是唯一的。

(2).域的获取
    有三个获取现有的域的API,即virDomainLookupByID, virDomainLookupByName 和virDomainLookupByUUID.这些对象中都用一个连接对象作为第一个输入參数,以及域标示符作为其他的输入參数。


演示样例:

    从ID获取一个域对象
    int domainID = 6;
    virDomainPtr dom;
    dom = virDomainLookupByID(conn, domainID);
    从name获取一个域对象
    int domainName = "someguest";
    virDomainPtr dom;
    dom = virDomainLookupByName(conn, domainName);
    从UUID获取一个域对象
    char *domainUUID = "00311636-7767-71d2-e94a-26e7b8bad250";
    virDomainPtr dom;
    dom = virDomainLookupByUUIDString(conn, domainUUID);
(3).域表单的获取
    Libvirt API公开了两个域的列表,第一个包括执行域。第二个包括无效的持久的域。
    活跃的域列表的API--virConnectListDomains,返回域ID的列表。

为了确定ID数组的大小,应用程序能够调用virConnectNumOfDomains API来解决。把这两个API调用放在一起,打印执行域ID列表的代码将会是例如以下所看到的:

  1. int i;  
  2. int numDomains;  
  3. int *activeDomains;  
  4. numDomains = virConnectNumOfDomains(conn);  
  5. activeDomains = malloc(sizeof(int) * numDomains);  
  6. numDomains = virConnectListDomains(conn, activeDomains, numDomains);  
  7. printf("Active domain IDs:\n");  
  8. for (i = 0 ; i < numDomains ; i++) {  
  9.     printf(" %d\n", activeDomains[i]);  
  10. }  
  11. free(activeDomains);  
    除了正在执行的域。可能还会有一些持久的无效域配置存储在主机上。假设一个无效的域不具备不论什么的ID标志,这个不活跃域的列表将会以name字符串列表的形式输出。

    virConnectListDefinedDomains将会返回所填充的name字符串到数组元素的总数量。也有一个virConnectNumOfDefinedDomains来确定name的数量。

打印无效的持久域的name列表的代码将会是例如以下所看到的:

  1. int i;  
  2. int numDomains;  
  3. char **inactiveDomains;  
  4. numDomains = virConnectNumOfDefinedDomains(conn);  
  5. inactiveDomains = malloc(sizeof(char *) * numDomains);  
  6. numDomains = virConnectListDomains(conn, inactiveDomains, numDomains);  
  7. printf("Inactive domain names:\n");  
  8. for (i = 0 ; i < numDomains ; i++) {  
  9.     printf(" %s\n", inactiveDomains[i]);  
  10.     free(inactiveDomains[i]);  
  11. }  
  12. free(inactiveDomains);  
(4).域生命周期的控制
    Libvirt可以控制域的整个生命周期。域可以在它的整个生命周期的几个状态之间进行转换:
    Undefined这是一个主要的状态。

不论什么未定义或者没有建立的域的状态。

    Defined这是一个域已定义可是没有执行的状态。这样的状态也能够被描写叙述为停止。
    Running这是一个已经定义并执行在一个hypervisor上面的域的状态。
    Paused这个状态是形容一个域系统从执行状态转换为暂停状态。它的内存镜像已经被临时地存储。它能够恢复到执行状态。


    三个重要的API:
    virDomainCreateXML将会建立并马上引导启动一个新的暂时性的域。

当这个域系统关闭的时候。全部的执行痕迹将会消失。

    virDomainDefineXML将会为一个持久性的域建立并存储配置文件。

    virDomainCreate将会从持久性配置中引导启动一个预先定义的域。
    引导一个暂时的域
    假设想引导一个暂时的域。仅仅须要建立一个对libvirt的连接以及一个包括了描写叙述了所需求的域的配置的XML文档的字符串。
  1. virDomainPtr dom;  
  2. const char *xmlconfig = "<domain>........</domain>";  
  3. dom = virConnectCreateXML(conn, xmlconfig, 0);  
  4. if (!dom)   
  5. {      
  6.     fprintf(stderr, "Domain creation failed");      
  7.     return;  
  8. }  
  9. fprintf(stderr, "Guest %s has booted",virDomainName(dom));  
  10. virDomainFree(dom);   
    假设创建域的尝试成功,那么将会返回virDomainPtr作为这个域的句柄。虽然域引导启动成功。可是这不能保证这个域的持续执行。


    定义并引导一个持久的域
    在一个持久域可以被引导之前,必须使它的配置文件已经定义完毕。这也要求建立一个对libvirt的连接以及一个包括了描写叙述了所需求的来宾域的配置文件的XML文档的字符串。以下的演示样例假定了conn是virConnectPtr对象的实例。


  1. virDomainPtr dom;  
  2. const char *xmlconfig = "<domain>........</domain>";  
  3. dom = virConnectDefineXML(conn, xmlconfig, 0);  
  4. if(virDomainCreate(dom) < 0){      
  5.     virDomainFree(dom);      
  6.     fprintf(stderr, "Cannot boot guest");      
  7.     return;  
  8. }  
  9. fprintf(stderr,"Guest %s has booted",virDomainName(dom));  
  10. virDomainFree(dom);  

    至于网络 API(监控虚拟网络)、存储卷 API(管理存储设备)和存储池 API(管理存储文件系统)这里先不做介绍了。假设有须要的话,能够直接看官方文档,介绍的非常具体,还有非常多简单明了的演示样例。
posted @ 2017-05-16 09:01  zsychanpin  阅读(4364)  评论(0编辑  收藏  举报