QEMU实例运行时,用户可以通过monitor机制来与实例进行交互,通过它可以获取当前运行的虚拟机信息,处理热插拔设备,管理虚拟机快照等。要了解全部能力,可以参考文档:
https://qemu.weilnetz.de/doc/qemu-doc.html#pcsys_005fmonitor
QEMU启动时,需要使用-monitor
选项指定做为console
设备,官方文档说明如下:
1 | -monitor dev |
下面首先以标准输入输出设备做为console
来启动QEMU实例:
1 | [root@localhost ~]# qemu-system-x86_64 cirros-0.3.5-x86_64-disk.img -smp 2,cores=2 -m 2G -vnc :20 -device virtio-net-pci,netdev=net0 -netdev tap,id=net0,ifname=tap0,script=no,downscript=no -name vm0 -monitor stdio |
在console
里可以输入相关命令来完成我们的操作,比如我们查看虚拟机网络设备状态:
1 | (qemu) info network |
也可以动态添加设备,比如我们添加一个8M大小的ivshmem
设备:
1 | (qemu) device_add ivshmem,size=8m,shm=flygoast_vm0,bus=pci.0,addr=0x1f |
执行后,我们在Guest OS里查看PCI设备, 可以看到已经检测到了新的PCI设备:
除了标准输入输出设备,也可以使用网络连接做为console
, 比如TCP、UnixSocket等。下面使用TCP监听端口做为console
启动QEMU实例:
1 | [root@localhost ~]# qemu-system-x86_64 cirros-0.3.5-x86_64-disk.img -smp 2,cores=2 -m 2G -vnc :20 -device virtio-net-pci,netdev=net0 -netdev tap,id=net0,ifname=tap0,script=no,downscript=no -name vm0 -monitor tcp:127.0.0.1:4444,server,nowait -daemonize |
使用nc
连接console
并查询虚拟机状态:
1 | [root@localhost ~]# nc 127.0.0.1 4444 |
上述这种方式更偏向用户直接输入命令进行交互,称为HMP(Human Machine Protocol),程序使用这种方式不是太方便。QEMU还提供了另外一种基于JSON的QMP(QEMU Machine Protocol)来满足自动化处理的需求。Libvirt就是使用QMP来控制QEMU实例。
QMP规范可以参考:
- https://github.com/qemu/qemu/blob/master/docs/interop/qmp-intro.txt
- https://github.com/qemu/qemu/blob/master/docs/interop/qmp-spec.txt
- https://qemu.weilnetz.de/doc/qemu-qmp-ref.html
QMP协议的工作流程如下:
- 连接建立后服务器发送欢迎信息,进入能力协商(
capabilities negotiation
)模式 - 客户端发送
{“execute”:”qmp_capablities”}
- 成功则服务器返回
{“return”:{}}
,否则return
中会含有error
。 - 客户端发送命令
- 服务器以异步消息返回结果
QMP方式console
也可以使用多种设备形式, 如,标准输入输出、TCP、UnixSocket等。可以通过QEMU选项-mon
来指定console
设备, 我们以标准输入输出设备做为console
启动QEMU实例:
1 | [root@localhost ~]# qemu-system-x86_64 cirros-0.3.5-x86_64-disk.img -smp 2,cores=2 -m 2G -vnc :20 -device virtio-net-pci,netdev=net0 -netdev tap,id=net0,ifname=tap0,script=no,downscript=no -name vm0 -chardev stdio,id=mon0 -mon chardev=mon0,mode=control,pretty=on |
可以看到服务器发送了欢迎信息到标准输出,我们在标准输入设备里输入:
1 | {"execute":"qmp_capabilities”} |
QEMU实例返回:
1 | { |
此时我们可以发送命令了,我们来查询虚拟机状态:
1 | {"execute":"query-status”} |
服务器返回了结果:
1 | { |
我们还可以使用UnixSocket做为console
:
1 | [root@localhost ~]# qemu-system-x86_64 cirros-0.3.5-x86_64-disk.img -smp 2,cores=2 -m 2G -vnc :20 -device virtio-net-pci,netdev=net0 -netdev tap,id=net0,ifname=tap0,script=no,downscript=no -name vm0 -chardev socket,id=mon0,path=/tmp/vm0.monitor,server,nowait -mon chardev=mon0,mode=control,pretty=on -daemonize |
使用nc
连接UnixSocket文件, QEMU实例返回了欢迎信息:
1 | [root@localhost ~]# nc -U /tmp/vm0.monitor |
除了使用-mon
选项,还可以直接使用-qmp
选项:
1 | [root@localhost ~]# qemu-system-x86_64 cirros-0.3.5-x86_64-disk.img -smp 2,cores=2 -m 2G -vnc :20 -device virtio-net-pci,netdev=net0 -netdev tap,id=net0,ifname=tap0,script=no,downscript=no -name vm0 -qmp unix:/tmp/vm0.monitor,server,nowait -daemonize |
使用nc
连接:
1 | [root@localhost ~]# nc -U /tmp/vm0.monitor |
上面提到,Libvirt使用QMP与QEMU实例通信,libvirt创建QEMU实例时会指定一个UnixSocket文件做为console
。我们可以通过使用virsh
命令的qemu-monitor-command
子命令来访问QEMU monitor,比如我们查询块文件信息:
1 | [root@localhost ~]# virsh qemu-monitor-command i1 '{"execute":"query-block"}' |
这种方式使用的是JSON格式的QMP协议,可以加上—hmp
选项直接输入命令来交互:
1 | [root@localhost ~]# virsh qemu-monitor-command --hmp i1 info kvm |
我们如果想直接连接libvirt生成的Unix Socket文件来操作QEMU实例,需要先将libvirtd关闭,如:
1 | [root@localhost ~]# service libvirtd stop |