江博士带你轻松搞定KVM虚拟化

在虚拟化中,必然存在宿主机与虚拟机通信的需要。一般来说,可以通过网桥的方式与虚拟机建立通信通道,通过网络传输数据,适用性比较强。但是,这种方式依赖于网络通畅,当虚拟机发生某些故障,网络已经发生问题,宿主机就需要另外一种方式与虚拟机建立通信通道了。经常使用VMWare的同学都知道Mware Tools,这个工具安装在虚拟机内部,可以实现宿主机与虚拟机的通信。

什么是QEMU Guest Agent

对于QEMU/KVM 来说,也有这么一款工具叫做QEMU Guest Agent。

QEMU Guest Agent(下简称:QGA)是一个运行在虚拟机内部的普通应用程序(可执行文件名称默认为qemu-ga,服务名称默认为qemu-guest-agent),是一种宿主机与虚拟机的交互方式。QGA依赖于virtio-serial或者isa-serial,不依赖于网络,在虚拟机内部是一个串口设备,在宿主机上是一个unix socket文件,在宿主机上使用普通的unix socket读写方式写入命令,虚拟机里读写串口设备与宿主机交互(qemu-ga监听改设备,有命令进来,就开始分析、执行)。QGA的交互协议是qmp(qemu monitor protocol)协议,其实就是使用json格式交换数据。串口设备的速率通常比较低,所以比较适合小数据量的交换。

QGA的使用方法

环境如下:

宿主机:

系统版本:CentOS Linux release 7.1.1503

virsh版本:libvirt 1.2.17、QEMU 2.6.0

虚拟机:

系统版本:CentOS Linux release 7.1.1503

QGA版本(QEMU版本):2.7.1 release

准备虚拟机:

具体请参考前期文章:

《江博士带你轻松搞定KVM虚拟化》http://mp.weixin.qq.com/s/auW_c4Z_-mgoiZl7EmhAZg

使用virsh命令创建虚拟机。简单步骤如下:

创建虚拟机配置文件centos.xml,并在<devices>下添加QGA配置项:

<devices>
    …
<channel type='unix'>
        <source mode='bind' path='/var/centos7-1.0'/>
        <target type='virtio' name='org.qemu.guest_agent.0'/>
        <address type='virtio-serial' controller='0' bus='0' port='1'/>
</channel>
…
</devices>

其中,source -> path可以自己指定路径及名称,这个就是宿主机上的unix socket文件;target -> name 要与虚拟机内QGA设备相同,默认是org.qemu.guest_agent.0

创建虚拟机

virsh create centos.xml

在source -> path 目录下可以看到对应的socket文件。

在虚拟机内安装QGA

使用yum安装QGA

如果只使用QGA默认功能,不进行扩展的话,可以直接使用yum安装:

yum install qemu-guest-agent

由于本机yum源没有最新版的QGA,安装的是2.5.0版本,如果需要最新版或者需要扩展功能请参考本文2.2.2 编译安装内容。

使用源码编译安装QGA

下载QGA源文件

如果需要扩展QGA,需要下载源码,修改后编译安装:

下载QGA源码并解压到/home/qemu-2.7.1 (不要纠结这个路径…)

git clone git://git.qemu-project.org/qemu.git   git克隆代码。
或
http://wiki.qemu-project.org/download/qemu-2.7.1.tar.bz2 下载tar.bz2源码包。

说明:

QGAQEMU的一个模块,官方没有单独的QGA源码,下载QEMU源码,可以单独编译QGA模块。如果只是用QGA的话,可自行精简源码。

编译安装:

# 进入qemu目录
cd /home/qemu-2.7.1
# 在configure阶段可能出现缺少依赖项问题,根据提示安装对应的依赖项即可。
./configure

# 只编译 安装 qemu-ga
make qemu-ga
make install qemu-ga

运行及使用QGA

宿主机使用socat建立连接:

socat  /var/centos7-1.0  readline

通过qemu-ga命令打开虚拟机上的串口设备:

qemu-ga -m virtio-serial -p /dev/virtio-ports/org.qemu.guest_agent.0


说明:

前文说过QGA在虚拟机里是一个设备,宿主机发送的命令会自动写入到该设备中缓存,linux中设备也是个文件,所以这个org.qemu.guest_agent.0也可以用vim打开,查看宿主机命令是否写入。另外,虚拟机里的QGA设备的文件名org.qemu.guest_agent.0是在配置文件xmldevices -> target -> name定义的。具体的qga路径信息可以使用命令qemu-ga –D 查看。

