利用Qemu Guest Agent (Qemu-ga) 实现 Openstack 监控平台
经常使用vmWare的同学都知道有vmware-tools这个工具,这个安装在vm内部的工具,可以实现宿主机与虚拟机的通讯,大大增强了虚拟机的性能与功能,
如vmware现在的Unity mode下可以让应用程序无缝地与宿主机交互,更不用提直接复制粘帖文件及内容的小功能了。
对于KVM而言,其实也有一款这样的工具叫做 Qemu Guest Agent(以下称qga).
原理分析:
qga是一个运行在虚拟机内部的普通应用程序(可执行文件名称默认为qemu-ga,服务名称默认为qemu-guest-agent),其目的是实现一种宿主机和虚拟机进行交互的方式,这种方式不依赖于网络,而是依赖于virtio-serial(默认首选方式)或者isa-serial,而QEMU则提供了串口设备的模拟及数据交换的通道,最终呈现出来的是一个串口设备(虚拟机内部)和一个unix socket文件(宿主机上)。
qga通过读写串口设备与宿主机上的socket通道进行交互,宿主机上可以使用普通的unix socket读写方式对socket文件进行读写,最终实现与qga的交互,交互的协议与qmp(QEMU Monitor Protocol)相同(简单来说就是使用JSON格式进行数据交换),串口设备的速率通常都较低,所以比较适合小数据量的交换。
QEMU virtio串口设备模拟参数:
/usr/bin/kvm(QEMU) \
……\
-device virtio-serial-pci,id=virtio-serial0,bus=pci.,addr=0x6 \
-device isa-serial,chardev=charserial1,id=serial1 \
-chardev socket,id=charchannel0,path=/var/lib/libvirt/qemu/test.agent,server,nowait \
-device virtserialport,bus=virtio-serial0.,nr=,chardev=charchannel0,id=channel0,\
name=com..spice.
通过上面的参数就可以在宿主机上生成一个unix socket文件,路径为:/var/lib/libvirt/qemu/test.agent,同时在虚拟机内部生成一个serial设备,名字为com.163.spice.0,设备路径为:/dev/vport0p1,映射出来的可读性比较好的路径为:/dev/virtio-ports/com.163.spice.0,可以在运行qga的时候通过-p参数指定读写这个设备。
也可以通的XML文件来配置这个串口设备:
<channel type='unix'>
<source mode='bind' path='/var/lib/libvirt/qemu/test.agent'/>
<target type='virtio' name='com.163.spice.0'/>
</channel>
注意: libvirt-qemu:kvm用户要有权限读写'/var/lib/libvirt/qemu/test.agent'
已有功能
目前qga最新版本为1.5.50,linux已经实现下面的所有功能,windows仅支持加*的那些功能:
Ø guest-sync-delimited*:宿主机发送一个int数字给qga,qga返回这个数字,并且在后续返回字符串响应中加入ascii码为0xff的字符,其作用是检查宿主机与qga通信的同步状态,主要用在宿主机上多客户端与qga通信的情况下客户端间切换过程的状态同步检查,比如有两个客户端A、B,qga发送给A的响应,由于A已经退出,目前B连接到qga的socket,所以这个响应可能被B收到,如果B连接到socket之后,立即发送该请求给qga,响应中加入了这个同步码就能区分是A的响应还是B的响应;在qga返回宿主机客户端发送的int数字之前,qga返回的所有响应都要忽略; Ø guest-sync*:与上面相同,只是不在响应中加入0xff字符; Ø guest-ping*:Ping the guest agent, a non-error return implies success; Ø guest-get-time*:获取虚拟机时间(返回值为相对于1970-01-01 in UTC,Time in nanoseconds.); Ø guest-set-time*:设置虚拟机时间(输入为相对于1970-01-01 in UTC,Time in nanoseconds.); Ø guest-info*:返回qga支持的所有命令; Ø guest-shutdown*:关闭虚拟机(支持halt、powerdown、reboot,默认动作为powerdown); Ø guest-file-open:打开虚拟机内的某个文件(返回文件句柄); Ø guest-file-close:关闭打开的虚拟机内的文件; Ø guest-file-read:根据文件句柄读取虚拟机内的文件内容(返回base64格式的文件内容); Ø guest-file-write:根据文件句柄写入文件内容到虚拟机内的文件; Ø guest-file-seek:Seek to a position in the file, as with fseek(), and return the current file position afterward. Also encapsulates ftell()'s functionality, just Set offset=0, whence=SEEK_CUR; Ø guest-file-flush:Write file changes bufferred in userspace to disk/kernel buffers; Ø guest-fsfreeze-status:Get guest fsfreeze state. error state indicates; Ø guest-fsfreeze-freeze:Sync and freeze all freezable, local guest filesystems; Ø guest-fsfreeze-thaw:Unfreeze all frozen guest filesystems; Ø guest-fstrim:Discard (or "trim") blocks which are not in use by the filesystem; Ø guest-suspend-disk*:Suspend guest to disk; Ø guest-suspend-ram*:Suspend guest to ram; Ø guest-suspend-hybrid:Save guest state to disk and suspend to ram(This command requires the pm-utils package to be installed in the guest.); Ø guest-network-get-interfaces:Get list of guest IP addresses, MAC addresses and netmasks; Ø guest-get-vcpus:Retrieve the list of the guest's logical processors; guest-set-vcpus:Attempt to reconfigure (currently: enable/disable) logical processors inside the guest。
功能扩展方式
qga功能扩展十分方便,只需要在qapi-schema.json文件中定义好功能名称、输入输出数据类型,然后在commands-posix.c里面增加对应的功能函数即可,下面的补丁即在qga中增加一个通过statvfs获取虚拟机磁盘空间信息的功能:
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index e199738..2f42a2f
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -, +, @@
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
+#include <sys/statvfs.h>
#include <inttypes.h>
#include "qga/guest-agent-core.h"
#include "qga-qmp-commands.h"
@@ -, +, @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
}
#endif +GuestFileSystemStatistics *qmp_guest_get_statvfs(const char *path, Error **errp)
+{
+ int ret;
+ GuestFileSystemStatistics *fs_stat;
+ struct statvfs *buf;
+ buf = g_malloc0(sizeof(struct statvfs));
+
+
+ ret = statvfs(path, buf);
+ if (ret < ) {
+ error_setg_errno(errp, errno, "Failed to get statvfs");
+ return NULL;
+ }
+
+ fs_stat = g_malloc0(sizeof(GuestFileSystemStatistics));
+ fs_stat->f_bsize = buf->f_bsize;
+ fs_stat->f_frsize = buf->f_frsize;
+ fs_stat->f_blocks = buf->f_blocks;
+ fs_stat->f_bfree = buf->f_bfree;
+ fs_stat->f_bavail = buf->f_bavail;
+ fs_stat->f_files = buf->f_files;
+ fs_stat->f_ffree = buf->f_ffree;
+ fs_stat->f_favail = buf->f_favail;
+ fs_stat->f_fsid = buf->f_fsid;
+ fs_stat->f_flag = buf->f_flag;
+ fs_stat->f_namemax = buf->f_namemax;
+
+ return fs_stat;
+}
+
/* register init/cleanup routines for stateful command groups */
void ga_command_state_init(GAState *s, GACommandState *cs)
{
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 7155b7a..a071c3f
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -, +, @@
{ 'command': 'guest-set-vcpus',
'data': {'vcpus': ['GuestLogicalProcessor'] },
'returns': 'int' }
+
+##
+# @GuestFileSystemStatistics:
+#
+# Information about guest file system statistics.
+#
+# @f_bsize: file system block size.
+#
+# @f_frsize: fragment size.
+#
+# @f_blocks: size of fs in f_frsize units.
+#
+# @f_bfree: free blocks.
+#
+# @f_bavail: free blocks for non-root.
+#
+# @f_files: inodes.
+#
+# @f_ffree: free inodes.
+#
+# @f_favail: free inodes for non-root.
+#
+# @f_fsid: file system id.
+#
+# @f_flag: mount flags
+#
+# @f_namemax: maximum filename length.
+#
+# Since 1.5.(NetEase)
+##
+{ 'type': 'GuestFileSystemStatistics',
+ 'data': { 'f_bsize': 'int', 'f_frsize': 'int', 'f_blocks': 'int',
+ 'f_bfree': 'int', 'f_bavail': 'int', 'f_files': 'int',
+ 'f_ffree': 'int', 'f_favail': 'int', 'f_fsid': 'int',
+ 'f_flag': 'int', 'f_namemax': 'int'} }
+
+##
+# @guest-get-statvfs:
+#
+# Get the information about guest file system statistics by statvfs.
+#
+# Returns: @GuestFileSystemStatistics.
+#
+# Since 1.5.(NetEase)
+##
+{ 'command': 'guest-get-statvfs',
+ 'data': { 'path': 'str' },
+ 'returns': 'GuestFileSystemStatistics' }
+
中间复杂的类型定义代码,以及头文件包含关系处理都由一个python脚本在编译的时候动态生成出来,这对开发人员来说是非常方便的,开发人员在扩展功能的时候只需要关注输入、输出的数据类型,以及功能的函数内容即可。
写到这里,有经验的开发人员已经知道如何用qga开发监控平台,下面是网友的实现思路,供参考:
社区活跃度
QEMU社区从2011年7月20号开始在QEMU代码仓库中增加qga功能,最近一次提交在2013年5月18号,总共有100多次提交记录,代码维护人员主要来自redhat和IBM,社区的活跃度不高,但是QEMU本身的提交记录从2003年至今已有27200多条,还是比较活跃的,qga的功能及代码都比较简单,也是活跃度不高的一个重要原因。
QEMU代码仓库地址:git clone git://git.qemu-project.org/qemu.git
qga代码位于QEMU代码的根目录下的qga目录中。
监控方案现状
目前普遍云主机监控的实现方法是,在创建云主机的过程中,增加监控脚本及其配置文件、定时任务及监控信息推送配置文件的注入过程,包括四个文件,其中监控信息推送配置文件(/etc/vm_monitor/info)由管理平台根据云主机所属用户的注册信息以及监控平台相关配置生成,并传入创建云主机的API来实现文件的注入,监控脚本(/etc/vm_monitor/send_monitor_data.py)及其配置文件(/etc/vm_monitor/monitor_settings.xml)、定时任务文件(/etc/cron.d/inject_cron_job)是包含在NVS经过base64编码后的监控脚本文件inject_files.json中。
工作模式为,在root账户增加定时任务inject_cron_job,其中有一条任务为:root su -c 'python /etc/vm_monitor/send_monitor_data.py' > /dev/null 2>&1,也即每60s收集并推送一次监控信息给监控平台。
当前监控方案的问题
- 依赖云主机内部的python解释器
- 云主机必须存在root账户
- 依赖NVS文件注入功能;并且为了注入这些监控文件对nova的改动也比较大,也无法与社区同步;windows镜像也会注入这些无用的文件,可能导致一些意想不到的问题;另外如果有的镜像的操作系统不在第一个分区上,则注入的监控文件会失效
- 已经运行的云主机内部的监控相关文件更新困难,导致新监控项的添加、推送周期、推送地址等的修改也比较困难,灵活性较差
- Nova中base64编码的注入脚本的代码可读性很差,代码更新及维护困难
- 定位问题一般都需要登录到云主机内部进行,对于采用密钥对登录的云主机来说定位问题比较困难
采用qga方式的监控方案
首先为每个云主机增加virtio-serial的配置,这个只需要修改生成libvirt配置文件的代码即可,并且应该可以提交给社区;其次需要在虚拟机内部安装qga服务;最后需要在宿主机上新增一个服务进程(这里暂定为monitor服务),用来通过与qga交互从云主机内部获取监控信息;总的模块交互流程如下:
云主机创建流程中的监控相关操作:

monitor服务单次监控信息获取及推送流程如下:

参考资料:
libvirt:http://wiki.libvirt.org/page/Qemu_guest_agent
RedHat ovirt: http://www.ovirt.org/Category:Ovirt_guest_agent
qemu: http://wiki.qemu.org/Features/QAPI/GuestAgent
利用Qemu Guest Agent (Qemu-ga) 实现 Openstack 监控平台的更多相关文章
- QEMU Guest Agent
QEMU Guest Agent It is a daemon program running inside the domain which is supposed to help manageme ...
- 干货|带你体验一次原生OpenStack云平台发放云主机的过程
一个执着于技术的公众号 1 前言 上一章节我们完成了OpenStack云平台的搭建工作,今天就带大家一起学习下如何发放一台云主机 点击查看:如何搭建一套OpenStack云平台 2 发放OpenSta ...
- 干货 | 手把手教你搭建一套OpenStack云平台
1 前言 今天我们为一位朋友搭建一套OpenStack云平台. 我们使用Kolla部署stein版本的OpenStack云平台. kolla是用于自动化部署OpenStack的一个项目,它基于dock ...
- OpenStack云平台网络模式及其工作机制
转自:http://openstack.csdn.net/content.html?arcid=2808381 OpenStack云平台网络模式及其工作机制 网络,是OpenStack的部署中最容易出 ...
- zabbix server+agent+proxy搭建性能监控平台
这是新找到了配置文件配置方法但未尝试 每个模块工作职责: Zabbix Server:负责接收agent发送的报告信息的核心组件,所有配置,统计数据及操作数据均由其组织进行: Database Sto ...
- [daily][qemu][kvm] 使用qemu/kvm模拟numa节点
qemu的配置参数又复杂又难用,man手册写的也是非常对付,很多信息都没有. 而且,竟然遗弃掉旧的配置,换用新的配置.不过这也是好事,说明它在发展,我是欢迎的. 唯一的问题是,要经常跟着它一起更新配置 ...
- qemu 如何退出qemu
如何退出qemu ctrl + a 放开后,再按下x 这里字母是小写!(不要按着大写键)
- SQL Server下实现利用SQL Server Agent Job对索引重建实现Balance Load
昨天工作中遇到这样一个场景,有个项目需要把某台服务器下所有的表和索引都启用数据压缩(data_compression=page),已经启用了的表和索引就不需要再压缩一次了.统计一下后发现要运行的REB ...
- centos6.5制作OpenStack云平台Windows7镜像
# yum install virt-manager libvirt qemu-img virt-viewer -y # vi /etc/libvirt/qemu.conf # service lib ...
随机推荐
- 位图文件格式及linux下C语言来操作位图文件
说到图片,位图(Bitmap)当然是最简单的,它是Windows显示图片的基本格式,其文件扩展名为*.BMP.由于没有经过任何的压缩,故BMP图片往往很大.在Windows下,任何格式的图片文件都要转 ...
- 分享8款最新HTML5/CSS3功能插件及源码下载
1.HTML5/CSS3鬼脸表情下拉菜单 超级可爱 这款HTML5/CSS3鬼脸表情下拉菜单真的很特别,虽然菜单的实现并没有利用复杂的HTML5/CSS3技术,但是创意的确不错. 在线演示 源码下载 ...
- POJ 2499 Binary Tree
题意:二叉树的根节点为(1,1),对每个结点(a,b)其左结点为 (a + b, b) ,其右结点为 (a, a + b),已知某结点坐标,求根节点到该节点向左和向右走的次数. 分析:往回一步一步走肯 ...
- 数据结构与算法课程作业--1014. Translation
这道题思想很简单,就是用map将foreign的作为键值,english的值作为对应的映射值,然后通过直接用foreign作为map对象的下标直接查找. 本题比较烦人的一点就是输入数据,我使用了get ...
- SPA解释:单页应用程序
单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序. 单页W ...
- Cassandra1.2文档学习解读计划——为自己鼓劲
最近想深入研究一下Cassandra,而Cassandra没有中文文档,仅有的一些参考书都是0.7/0.6版本的.因此有个计划,一边学习文档(地址:http://www.datastax.com/do ...
- JS 获取select(多选下拉)中所选值的示例代码
通过js获取select(多选下拉)中所选值,具体实现如下,有需要的朋友可以参考下,希望对大家有所帮助 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML ...
- fis3简单教程
#进入工作目录初始化fis3目录(此步非必须,如果当前目录已有fis-conf.js文件,可以不用初始化)fis3 init#部署(<path>为部署目录,如果想部署到当前output目录 ...
- Optimize str2date function
The job can be any string date format convert to AX date format. so that, Do not need to specify str ...
- ORACLE AWR 和 ASH
一.关于ASH 我们都知道,用户在 ORACLE 数据库中执行操作时,必然要创建相应的连接和会话, 其中,所有当前的会话信息都保存在动态性能视图 V$SESSION 中,通过该视图,DBA 可 以查看 ...