一、qga简介

1、qga工具

qemu guest agent,简称qga,是一个运行在虚拟机内部的普通应用程序,可实现宿主机libvirt和虚拟机的通信,宿主机可通过向虚机中的qga发送命令控制虚机。

这种通信不依赖网络,而是通过virtio-serial的方式。使用virtio传递消息,对虚拟机和主机的网络设置没有任何要求,且效率更高,类似于VMware Tools。

 

2、宿主机libvirt和VM通信方式选择

宿主机若要和VM通信,需要满足以下两个条件:

1)vm内部和外部宿主机之间,打开一个通道,进行数据交互

2)vm内部需要安装agent,用于接收外部宿主机具体的指令,并反馈结果

其中,打开通道有2类方法:

(1)走网络:需预插入一张管理网卡,增加网络拓扑复杂性

(2)走设备:只需在VM内部和宿主之间建立一个设备通道,实现简单,为当前使用方式

QEMU通过串口设备的模拟,为宿主机和虚拟机提供了一个数据通道(channel),这个通道的两端分别是在虚拟机内看到的串口和在宿主机上看到的unix socket文件。

串口设备的速率较低,适合小数据量的交换。

 

3、基本实现原理

1)创建虚机时,需要在xml中配置channel段,写入相关参数,启动虚机时,会在宿主机上生成对应unix socket文件,同时,会在vm里生成一个字符设备,生成的unix socket和字符设备可以理解为一个channel隧道的两端

2)虚拟机镜像制作时,安装好qemu-ga守护进程并配置开启自启动,qemu-ga进程会监听字符设备。

3)宿主机上,将虚机中qga支持的rpc指令,通过channel发送,虚机中的qemu-guest-agent从串口设备收到数据后,执行相关指令。可实现文件读写、密码修改等

 

二、制作Guest镜像,部署qemu-ga

1、linux虚机安装qemu-ga

(1)rhel/centos安装qga

yum install qemu-guest-agent

(2)配置开机启动

systemctl enable qemu-guest-agent

(3)按需修改/etc/sysconfig/qemu-ga配置文件

[root@centos7-001 ~]# cat /etc/sysconfig/qemu-ga

# Default: /dev/virtio-ports/org.qemu.guest_agent.0

DEVPATH="/dev/virtio-ports/org.qemu.guest_agent.1"

# 禁用指定的指令

#BLACKLIST_RPC=""

 

2、Windows虚机安装qemu-ga

windows系统需要下载virtio-win,以及qemu-ga安装包

https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/

https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-qemu-ga/

 

三、xml配置virtio对应设备,创建虚机

1、libvirt在虚拟机创建时启动virtio通道,在xml虚机配置中加入virtio通道设备,如下:

<channel type='unix'>
    <source mode='bind' path='/var/lib/libvirt/qemu/org.qemu.guest_agent.1.instance-00000284.sock'/>
    <target type='virtio' name='org.qemu.guest_agent.1'/>
    <alias name='channel0'/>
    <address type='virtio-serial' controller='0' bus='0' port='1'/>
</channel>

其中,path为virtio通道在主机本地的映射节点文件,宿主机可以基于此socket文件,通过unix sock实现与虚拟机的通信

 

2、 基于以上xml创建的虚拟机中,会发现新的串口设备

设备名可能是/dev/vport0p0 或/dev/vport0p1,如下:

[root@centos7-001 ~]# cat /etc/sysconfig/qemu-ga |grep guest_agent

# Default: /dev/virtio-ports/org.qemu.guest_agent.0

DEVPATH="/dev/virtio-ports/org.qemu.guest_agent.1"

[root@centos7-001 ~]# ll /dev/virtio-ports/org.qemu.guest_agent.1

lrwxrwxrwx 1 root root 11 Jul 17 10:12 /dev/virtio-ports/org.qemu.guest_agent.1 -> ../vport1p1

[root@centos7-001 ~]# ll /dev/vport1p1

crw------- 1 root root 249, 1 Jul 17 10:12 /dev/vport1p1

[root@centos7-001 ~]#

 

四、通过socat方式指定socket文件与虚机通信

虚机内部默认串口name修改为org.qemu.guest_agent.1之后,在宿主机上连接虚机,可使用socat方式

(默认org.qemu.guest_agent.0 可以使用 virsh qemu-agent-command方式通信)

 

1、下载socat,安装到宿主机

http://rpmfind.net/linux/centos/7.8.2003/os/x86_64/Packages/socat-1.7.3.2-2.el7.x86_64.rpm

2、宿主机上执行socat命令连接指定虚机socket文件

3、连接成功后,执行对应的参数,会有返回值

[root@compute1 ~]# socat unix-connect:/var/lib/libvirt/qemu/org.qemu.guest_agent.1.instance-00000275.sock readline

# 查看当前所有支持的命令

{"execute": "guest-info"} <------ 直接输入,返回以下return内容,此命令可以查看所有支持的命令

{"return": {"version": "1.5.3", "supported_commands": [{"enabled": true, "name": "guest-default-dir-file-open"}, {"enabled": true, "name": "guest-file-upload"}, {"enabled": true, "name": "guest-command-py"}, {"enabled": true, "name": "guest-file-delete"}, {"enabled": true, "name": "guest-command"}, {"enabled": true, "name": "guest-net-usage"}, {"enabled": true, "name": "guest-disk-io"}, {"enabled": true, "name": "guest-disk-usage"}, {"enabled": true, "name": "guest-memory-usage"}, {"enabled": true, "name": "guest-cpu-usage"}, {"enabled": true, "name": "guest-get-statvfs"}, {"enabled": true, "name": "guest-set-vcpus"}, {"enabled": true, "name": "guest-get-vcpus"}, {"enabled": true, "name": "guest-network-get-interfaces"}, {"enabled": true, "name": "guest-suspend-hybrid"}, {"enabled": true, "name": "guest-suspend-ram"}, {"enabled": true, "name": "guest-suspend-disk"}, {"enabled": true, "name": "guest-fstrim"}, {"enabled": true, "name": "guest-fsfreeze-thaw"}, {"enabled": true, "name": "guest-fsfreeze-freeze"}, {"enabled": true, "name": "guest-fsfreeze-status"}, {"enabled": true, "name": "guest-file-flush"}, {"enabled": true, "name": "guest-file-seek"}, {"enabled": true, "name": "guest-file-write"}, {"enabled": true, "name": "guest-file-read"}, {"enabled": true, "name": "guest-file-close"}, {"enabled": true, "name": "guest-file-open"}, {"enabled": true, "name": "guest-shutdown"}, {"enabled": true, "name": "guest-info"}, {"enabled": true, "name": "guest-set-time"}, {"enabled": true, "name": "guest-get-time"}, {"enabled": true, "name": "guest-ping"}, {"enabled": true, "name": "guest-sync"}, {"enabled": true, "name": "guest-sync-delimited"}]}}

# Ping虚机qemu-ga,如果不返回错误信息,则成功

{"execute":"guest-ping"}

{"return":{}}

 

# 获取虚机系统时间

{"execute":"guest-get-time"}

{"return": 1595211016927964000}

 

# 获取cpu使用率、内存使用率、磁盘使用率及磁盘io(磁盘使用率按分区获取、磁盘io按设备获取)

{"execute":"guest-cpu-usage"}

{"return": 0}

{"execute":"guest-memory-usage"}

{"return": {"free_mem": 882544640, "total_mem": 1027674112, "usage": 15}}

{"execute":"guest-disk-usage"}

{"return": [{"total": 52708569088, "name": "/", "free": 48791240704, "type": "ext4"}]}

{"execute":"guest-disk-io"}

{"return": [{"name": "vda", "io_util": 0.008261, "io_time": 8.169811, "read_kB": 0, "read_cnt": 0, "size": 53687091200, "write_kB": 1.24991, "write_cnt": 0.19036}, {"name": "vdb", "io_util": 0, "io_time": 0, "read_kB": 0, "read_cnt": 0, "size": 5368709120, "write_kB": 0, "write_cnt": 0}]}

 

# 获取当前socket对应虚机的所有网卡接口信息

{"execute": "guest-network-get-interfaces"} <------ 直接输入,用于获取虚机的所有网卡信息,返回以下return内容

{"return": [{"name": "lo", "ip-addresses": [{"ip-address-type": "ipv4", "ip-address": "127.0.0.1", "prefix": 8}, {"ip-address-type": "ipv6", "ip-address": "::1", "prefix": 128}], "hardware-address": "00:00:00:00:00:00"}, {"name": "eth0", "ip-addresses": [{"ip-address-type": "ipv4", "ip-address": "172.16.6.12", "prefix": 24}, {"ip-address-type": "ipv6", "ip-address": "fe80::f816:3eff:fe6e:c5ab", "prefix": 64}], "hardware-address": "fa:16:3e:6e:c5:ab"}, {"name": "eth1", "ip-addresses": [{"ip-address-type": "ipv4", "ip-address": "172.16.5.29", "prefix": 24}, {"ip-address-type": "ipv6", "ip-address": "fe80::f816:3eff:fef1:f88e", "prefix": 64}], "hardware-address": "fa:16:3e:f1:f8:8e"}, {"name": "eth2", "ip-addresses": [{"ip-address-type": "ipv4", "ip-address": "172.16.1.189", "prefix": 24}, {"ip-address-type": "ipv6", "ip-address": "fe80::f816:3eff:feee:ba60", "prefix": 64}], "hardware-address": "fa:16:3e:ee:ba:60"}]}

 

# 获取当前socket对应虚机的网卡相关监控信息

