KVM 管理员必备 CLI:virt-top、virt-cat、virt-ls 等 6 个工具实战

多数 KVM 故障排查根本不需要进入虚拟机控制台。libguestfs 工具可以在虚拟机关机时读取和编辑其磁盘镜像中的文件,virt-clone 能以更安全的方式复制虚拟机,virt-top 则能在宿主机上显示每个域正在做什么。无需打开一次 virt-manager,你就能提取日志、修复损坏的 sshd_config,并查明哪个虚拟机占满了磁盘。

本文介绍日常最常用的 6 个工具。所有命令均于 2026 年 11 月在 Rocky Linux 10 和 Ubuntu 24.04 宿主机上运行,下面的输出也来自这些测试。每个工具解决不同问题,因此先给出总览:

  • virt-top:实时查看每个虚拟机的 CPU 和内存占用。
  • virt-cat:打印镜像中的文件。
  • virt-ls:列出镜像中的文件。
  • virt-edit:无需启动虚拟机即可修复文件。
  • virt-df:查看所有虚拟机的磁盘使用量。
  • virt-clone:安全复制虚拟机。

这些工具还有配套命令:qemu-img 和 qemu-nbd 负责镜像转换与挂载,virt-copy-in 把文件复制到镜像中,virt-sysprep 则重置克隆镜像,使其能以独立机器的身份启动。

安装 KVM CLI 工具

这套工具由三个软件包提供。由于依赖相同,两种发行版都可以用一条命令全部安装。virt-top 是独立软件包;文件工具(virt-cat、virt-ls、virt-edit、virt-df)来自 libguestfs 套件;virt-clone 则随 virt-install 一起提供。参照旧版 RHEL 指南时要注意软件包名称变化:RHEL 10 使用 guestfs-tools,Debian 和 Ubuntu 仍使用 libguestfs-tools。名称弄错正是全新 RHEL 10 主机报告“找不到 libguestfs-tools 软件包”的常见原因。

sudo dnf install -y guestfs-tools virt-top virt-install
sudo apt update
sudo apt install -y virt-top libguestfs-tools virtinst libvirt-daemon-system

确认宿主机已安装的组件。测试所用的 Rocky Linux 10 主机版本如下:

virt-top --version
virt-cat --version
virt-install --version

virt-top 和 virt-cat 会打印名称及版本,virt-install 则只打印版本号:

virt-top 1.1.2 ocaml-libvirt 0.6.1.7
virt-cat 1.54.0
5.1.0

Ubuntu 24.04 上同样的检查显示 virt-top 1.1.1、virt-cat 1.52.0 和 virt-install 4.1.0。这里还有一个打包细节:Ubuntu 上的文件工具实际上也位于 guestfs-tools 软件包中,libguestfs-tools 会把它作为依赖引入,因此前面的安装命令两种写法都能正常工作。本文其余命令在两个平台上完全一致。

Rocky Linux 主机上的版本检查结果如下。

Rocky Linux 10 KVM 宿主机上的 virt-top、virt-cat 与 virt-install 版本

Ubuntu 主机使用的是同一批工具中较旧的 Debian 发布版本:

Ubuntu 24.04 KVM 宿主机上的 virt-top、virt-cat 与 virt-install 版本

两台主机都从官方软件仓库安装:Rocky 使用 AppStream,Ubuntu 24.04 使用 Ubuntu 归档,均不需要 EPEL 或 PPA。

使用 virt-top 实时监控虚拟机

virt-top 相当于虚拟机管理程序版的 top。它读取 libvirt API,每个域显示一行,包括 CPU、内存、磁盘请求和网络流量,每隔几秒刷新。因此,某个虚拟机变得异常繁忙时,屏幕会在用户提交工单之前就显示出来。针对默认的 qemu:///system 连接运行:

sudo virt-top

用于脚本和告警时,可以以脚本模式运行一次并写出 CSV。--script 完全跳过终端界面,因此在 cron 中运行也很安全。下面的命令采样 8 秒后退出:

sudo virt-top --script --csv /tmp/vt.csv --end-time +8

表头会命名所有列,每个采样行包含宿主机汇总以及运行中域的数据:

Hostname,Time,Arch,Physical CPUs,Count,Running,Blocked,Paused,Shutdown,Shutoff,Crashed,Active,Inactive,%CPU,Total hardware memory (KB),Total memory (KB),Total guest memory (KB),Total CPU time (ns),Domain ID,Domain name,CPU (ns),%CPU,Mem (bytes),%Mem,Block RDRQ,Block WRRQ,Net RXBY,Net TXBY
kvm-host01,00:43:20,x86_64,2,2,1,0,0,0,0,0,1,1,0.0,3737636,1048576,1048576,0,19,db01,0.,0.,0,0,,,,

各列数字与交互界面相同,因此 CSV 模式很适合告警:让 cron 或指标导出器读取文件,并针对关注的字段设置告警,不必整天盯着终端。首次采样时四个网络字节列为空,因为按域统计的计数器会延迟一个采样间隔;空值是正常现象,并非导出损坏。读取数据行时,值得告警的字段包括:

  • %CPU:该域在本次采样中消耗的宿主机 CPU 比例。
  • %MEM:该域占用的宿主机内存比例。
  • RDRQ 与 WRRQ:读写请求数,是发现虚拟机之间存储争抢最快的信号。
  • TIME:累计 CPU 时间,连续几天高 CPU 的虚拟机会十分明显。

CSV 示例显示了表头和 db01 的数据行:

virt-top 脚本模式在 Rocky Linux 10 主机上为 db01 写出 CSV 样本

把 -c 指向远程 URI 就能监控另一台主机,例如 sudo virt-top -c qemu+ssh://user@remote-host/system。数据会通过 SSH 流式传回终端,无需登录目标机器或打开第二个窗口,远端也只需要 libvirt。它要求以密钥方式通过 SSH 登录该主机;如果你已能从终端管理这台机器,相关配置通常已经具备。本文其他工具也支持同样的 URI 形式。

使用 virt-cat 读取虚拟机中的文件

virt-cat 可以打印虚拟机磁盘镜像中的任意文件。虚拟机无需运行,镜像中的内容也不会改变。既可以用 -d 按 libvirt 域名引用虚拟机,也可以用 -a 直接指定镜像文件:

sudo virt-cat -d db01 /etc/os-release

测试虚拟机是 Debian 12 镜像,下面是从离线磁盘直接读取的前几行:

PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

日志和配置文件也使用相同方式读取。以下两个读取命令几乎每天都会用到:

sudo virt-cat -d db01 /etc/fstab

挂载表会完全按照虚拟机看到的内容打印:

# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# systemd generates mount units based on this file, see systemd.mount(5).
# Please run 'systemctl daemon-reload' after making changes here.
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/vda1 during installation
UUID=ddf91058-656c-4606-806a-8a4a9d31676c /               ext4    errors=remount-ro 0       1

测试主机执行这次读取时,虚拟机处于关机状态:

virt-cat 在 Rocky Linux 10 主机上从离线的 db01 镜像读取 /etc/fstab

由于输出写到标准输出,普通的 Shell 管道同样适用。可以用管道过滤,也可以把镜像中的文件导出,用于工单排查:

sudo virt-cat -d db01 /etc/passwd | tail -3
sudo virt-cat -d db01 /var/log/auth.log > auth-today.log

第二行在凌晨三点尤其有用:只需一条命令,就能在宿主机上取得无法启动虚拟机的认证日志。有一种失败模式几乎所有人都会遇到,因此值得单独说明。

virt-cat 会拒绝运行中虚拟机的镜像

如果把 virt-cat 指向仍处于开机状态的域磁盘,libguestfs 会在镜像锁处停止:

libguestfs: error: could not create appliance through libvirt. Original error from libvirt: internal error: process exited while connecting to monitor: qemu-kvm: -blockdev {"node-name":"libvirt-4-format","read-only":true,"cache":{"direct":false,"no-flush":true},"driver":"qcow2","file":"libvirt-4-storage","backing":null}: Failed to get shared "write" lock
Is another process using the image [/var/lib/libvirt/images/db01.qcow2]? [code=1 int1=-1]

运行中的 qemu 进程会对 qcow2 文件持有写锁,而 libguestfs 拒绝与之争抢,因为两个写入方修改同一镜像可能严重破坏虚拟机。先执行 virsh shutdown db01 关机,等待 virsh list 中的状态显示为“shut off”,再重新运行命令。我们第一次针对运行中的虚拟机执行时就遇到了这个问题,因此最好尽早养成习惯:libguestfs 文件工具只读取离线镜像或已关机虚拟机的镜像,没有任何参数能让它强行取得锁。

使用 virt-ls 列出虚拟机文件

virt-ls 遍历虚拟机文件系统的方式与 ls 相同。普通输出只显示名称,-l 则增加权限、大小等长格式信息:

sudo virt-ls -l -d db01 /etc/ssh

列表中可以看到宿主机密钥文件和配置,以及它们在虚拟机中的真实所有者:

total 588
drwxr-xr-x  4 root root   4096 Jun  2  2023 .
drwxr-xr-x 67 root root   4096 Nov  9 23:31 ..
-rw-r--r--  1 root root 573928 Feb  8  2023 moduli
-rw-r--r--  1 root root   1650 Feb  8  2023 ssh_config
drwxr-xr-x  2 root root   4096 Feb  8  2023 ssh_config.d
-rw-r--r--  1 root root   3223 Feb  8  2023 sshd_config
drwxr-xr-x  2 root root   4096 Feb  8  2023 sshd_config.d

-R 会递归列出,适合在记不清配置文件位于哪个目录时进行搜索:

sudo virt-ls -R -d db01 /etc/apt

递归输出每行一个路径,可以直接交给 grep 或 while 循环:

/apt.conf
/apt.conf.d
/apt.conf.d/00trustcdrom
/apt.conf.d/01autoremove
/apt.conf.d/20listchanges
/apt.conf.d/70debconf
/auth.conf.d
/keyrings
/listchanges.conf
/listchanges.conf.d

测试虚拟机的递归结果如下,可直接送入循环处理:

virt-ls 列出离线 db01 镜像中的 /etc/ssh,并递归查看 /etc/apt

当关注大小而不是精确字节数时,把 -h 与 -l 一起使用;排查文件增长问题时,人类可读的大小更容易比较。借助 virt-ls 查找文件、再用 virt-cat 读取文件,大部分“文件在哪里、内容是什么”的问题都能从宿主机解决,也不会为了读取一个配置而反复启动故障虚拟机三次。

使用 virt-edit 编辑虚拟机中的文件

virt-edit 会直接在镜像中原地修改文件。除文件路径外不传其他参数时,它会打开编辑器,行为与 vim 类似。处理故障虚拟机时,我们最常用的是非交互模式:-e 接受 Perl 替换表达式,因此一行修复也能写成脚本化命令。下面的命令从宿主机侧关闭 SSH 密码认证:

sudo virt-edit -d db01 -e 's/^#PasswordAuthentication yes/PasswordAuthentication no/' -b .bak /etc/ssh/sshd_config

-b 接受一个扩展名,并在镜像内保留原文件为 sshd_config.bak。它曾多次把我们从不正确的替换表达式里救回来,而且添加它的成本很低。文件路径必须放在最后,因为 -b 会把下一个单词当作扩展名;按照命令语法说明,把文件路径保留为最后一个参数。之后用 virt-cat 回读文件,确认修改已经生效:

sudo virt-cat -d db01 /etc/ssh/sshd_config | grep -i passwordauth

替换成功,注释掉的原始内容保持不变:

PasswordAuthentication no
# PasswordAuthentication.  Depending on your PAM configuration,
# PAM authentication, then enable this but set PasswordAuthentication

修改和验证都针对离线镜像执行:

virt-edit 在离线 db01 镜像中替换 sshd_config,然后用 virt-cat 验证

需要精准的小范围修复时应使用 virt-edit,因为能在命令历史中审阅的脚本化替换,比必须全程盯着的救援启动更可靠。对于结构性变更,例如无论怎样修补都无法启动的虚拟机网络配置,从 PXE 或 ISO 源重新构建虚拟机通常更干净。

使用 virt-df 检查虚拟机磁盘使用量

virt-df 是宿主机上所有虚拟机的 df。不带参数运行时会遍历全部已定义域,并打印每个虚拟机的文件系统表:

sudo virt-df -h

每行对应虚拟机内的一个文件系统,前面带有虚拟机名称,因此磁盘满时能立刻看出属于哪个虚拟机:

Filesystem                                Size       Used  Available  Use%
db01:/dev/sda1                            5.8G       1.2G       4.3G   21%

关注 inode 而不是数据块时,把 -h 换成 -i。邮件或容器主机可能在 df 仍显示大量空闲空间时耗尽 inode,而虚拟机自身的日志不会说明原因,因此从宿主机同时检查两者可以省下一次启动。如果只检查一个镜像文件而不是所有虚拟机,可以用 -a 传入路径:

sudo virt-df -h -a /var/lib/libvirt/images/db01.qcow2

两次针对测试虚拟机的运行如下:先显示完整表格,再检查单个镜像:

virt-df 报告 db01 文件系统使用量,并通过 -a 直接检查其磁盘镜像

从故障主机取出的镜像也能使用这种方式,因此可以把 qcow2 复制到正常机器上直接得到答案,而不必复活原主机。这是回答“它宕机时磁盘是否已满”最快的方法,而几乎所有事后分析都会首先问这个问题。

使用 virt-clone 克隆虚拟机

virt-clone 复制已定义的虚拟机,并修复复制后可能冲突的宿主机侧标识:域名、MAC 地址和 NVRAM 文件。它只能复制关机状态的虚拟机,因此请先关闭源虚拟机:

sudo virsh shutdown db01
sudo virt-clone --original db01 --name db02 --auto-clone

使用 --auto-clone 时,它会在原磁盘旁自动生成新磁盘名称,并在复制过程中打印路径:

Allocating 'db02.qcow2'                                     | 6.0 GB  00:30

Clone 'db02' created successfully.

如果希望把副本放到指定位置,就省略 --auto-clone 并自行传入路径:

sudo virt-clone --original db01 --name db02 --file /var/lib/libvirt/images/db02.qcow2

克隆出来的虚拟机能启动,但仍然沿用源虚拟机的主机名、machine ID 和 SSH 主机密钥。这些冲突造成的问题往往很难追踪:DHCP 可能给两台机器相同的保留地址,SSH 会警告主机密钥改变,任何依赖 machine ID 的功能都可能异常。请在首次启动前,趁镜像仍关机时对克隆执行 virt-sysprep 清除这些标识。默认操作集合范围很广,因此这里明确指定三个身份重置项;注意 user-account 会从克隆中删除所有非 root 用户及其主目录。如果要做模板镜像,这正是需要的效果;如果克隆应保留登录账户,就跳过该项:

sudo virt-sysprep --domain db02 --hostname db02 --operation machine-id,ssh-hostkeys,user-account

它会在执行每个重置操作时打印信息:

[   0.0] Examining the guest ...
[ 157.0] Performing "machine-id" ...
[ 157.4] Performing "ssh-hostkeys" ...
[ 157.7] Performing "user-account" ...

完成之后,克隆就是一台真正独立的机器。用 virsh list --all 列出两台虚拟机,应看到这一对:

 Id   Name   State
-----------------------
 -    db01   shut off
 -    db02   shut off

我们的克隆操作从磁盘复制开始,经过 sysprep 重置,最终得到 virsh list 的输出:

在 Rocky Linux 10 主机上将 db01 克隆为 db02,随后执行 virt-sysprep,并通过 virsh list 显示两台虚拟机均已关机

对于不是通过克隆创建、而是需要从零构建的虚拟机,virt-builder 可以从在线模板库生成全新镜像,带 Kickstart 文件的 virt-install 则能自动化完整安装。

哪个工具处理哪种任务

这 6 个工具会一起安装,并读取同一份 libvirt 清单,因此唯一要判断的是当前问题适合哪个工具:

工具 任务 所需虚拟机状态
virt-top 实时查看每个域的 CPU、内存、磁盘和网络 任意状态,运行中最佳
virt-cat 从镜像打印文件 关机
virt-ls 浏览镜像目录树 关机
virt-edit 修复或脚本化修改单个文件 关机
virt-df 查看所有虚拟机的文件系统使用量 关机
virt-clone 复制虚拟机并生成新的身份字段 源虚拟机关机

把 libguestfs 文件工具用于离线操作,把 virt-top 用于实时观察,大多数虚拟机问题都能只在宿主机上解决;当问题虚拟机无法启动时,这正是最需要的能力。virsh 命令速查表涵盖与这些工具配合使用的生命周期命令,而当虚拟机本身需要运行 KVM 时,还需要处理嵌套虚拟化。

libguestfs 官方文档列出了完整工具集,包括用于交互会话的 guestfish 和用于救援 Shell 的 virt-rescue。熟练掌握上述 6 个工具后,这两个也值得学习,因为它们能处理文件系统级清理、启动顺序修复等单一用途工具无法覆盖的罕见任务。

Avatar photo

关于 木子

Email: muzi@vip.rockylinux.cn 微信:VebinLee QQ: 2306867585
Founder of the Rocky Linux Chinese community, MVP、VMware vExpert、TVP, advocate for cloud native technologies, with over ten years of experience in site reliability engineering (SRE) and the DevOps field. Passionate about Cloud Computing、Microservices、CI&CD、DevOps、Kubernetes, currently dedicated to promoting and implementing Rocky Linux in Chinese-speaking regions.
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