在宿主机上发送命令给虚拟机执行:

使用json格式给虚拟机发送命令。

下图是发送了两个QGA默认提供的两条命令,及返回内容的截图。

扩展QGA功能

本文第2章介绍了如何安装使用QGA,实际上,QGA默认提供的功能(命令)并不能满足我们,这时我们就需要根据需求修改QGA源码,添加相应的功能,然后重新编译运行。

QGA功能扩展比较方便,共需要操作三个文件:

/qemu-2.7.1/qga/qapi-schema.json
/qemu-2.7.1/qga/ qapi-generated/qga-qmp-commands.h
/qemu-2.7.1/qga/ commands-posix.c

qapi-schema.json文件中,定义功能(命令)名称、输入输出数据类型即可,格式参考自带功能(命令);在qga-qmp-commands.h文件中,添加对应的函数声明;在commands-posix.c文件中,添加对应的功能函数即可。

下面的示例添加一个功能(命令),宿主机使用QGA方式将字符串写入虚拟机中的文件中。具体步骤,咱们一步一步的来!

首先,在qapi-schema.json文件中,定义功能(命令)名称、输入输出数据类型即可,格式参考自带功能(命令):

如下图所示:

参考自带的命令格式,添加我们自定义的功能(命令)。

先定义返回值类型。

本文使用QGA版本已经不允许使用內建数据类型作为返回值类型了,所以我们先定义一个返回值的数据结构。

{ 'struct': 'TestRE',
'data': { 'code': 'int'} }

结构的名字是:TestRE
内容的key是code,值是int型。

再定义功能(命令)的输入输出。

{ 'command': 'guest-test',
'data':    {'content':'str'},
'returns': 'TestRE'}

命令的名字是:guest-test
输入数据的key是content,值是一个字符串。
输出数据是一个TestRE的结构,刚刚我们自己定义的。

然后,在qga-qmp-commands.h文件中,添加对应的函数声明,并在commands-posix.c文件中,添加对应的功能函数。

先在qga-qmp-commands.h添加函数声明。如下图:

TestRE *qmp_guest_test(const char *content, Error **errp);

为什么是这个名字,看下文!

在commands-posix.c添加函数体。如下图:

在文件尾添加:

TestRE *qmp_guest_test(const char *content, Error **errp)
{
    FILE *fd;
    int ret = 0;
    fd = fopen("/var/test.txt", "a+");
    printf("%s",content);
    if (fd){
        ret = fprintf(fd, "%s\n", content );
    }
    fclose(fd);
    TestRE *ge = NULL;
    // get 100 byte malloc
    ge = g_new0(TestRE, 100);
    ge->code = ret;
    return ge;
}

说明:

定义指针函数,函数名与qapi-schema.json定义的功能(命令)名对应。以qmp_ 开头,把横线改为下划线_,返回我们定义的返回类型即可。函数实现了一个简单的功能,把输入的字符串存到/var/test.txt中,返回存入文件的字符数。

好了,修改完毕!

保存后,重新编译:

make qemu-ga
make install qemu-ga

运行(参考2.3):

宿主机使用socat建立连接:

socat  /var/centos7-1.0  readline

通过qemu-ga命令打开虚拟机上的串口设备:

qemu-ga -m virtio-serial -p /dev/virtio-ports/org.qemu.guest_agent.0

结果如图:

在宿主机上发动了三条写字符串到虚拟机文件的命令,可以看到,虚拟机执行命令正确(写入了文件),返回值正确(返回写入文件的字符数)。

扩展成功!

qga通道

如图所示:

在宿主机中,将命令写入unix socket文件。

在虚拟机中,可以在QGA设备文件中读取到。

这就组成了宿主机到虚拟机间的QGA通道。

结语

本文简单介绍了QEMU Guest Agent的使用及扩展方法。通过在虚拟机内部预装qemu-ga,云平台对虚拟机的控制能力显著加强。但是,串口方式,速率较低,仅能进行小数据量的交换。各位看官,自取所需。在qga-qmp-commands.h文件中

如果您需要了解更多内容,可以
加入QQ群:570982169
直接询问:010-68438880

Spread the word. Share this post!

Meet The Author

Leave Comment