Keep learning, keep living...

0%

VMware Guest虚拟机失去响应的排查方法

在一些业务环境的VMware Guest虚拟机上安装我们的内核模块后,偶尔虚拟机会变成无响应的状态。重启后登录系统查看,处于无响应状态的那段时间在/var/log/messages中却没有任何信息,完全没有分析问题原因的头绪。

经过调研,找到两种方法可以帮助排查定位这类系统失去响应的问题,分别是:

  • 发送NMI: Non-Maskable Interupt给虚拟机
  • VMware内存快照

发送NMI给虚拟机

NMI是不可屏蔽的硬件中断。在虚拟化环境中,Hypervisor可以向Guest虚拟机发送NMI中断。Guest虚拟机收到NMI后产生dump文件, 继而从dump文件中分析系统状态。

只是Linux系统对于NMI中断的默认处理行为是发送到stdout,并不会panic并产生dump文件。为了在接收到NMI时产生dump文件,我们需要在GuestLinux系统中完成这些配置:

  • 安装kexec-tools, 并启动kdump服务:

    1
    systemctl start kdump.service
  • 配置sysctl参数,令Linux系统接收到NMIpanic:

    1
    2
    sysctl -w kernel.panic_on_unrecovered_nmi=1
    sysctl -w kernel.unknown_nmi_panic=1

VCenterGUI界面中, 可以在相应Guest虚拟机的导出系统日志操作中向虚拟机发送NMI, 如图:

这种方式对VCenter登录帐号的管理权限有所要求。

在相应的ESXi主机上也可以通过命令行向虚拟机发送NMI:

1
vm-support -a HungVM:Send_NMI_To_Guest --vm=/vmfs/volumes/Path/of/VMname.vmx

可以参考官方KB:

如果是RHEVoVirt环境, 可以使用virsh命令发送NMI:

1
virsh inject-nmi guest1

具体可以参考链接:

内存快照

另外一种方法就是基于VMware的快照。VMware官方提供了一个工具可以将快照文件转换成crash工具可以读取的dump文件。

工具使用说明:

工具下载地址:

但经过尝试,发现转换完成的dump文件使用crash并不能正常读取。

Redhat这篇KB上描述的错误一致:

crash无法读取的根本原因是从7.5版本开始,RHEL内核默认启用了KASLR特性:

1
2
3
4
5
Starting 7.5, RHEL kernels feature KASLR (Kernel Address Space Linear Randomization) enabled by default. KASLR is a security feature that enables the kernel to relocate itself to a random location on each boot, making writing exploits that depend on local resources significantly harder.

The side effect of this feature is debugging tools like crash may encounter some trouble trying to open vmcores from KASLR-enabled kernels.

For more information about this, please refer to this article.

可以参考这里:

但它也提到,crash可以直接读取VMware的快照文件,步骤如下:

  • 复制ESXi主机上Guest所在目录下的.vmss/.vmsn.vmem文件到一个目录
  • 保持文件名称不变
  • 使用crash工具打开.vmsn/.vmss文件,crash会自动加载相应的.vmem文件

如:

1
# crash <NAME>.vmsn  /cores/retrace/repos/kernel/x86_64/usr/lib/debug/lib/modules/<kernel version>/vmlinux

不过在生成快照时,需要注意勾选包括虚拟机的内存:

有时侯系统可能会连NMI也无法响应,这种场景下就只能使用快照方式。但快照方式本身需要从ESXi主机上获取快照文件,也不是很方便。总之各有利弊,看情况选择使用哪种方法。

因为使用crash工具分析dump文件,需要对应内核版本的debuginfo包。有时我们拿到dump文件,却不知道内核版本。我们可以从dump文件中直接查找字符串来搜索, 如:

1
2
3
4
5
[root@localhost centos76-Snapshot1]# strings vmss.core  |grep -i 'BOOT_IMAGE'
BOOT_IMAGE=/vmlinuz-3.10.0-957.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=en_US.UTF-8
$(cat /proc/cmdline| grep "BOOT_IMAGE" | cut -d' ' -f1)
KDUMP_BOOTDIR="/boot"$(dirname $BOOT_IMAGE)
BOOT_IMAGE

参考: