基于QMP实现对qemu虚拟机进行交互

基于QMP实现对qemu虚拟机进行交互

本文详解QMP,包含qmp、hmp、qemu-guest-agent的介绍、工做原理、配置方法、范例html

小慢哥的原创文章,欢迎转载node


目录

▪ QMP介绍
▪ QMP语法
▪ 单独使用qemu,启用QMP
▪ 经过libvirt启动qemu,启用QMP
▪ qemu-guest-agent(qemu-ga)
▪ 官方参考文档linux

QMP介绍

qemu对外提供了一个socket接口,称为qemu monitor,经过该接口,能够对虚拟机实例的整个生命周期进行管理,主要有以下功能json

▷ 状态查看、变动
▷ 设备查看、变动
▷ 性能查看、限制
▷ 在线迁移
▷ 数据备份
▷ 访问内部操做系统windows

经过该socket接口传递交互的协议是qmp,全称是qemu monitor protocol,这是基于json格式的协议centos

在继续往下讲以前,须要先了解qemu、kvm、libvirt之间的区别(由于有不少童鞋对这三者的理解是混乱的)api

▷ qemu:虚拟机仿真器。经过软件模拟出cpu、内存、磁盘、主板、网卡等设备
▷ kvm:高性能的cpu仿真器。因为软件模拟的cpu性能不好,所以出现了kvm,这是经过硬件与内核的支持实现接近native性能的cpu仿真器,能够理解为虚拟机里的cpu任务直接交给物理机cpu完成。
▷ libvirt:虚拟机管理平台。能纳管qemu、lxc、esx等虚拟化软件,经过编写xml实现对虚拟机、存储、网络等进行配置和管理网络

上面只描述最核心的功能,另有一些高级功能,以及互相重叠的功能在这里不作描述,不然容易混淆dom

QMP语法

# 不带参数的指令
{ "execute" : "XXX" }

# 带参数的指令
{ "execute" : "XXX", "arguments" : { ... } }

单独使用qemu,启用QMP

启动qemu虚拟机异步

# qemu monitor采用tcp方式,监听在127.0.0.1上,端口为4444
/usr/libexec/qemu-kvm -qmp tcp:127.0.0.1:4444,server,nowait

# qemu monitor采用unix socket,socket文件生成于/opt/qmp.socket
/usr/libexec/qemu-kvm -qmp unix:/opt/qmp.socket,server,nowait

链接qemu monitor

# tcp能够经过telnet进行链接,方法以下
> telnet 127.0.0.1 4444
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
{"QMP": {"version": {"qemu": {"micro": 0, "minor": 12, "major": 2}, "package": "qemu-kvm-ev-2.12.0-18.el7_6.1.1"}, "capabilities": []}}

# unix socket能够经过nc -U进行链接,方法以下
> nc -U qmp.socket
{"QMP": {"version": {"qemu": {"micro": 0, "minor": 12, "major": 2}, "package": "qemu-kvm-ev-2.12.0-18.el7_6.1.1"}, "capabilities": []}}

按照上面执行完命令后,不会退出而是继续等待输入,但这个时候还没法使用,接着,须要输入一条qmp指令才能够

{ "execute" : "qmp_capabilities" }

此时屏幕会输出如下内容,表示从"capabilities negotiation模式"进入了"command"模式

{"return": {}}

接下来,就能够执行qmp的指令了,qmp指令很是多,因为篇幅有限,这里仅举几个例子(更多内容请参考官方文档,本文最后附上网址)

# 查看支持哪些qmp指令
{ "execute": "query-commands" }

# 虚拟机状态
{ "execute": "query-status" }

# 虚拟机暂停
{ "execute": "stop" }

# 磁盘查看
{ "execute": "query-block" }

# 磁盘在线插入
{ "execute": "blockdev-add", "arguments": { "driver": "qcow2", "node-name": "drive-virtio-disk1", "file": { "driver": "file", "filename": "/opt/data.qcow2" } } }
{ "execute": "device_add", "arguments": { "driver": "virtio-blk-pci", "drive": "drive-virtio-disk1" } }

# 磁盘完整备份
{ "execute" : "drive-backup" , "arguments" : { "device" : "drive-virtio-disk0" , "sync" : "full" , "target" : "/opt/backuptest/fullbackup.img" } }

除了使用telnet、nc从外部链接,还能够在qemu启动时候进入一个交互的cli界面,直接输入指令,只不过这个时候输入的是hmp(human monitor protocol),而不是qmp。hmp简化了qmp的使用,但实际在底层依然是转化为qmp进行操做的,配置方法以下

/usr/libexec/qemu-kvm -qmp tcp:127.0.0.1:4444,server,nowait -monitor stdio

此时会出现交互界面,输入help,就能够看到hmp支持的全部命令

(qemu) help

使用hmp不须要输入相似qmp的{ "execute" : "qmp_capabilities" }

这里列出几个范例

# 直接输入info回车,能够看到全部查询类的指令使用方法
(qemu) info

# 查看块设备
(qemu) info block