{"execute":"guest-net-usage", "arguments":{"mac_list":[{"mac":"fa:16:3e:db:3d:85"},{"mac":"fa:16:3e:d5:9d:ff"},{"mac": "fa:16:3e:66:9f:80"},{"mac":"fa:16:3e:51:17:12"},{"mac":"fa:16:3e:09:5e:e2"},{"mac":"fa:16:3e:03:b0:c4"},{"mac":"fa:16:3e:0c:2d:ad"},{"mac":"fa:16:3e:26:d6:d2"},{"mac":"fa:16:3e:f3:b5:00"},{"mac":"fa:16:3e:19: ec:c9"},{"mac":"fa:16:3e:1e:d0:02"},{"mac":"fa:16:3e:2e:5b:38"},{"mac":"fa:16:3e:a7:99:59"},{"mac":"fa:16:3e:2f:b5:4f"},{"mac":"fa:16:3e:4c:c2:68"},{"mac":"fa:16:3e:22:79:91"},{"mac":"fa:16:3e:6e:c5:ab"}]}} <------ 直接输入,返回以下return内容

{"return": [{"name": "eth0", "out_rate": 0, "in_rate": 60, "mac": "fa:16:3e:6e:c5:ab"}]}

 

4、通过socket文件连接虚机读取文件的方法

1)创建虚机,并使用账号密码登录虚机内部,创建自定义文件test,如下:

[root@centos7-001 ~]# cat /home/testfile

abcd

2)在宿主机上,使用socat指定socket文件,连接虚机读取指定路径文件的内容

[root@compute2 ~]# socat unix-connect:/var/lib/libvirt/qemu/org.qemu.guest_agent.1.instance-00000299.sock readline

{"execute":"guest-file-open","arguments":{"path":"/home/testfile"}}

{"return": 1134}

{"execute":"guest-file-read","arguments":{"handle": 1134}}

{"return": {"count": 5, "buf-b64": "YWJjZAo=", "eof": true}}

3)对获取的文件内容进行base64解码,可获取到文件中的内容

[root@controller1 ~]# echo -n "YWJjZAo=" |base64 -d

abcd

 

五、禁用socket文件与虚机通信相关操作

若出于安全考虑,需要禁用qga某些功能,可修改配置文件的BLACKLIST_RPC,添加禁用操作黑名单列表

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

例如,需要禁用guest-file-open,需要做如下修改:

[root@centos7-001 ~]# vim /etc/sysconfig/qemu-ga

#BLACKLIST_RPC=""

BLACKLIST_RPC="guest-file-open"

之后,重启qemu-ga服务

[root@centos7-001 ~]# systemctl restart qemu-ga

 

验证:

在宿主机上,使用socat指定此虚机socket文件,执行guest-file-open,报错如下。

[root@compute2 ~]# socat unix-connect:/var/lib/libvirt/qemu/org.qemu.guest_agent.1.instance-00000299.sock readline

{"execute":"guest-file-open","arguments":{"path":"/home/testfile"}}

{"error": {"class": "GenericError", "desc": "The command guest-file-open has been disabled for this instance"}}

 

六、qga应用场景功能

qemu对外提供了一个socket接口,主要用于解决虚机外部无法实现的功能,例如:

▷ 在线修改密码

▷ 在线增加公钥

▷ 在线采集监控性能数据(如cpu使用率、负载、内存使用量等性能指标)

▷ 设备查看、变更

▷ 数据备份

 

七、org.qemu.guest_agent.0 和 org.qemu.guest_agent.1 区别

1)若name是org.qemu.guest_agent.0 [指定name],此时宿主机的libvirt可以和qga对应的socket建立连接。

<target type='virtio' name='org.qemu.guest_agent.0'/>

2)若name不是org.qemu.guest_agent.0,那么在宿主机上的libvirt将不会与socket建立连接。

某些情况下,用户可能只希望在其虚机XML中配置qga,但不希望libvirt连接到qga对应的套接字,此时,target name就要使用除了org.qemu.guest_agent.0之外的name,例如org.qemu.guest_agent.1

需要同时修改guest xml的path和name字段,如下:

<source mode='bind' path='/var/lib/libvirt/qemu/org.qemu.guest_agent.1.instance-00000284.sock'/>

<target type='virtio' name='org.qemu.guest_agent.1'/>

同时,在制作虚机镜像的qga对应配置,也需要修改相关路径name为:org.qemu.guest_agent.1

 

修改作用:

在宿主机上,无法通过libvirt相关命令来 获取/执行 qga相关命令控制虚拟机(但是还可以通过其它方式来交互,例如socat)。

[root@compute1 ~]# virsh qemu-agent-command instance-00000284 --pretty '{"execute":"guest-net-usage"}'

error: argument unsupported: QEMU guest agent is not configured

 

八、其它

1、socket文件的创建

在创建虚机时,组装xml文件,libvirt指定xml创建虚机,创建好虚机后,对应path的socket文件会由libvirtd自动创建。

2、qmp

QGA的交互协议是qmp(qemu monitor protocol)协议,使用json格式交换数据。

 

 

参考:

https://wiki.libvirt.org/page/Qemu_guest_agent

https://www.cnblogs.com/fzxiaomange/p/qmp-qemu-interactive.html

https://www.cnblogs.com/fzxiaomange/p/kvm-inject.html

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