https://cloud.tencent.com/developer/article/1468105
qemu) "ctrl+]" to return to telnet, (qemu)"quit" to exit qemu applicatoin.
通過網絡連接到QEMU MONITO
http://smilejay.com/2014/01/access-qemu-monitor-accross-network/
qemu-system-aarch64 -name vm2 -daemonize \ -enable-kvm -M virt -cpu host -smp 2 -m 4096 \ -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on \ -numa node,memdev=mem -mem-prealloc \ -global virtio-blk-device.scsi=off \ -device virtio-scsi-device,id=scsi \ -kernel vmlinuz-4.18 --append "console=ttyAMA0 root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1" \ -initrd initramfs-4.18 \ -drive file=vhuser-test1.qcow2 \ -device vfio-pci,host=0000:05:00.0 \ -net nic,macaddr=00:00:00:99:99:01 \ -monitor telnet:localhost:4321,server,nowait\ -vnc :10
system_powerdown不能關機,quit可以關機
[root@localhost cloud_images]# telnet localhost 4321 Trying ::1... Connected to localhost. Escape character is '^]'. QEMU 5.1.90 monitor - type 'help' for more information (qemu) system_powerdown (qemu) quit Connection closed by foreign host. [root@localhost cloud_images]#
關機命令
{ "execute": "stop" }
[root@localhost cloud_images]# telnet 127.0.0.1 4444
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
{"QMP": {"version": {"qemu": {"micro": 90, "minor": 1, "major": 5}, "package": "v5.2.0-rc0-dirty"}, "capabilities": ["oob"]}}
ifo^H^H
{"error": {"class": "GenericError", "desc": "JSON parse error, invalid keyword 'ifo'"}}
{"error": {"class": "GenericError", "desc": "JSON parse error, stray '\b'"}}
{"error": {"class": "GenericError", "desc": "JSON parse error, stray '\b'"}}
info
{"error": {"class": "GenericError", "desc": "JSON parse error, invalid keyword 'info'"}}
qmp_system_powerdown
{"error": {"class": "GenericError", "desc": "JSON parse error, invalid keyword 'qmp'"}}
{"error": {"class": "GenericError", "desc": "JSON parse error, stray '_'"}}
^]
telnet>
^]
telnet> qmp_system_powerdown
?Invalid command
telnet> ^[[A^H^H
?Invalid command
telnet> shutdown
?Invalid command
telnet> powerwo^H^H
?Invalid command
telnet> powerdown
?Invalid command
telnet> quit
Connection closed.
[root@localhost cloud_images]# telnet 127.0.0.1 4444
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
{"QMP": {"version": {"qemu": {"micro": 90, "minor": 1, "major": 5}, "package": "v5.2.0-rc0-dirty"}, "capabilities": ["oob"]}}
{ "execute": "stop" }
Connection closed by foreign host.
[root@localhost cloud_images]#
[root@localhost binary]# nc -U qmp.sock
{"QMP": {"version": {"qemu": {"micro": 90, "minor": 1, "major": 5}, "package": "v5.2.0-rc0-dirty"}, "capabilities": ["oob"]}}
{ "execute": "stop" }
Ncat: Connection reset by peer.
[root@localhost binary]#
1. QEMU monitor支持遠程telnet訪問:
1
|
[root@kvm-host ~]# qemu-system-x86_64 -enable-kvm -smp 2 -m 1024 vm2.img -monitor telnet:10.1.77.82:4444,server,nowait
|
關於這里-monitor的選項,做如下說明:
1
2
3
4
5
6
|
tcp – raw tcp sockets #下面第2點,我的舉例是RAW TCP socket
telnet – the telnet protocol is used instead of raw tcp sockets. This is the preferred option over tcp as you can break out of the monitor using Ctrl-] then typing quit. You can’t break out of the monitor like this after connecting with the raw socket option
10.1.77.82 – Listen on this host/IP only. You can use 127.0.0.1 if you want to only allow connections locally. If you want to listen on any ip address on the server, just leave this blank so you end up with two consecutive colons ie “::” .
4444 – port number to listen on.
server – listening in server mode
nowait – qemu will wait for a client socket application to connect to the port before continuing unless this option is used. In most cases you’ll want to use the nowait option.
|
通過telnet連接到遠程的QEMU monitor上:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
jay@jay-linux:~$ telnet 10.1.77.82 4444
Trying 10.1.77.82...
Connected to 10.1.77.82.
Escape character is '^]'.
QEMU 1.7.50 monitor - type 'help' for more information
(qemu) info kvm
kvm support: enabled
(qemu) info status
VM status: running
(qemu) help migrate
migrate [-d] [-b] [-i] uri -- migrate to URI (using -d to not wait for completion)
-b for migration without shared storage with full copy of disk
-i for migration without shared storage with incremental copy of disk (base image shared between src and destination)
(qemu) ctrl + ] (斷掉telnet連接)
telnet> quit (退出telnet)
Connection closed.
|
2. QEMU monitor支持RAW socket的遠程訪問:
1
|
[root@kvm-host ~]# qemu-system-x86_64 -enable-kvm -smp 2 -m 1024 vm2.img -monitor tcp:10.1.77.82:4444,server,nowait
|
可以使用netcat去連接這個socket:
1
2
3
4
5
6
|
jay@jay-linux:~$ nc 10.1.77.82 4444
QEMU 1.7.50 monitor - type 'help' for more information
(qemu) info kvm
info kvm
kvm support: enabled
(qemu) ^C
|
QMP介紹
qemu對外提供了一個socket接口,稱為qemu monitor,通過該接口,可以對虛擬機實例的整個生命周期進行管理,主要有如下功能
▷ 狀態查看、變更
▷ 設備查看、變更
▷ 性能查看、限制
▷ 在線遷移
▷ 數據備份
▷ 訪問內部操作系統
通過該socket接口傳遞交互的協議是qmp,全稱是qemu monitor protocol,這是基於json格式的協議
在繼續往下講之前,需要先了解qemu、kvm、libvirt之間的區別(因為有很多童鞋對這三者的理解是混亂的)
▷ qemu:虛擬機仿真器。通過軟件模擬出cpu、內存、磁盤、主板、網卡等設備
▷ kvm:高性能的cpu仿真器。由於軟件模擬的cpu性能很差,因此出現了kvm,這是通過硬件與內核的支持實現接近native性能的cpu仿真器,可以理解為虛擬機里的cpu任務直接交給物理機cpu完成。
▷ libvirt:虛擬機管理平台。能納管qemu、lxc、esx等虛擬化軟件,通過編寫xml實現對虛擬機、存儲、網絡等進行配置和管理
單獨使用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" } }
進入command模式后,不僅能夠執行命令,還同時成為了事件的輸出端口,比如執行磁盤備份命令后,應該就會陸續接收到一些關於備份成功或失敗的事件,比如:
{ "execute" : "drive-backup" , "arguments" : { "device" : "drive-virtio-disk0" , "sync" : "top" ,"target" : "/opt/ccvm/A" } } {"timestamp": {"seconds": 1551061368, "microseconds": 725212}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "drive-virtio-disk0"}} {"timestamp": {"seconds": 1551061368, "microseconds": 725330}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "drive-virtio-disk0"}} {"return": {}} {"timestamp": {"seconds": 1551061373, "microseconds": 276382}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "drive-virtio-disk0"}} {"timestamp": {"seconds": 1551061373, "microseconds": 276462}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "drive-virtio-disk0"}} {"timestamp": {"seconds": 1551061373, "microseconds": 276508}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "drive-virtio-disk0", "len": 21474836480, "offset": 11141120, "speed": 0, "type": "backup"}} {"timestamp": {"seconds": 1551061373, "microseconds": 276551}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "drive-virtio-disk0"}} {"timestamp": {"seconds": 1551061373, "microseconds": 276583}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "drive-virtio-disk0"}}
上面第一行是執行命令,接下來的就是陸續接收到的事件,這與linux的tty終端很像 接收到的事件不僅是本窗口命令執行的相關事件,而是會收到所有qmp事件,比如開了多個qmp監聽器,那么只要監聽器進入command模式,就都會同時接收到事件(下面還提到了libvirt啟動qmp,也是一樣的效果)
除了使用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
還有一種脫褲子放屁的hmp寫法,是將hmp套在qmp里,
{
"execute" : "human-monitor-command", "arguments" : { "command-line" : "這里寫hmp語法" } }
比如
{
"execute" : "human-monitor-command", "arguments" : { "command-line" : "drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=xxxx,file.port=xxxx,file.export=colo1,node-name=nbd_client1" } }