# 在线增长磁盘
(qemu) drive_add 0 file=/opt/data.qcow2,format=qcow2,id=drive-virtio-disk1,if=none
(qemu) device_add virtio-blk-pci,scsi=off,drive=drive-virtio-disk1

经过libvirt启动qemu,启用QMP

有2种方法:

1. xml里不作任何额外配置,默认就会启用QMP,但经过这种方法启用的QMP,只能经过libvirt接口(好比virsh命令或libvirt api)来进行QMP指令的输入,而不能经过telnet、nc之类的,由于默认启用的QMP,只会生成unix socket(位于/var/lib/libvirt/qemu/domain-xx-DOMAIN/monitor.sock),而该socket被libvirtd始终链接占用着。此时经过ps aux命令能够看到qemu进程参数,和以前有点不太同样,不是-qmp,而是以下

-chardev socket,id=charmonitor,fd=36,server,nowait \
-mon chardev=charmonitor,id=monitor,mode=control

qemu命令参数支持2种方法配置qmp,即-qmp和-mon

这里经过virsh作个简单示范

virsh qemu-monitor-command DOMAIN --pretty '{ "execute": "query-block" }'

使用--pretty是为了让json的输出具备换行缩进的格式化效果,而不是打印在一行里
不须要在执行其余指令前执行{ "execute" : "qmp_capabilities" }

2. 在xml里额外增长2段配置,注意看下面这个xml的第一行,须要增长一个xmlns:qemu,另外在<domain>里增长<qemu:command>

<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
  ...
  <devices>
    ...
  </devices>
  <qemu:commandline>
    <qemu:arg value='-qmp'/>
    <qemu:arg value='unix:/tmp/qmp-sock,server,nowait'/>
  </qemu:commandline>
</domain>

接着经过libvirt启动qemu(好比virsh start xxx),就建立了2个qmp通道,一个是libvirt默认建立的,能够依然使用libvirt接口来执行QMP指令,另外一个就是自定义的qmp,能够经过上面提到的nc来使用

nc -U /tmp/qmp-sock

libvirt也支持hmp:

virsh qemu-monitor-command DOMAIN --hmp 'info block'

qemu-guest-agent(qemu-ga)

经过qmp还能够对虚拟机内的操做系统进行RPC操做,其原理是:

1. 先在xml里配置channel段,而后启动虚拟机,会在宿主机上生成一个unix socket,同时在vm里生成一个字符设备,生成的unix socket和字符设备能够理解为一个channel隧道的两端
2. 虚拟机里要启动qemu-guest-agent守护进程,该守护进程会监听字符设备
3. 而后能够在宿主机上将虚拟机里的qemu-guest-agent所支持的RPC指令通过channel发送到虚拟机里,虚拟机里的qemu-guest-agent从字符设备收到数据后,执行指令,好比读写文件、修改密码等等

若要使用qemu-guest-agent须要知足如下条件

1. xml里配置channel,范例:

<domain type='kvm'>
  ...
  <devices>
    ...
    <channel type='unix'>
      <source mode='bind' path='/tmp/channel.sock'/>
      <target type='virtio' name='org.qemu.guest_agent.0'/>
    </channel>
  </devices>
</domain>

注意,path能够自定义,但name须要保持org.qemu.guest_agent.0,由于这会影响虚拟机里字符设备的文件名,而虚拟机里的qemu-guest-agent服务默认读取的是对应org.qemu.guest_agent.0的字符设备,若是改了name,那么qemu-guest-agent的配置文件也要跟着改,改为对应name的路径

2. 虚拟机内的操做系统内核须要支持(linux、windows均支持)

3. 虚拟机里要安装并启动qemu-ga的服务(好比centos能够yum install qemu-ga && systemctl start qemu-guest-agent,windows经过导入virtio-win的iso,该iso里包含有qemu-ga程序)

当按照上述配置好后,能够在宿主机上进行RPC操做

# 测试虚拟机里的qemu-guest-agent是否可用
virsh qemu-agent-command DOMAIN --pretty '{ "execute": "guest-ping" }'

# 查看支持的qemu-guest-agent指令
virsh qemu-agent-command DOMAIN --pretty '{ "execute": "guest-info" }'

# 得到网卡信息
virsh qemu-agent-command DOMAIN --pretty '{ "execute": "guest-network-get-interfaces" }'

# 执行命令,这是异步的,第一步会返回一个pid,假设为797,在第二步须要带上这个pid
virsh qemu-agent-command DOMAIN --pretty '{ "execute": "guest-exec", "arguments": { "path": "ip", "arg": [ "addr", "list" ], "capture-output": true } }'
virsh qemu-agent-command DOMAIN --pretty '{ "execute": "guest-exec-status", "arguments": { "pid": 797 } }'

qemu-guest-agent不支持hmp调用

虚拟机里的/etc/sysconfig/qemu-ga内容中的BLACKLIST_RPC参数能够配置禁止哪些指令

官方参考文档

# qemu
https://qemu.weilnetz.de/doc/qemu-doc.html

# qmp
https://qemu.weilnetz.de/doc/qemu-qmp-ref.html

# qemu-guest-agent
https://qemu.weilnetz.de/doc/qemu-ga-ref.html
相关文章
相关标签/搜索