记一次虚拟机无法挂载volume的怪异问题排查
故障现象
使用nova volume-attach <server> <volume>命令挂载卷,命令没有返回错误,但是查看虚拟机状态,卷并没有挂载上。
故障原因
疑似虚拟机长时间运行(超过1年)后,libvirt无法执行live attach操作。
处理方法
将虚拟机关机,在关机状态下挂载卷,然后启动虚拟机。
排查过程
由于没有nova命令没有报错,基本确定问题出在计算节点,直接到计算节点查看日志,发现如下异常:
2018-06-05 13:40:32.337 160589 DEBUG nova.virt.libvirt.config [req-392fd85e-1853-4c6c-8248-310ca6289895 d31b768e1dbf4a0dbf2571234b4e2f5a 65ea11db9ebf49c69d
3c05bc38925617 - - -] Generated XML ('<disk type="network" device="disk">\n <driver name="qemu" type="raw" cache="none"/>\n <source protocol="rbd" name="volumes/volume-433ad82b-4d8d-4d5c-b1c0-d0c88e0c397b">\n <host name="10.212.11.15" port="6789"/>\n <host name="10.212.13.30" port="6789"/>\n <host name="10.212.14.30" port="6789"/>\n </source>\n <auth username="cinder">\n <secret type="ceph" uuid="90b0641c-a0d1-4103-ad8c-d580dd7da953"/>\n </auth>\n <target bus="virtio" dev="vdc"/>\n <serial>433ad82b-4d8d-4d5c-b1c0-d0c88e0c397b</serial>\n</disk>\n',) to_xml /usr/lib/python2.7/site-packages/nova/virt/libvirt/config.py:82
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [req-392fd85e-1853-4c6c-8248-310ca6289895 d31b768e1dbf4a0dbf2571234b4e2f5a 65ea11db9ebf49c69d
3c05bc38925617 - - -] [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] Failed to attach volume at mountpoint: /dev/vdc
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] Traceback (most recent call last):
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] File "/usr/lib/python2.7/site-packages/nova/virt/libvirt/driver.py", line 1121, in attach_volume
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] guest.attach_device(conf, persistent=True, live=live)
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] File "/usr/lib/python2.7/site-packages/nova/virt/libvirt/guest.py", line 235, in attach_device
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] self._domain.attachDeviceFlags(conf.to_xml(), flags=flags)
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] File "/usr/lib/python2.7/site-packages/eventlet/tpool.py", line 183, in doit
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] result = proxy_call(self._autowrap, f, *args, **kwargs)
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] File "/usr/lib/python2.7/site-packages/eventlet/tpool.py", line 141, in proxy_call
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] rv = execute(f, *args, **kwargs)
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] File "/usr/lib/python2.7/site-packages/eventlet/tpool.py", line 122, in execute
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] six.reraise(c, e, tb)
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] File "/usr/lib/python2.7/site-packages/eventlet/tpool.py", line 80, in tworker
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] rv = meth(*args, **kwargs)
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] File "/usr/lib64/python2.7/site-packages/libvirt.py", line 554, in attachDeviceFlags
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] if ret == -1: raise libvirtError ('virDomainAttachDeviceFlags() failed', dom=self)
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced] libvirtError: internal error: unable to execute QEMU command '__com.redhat_drive_add': Device 'drive-virtio-disk2' could not be initialized
2018-06-05 13:40:32.386 160589 ERROR nova.virt.libvirt.driver [instance: 211437a1-e4c4-40e0-ade1-b167d6251ced]
volume保存在Ceph中,从日志看到生成的xml配置文件中volume的信息没有问题,在调用libvirt接口挂载时报了一条libvirtError: internal error: unable to execute QEMU command '__com.redhat_drive_add': Device 'drive-virtio-disk2' could not be initialized的错误。
查看qemu日志/var/log/libvirt/qemu/instance-0000017b.log,发现这样的信息:
2018-06-05T13:40:34.471447Z error reading header from volume-433ad82b-4d8d-4d5c-b1c0-d0c88e0c397b
似乎是不能正常识别Ceph中的rbd。于是把Ceph client的debug日志打开,在计算节点的/etc/ceph/ceph.conf中添加如下配置:
[client]
debug rbd = 20
log file = /var/log/ceph-client.log
其中/var/log/ceph-client.log需要是libvirt用户可写的。
再次执行nova volume-attach命令,查看Ceph日志:
2018-06-05 13:40:32.349046 7f99f5355c80 20 librbd: open_image: ictx = 0x7f99f785bc00 name = 'volume-433ad82b-4d8d-4d5c-b1c0-d0c88e0c397b' id = '' snap_name
= ''
2018-06-05 13:40:32.353777 7f99f5355c80 20 librbd: detect format of volume-433ad82b-4d8d-4d5c-b1c0-d0c88e0c397b : new
2018-06-05 13:40:32.362089 7f99f5355c80 10 librbd::ImageCtx: init_layout stripe_unit 4194304 stripe_count 1 object_size 4194304 prefix rbd_data.85160113150
e34 format rbd_data.85160113150e34.%016llx
2018-06-05 13:40:32.375950 7f99f5355c80 20 librbd: ictx_refresh 0x7f99f785bc00
2018-06-05 13:40:32.377678 7f99f5355c80 -1 librbd: Image uses unsupported features: 60
2018-06-05 13:40:32.377685 7f99f5355c80 20 librbd: close_image 0x7f99f785bc00
2018-06-05 13:40:32.377688 7f99f5355c80 20 librbd: flush 0x7f99f785bc00
2018-06-05 13:40:32.377690 7f99f5355c80 20 librbd: ictx_check 0x7f99f785bc00
注意报错Image uses unsupported features: 60。
Ceph rbd支持的features:
- layering: layering support,numeric value: 1
- striping: striping v2 support,numeric value: 2
- exclusive-lock: exclusive locking support,numeric value: 4
- object-map: object map support (requires exclusive-lock) ,numeric value: 8
- fast-diff: fast diff calculations (requires object-map) ,numeric value: 16
- deep-flatten: snapshot flatten support ,numeric value: 32
- journaling: journaled IO support (requires exclusive-lock) ,numeric value: 64
所以报错中的60代表的就是:
60 = 32+16+8+4 = exclusive-lock, object-map, fast-diff, deep-flatten
这些feature是format 2格式的rbd中默认开启的,而计算节点上的librbd表示不支持这些feature,官方的说法是在3.11版本以上的kernel才支持。
可以在cinder-volume节点的ceph配置文件中,设置rbd_default_features = 1,这样就只启用layering属性。对于已经创建的rbd,使用下面的命令关闭不支持的feature:
# rbd feature disable volumes/volume-433ad82b-4d8d-4d5c-b1c0-d0c88e0c397b exclusive-lock object-map fast-diff deep-flatten
经测试,关闭这些feature后,volume确实可以挂载上了。
但是实际上还是存在问题。因为之前挂载卷的时候没有出现过这种错误,查看已经挂载到虚拟机上的volume,它们的这些feature都是开启的。
在同一个计算节点上的虚拟机测试挂载同一个卷,发现有些虚拟机能挂载上,而有些则会出现上面的报错。这些报错的虚拟机存在这些共性:
1. 使用的镜像是其他虚拟机的snapshot,且镜像已经被删除
2. 使用的flavor包含交换分区,且flavor已经被删除
3. 运行时间在1年以上
从第1点和第2点看出使用极不规范,因为是老集群,其他同事的坑,只能默默接过。还好OpenStack数据库的删除都是软删除,手动修改数据库,将删除的flavor记录恢复。但是镜像就比较坑了,因为这不仅仅是数据库中的一条记录,还包括保存在文件系统中的镜像实体,这个是无法恢复的。只能通过从计算节点拷贝缓存的镜像还原。
查看计算节点上使用这个镜像的虚拟机:
# qemu-img info /var/lib/nova/instances/211437a1-e4c4-40e0-ade1-b167d6251ced/disk
image: /var/lib/nova/instances/211437a1-e4c4-40e0-ade1-b167d6251ced/disk
file format: qcow2
virtual size: 60G ( bytes)
disk size: 37G
cluster_size:
backing file: /var/lib/nova/instances/_base/141ce390743531b7da2db335d2159fa550f460c8
Format specific information:
compat: 1.1
lazy refcounts: false
refcount bits:
corrupt: false
可以看到它的backing file,这个就是转成raw格式的镜像。将它转换成qcow2格式:
# cd /var/lib/nova/instances/_base
# qemu-img convert -f raw -O qcow2 141ce390743531b7da2db335d2159fa550f460c8 141ce390743531b7da2db335d2159fa550f460c8.qcow2
然后将这个qcow2格式的镜像复制到glance节点保存镜像的目录,重命名为镜像的UUID。最后还要修改数据库中的记录:
MariaDB [glance]> update images set status='active', deleted_at=NULL,deleted=,is_public=,checksum='0a5a3e84558e8470946acb86a839dc02' where id='b3986e99-1988-43bb-b47c-0b34438bc189';
注意要更新镜像的checksum,这个值使用md5sum IMAGE_FILE命令获取:
# md5sum /mfsclient/ucscontroller/glance/images/b3986e99--43bb-b47c-0b34438bc189
0a5a3e84558e8470946acb86a839dc02 /mfsclient/ucscontroller/glance/images/b3986e99--43bb-b47c-0b34438bc189
另外发现glance保存镜像的目录也是修改过的,需要更新image_locations表:
MariaDB [glance]> update image_locations set value='file:///mfsclient/ucscontroller/glance/images/b3986e99-1988-43bb-b47c-0b34438bc189',deleted_at=NULL,deleted=,status='active' where image_id='b3986e99-1988-43bb-b47c-0b34438bc189';
对于一个正常上传的镜像,这样做就算恢复完成了。但这个镜像是一个虚拟机的snapshot,所以其实是没有办法复原的,这样做只是得到了一个UUID和旧镜像相同的一个新镜像。
使用恢复的flavor和image创建一个虚拟机,然后挂载之前使用的测试卷,没有报错,可以正常挂载。由于镜像不是完全复原的,不能排除镜像的问题,flavor是可以确定没有问题的。这样一来只剩下第3点了,是不是虚拟机运行太久导致的?
回顾nova-compute的报错日志,是在调用libvirt的attachDeviceFlags时出错。这里传入了一个flags参数。具体调用的代码在/usr/lib/python2.7/site-packages/nova/virt/libvirt/guest.py:
class Guest(object):
...
def attach_device(self, conf, persistent=False, live=False):
"""Attaches device to the guest. :param conf: A LibvirtConfigObject of the device to attach
:param persistent: A bool to indicate whether the change is
persistent or not
:param live: A bool to indicate whether it affect the guest
in running state
"""
flags = persistent and libvirt.VIR_DOMAIN_AFFECT_CONFIG or 0
flags |= live and libvirt.VIR_DOMAIN_AFFECT_LIVE or 0
self._domain.attachDeviceFlags(conf.to_xml(), flags=flags)
flags由上一级传入的persistent和live参数决定, /usr/lib/python2.7/site-packages/nova/virt/libvirt/driver.py:
class LibvirtDriver(driver.ComputeDriver):
...
def attach_volume(self, context, connection_info, instance, mountpoint,
disk_bus=None, device_type=None, encryption=None):
...
try:
state = guest.get_power_state(self._host)
live = state in (power_state.RUNNING, power_state.PAUSED) if encryption:
encryptor = self._get_volume_encryptor(connection_info,
encryption)
encryptor.attach_volume(context, **encryption) guest.attach_device(conf, persistent=True, live=live)
except Exception as ex:
LOG.exception(_LE('Failed to attach volume at mountpoint: %s'),
mountpoint, instance=instance)
if isinstance(ex, libvirt.libvirtError):
errcode = ex.get_error_code()
if errcode == libvirt.VIR_ERR_OPERATION_FAILED:
self._disconnect_volume(connection_info, disk_dev)
raise exception.DeviceIsBusy(device=disk_dev) with excutils.save_and_reraise_exception():
self._disconnect_volume(connection_info, disk_dev)
persistent硬编码为True,live由虚拟机状态决定,如果是RUNNING或者PAUSED,live为True,否则为False。我们是在为运行中的虚拟机挂载卷,live为True。
可知libvirt对关闭和运行的虚拟机挂载卷时操作不一样,是不是因为虚拟机运行久了,libvirt不能正常执行live状态下的挂载操作了呢。最简单的方法就是重启一下虚拟机再挂载。
将虚拟机关机,在关机状态下挂载卷,然后启动虚拟机,在虚拟机上可以看到挂载的块设备。没有继续深究libvirt内部的挂载逻辑。
参考资料
Need better documentation to describe RBD image features
记一次虚拟机无法挂载volume的怪异问题排查的更多相关文章
- nova挂载volume源码分析
当nova volume-attach instance_uuid volume_uuid 执行后,主要流程如下: 使用的存储类型是lvm+iscis 1.nova client解析该命令行,通过re ...
- docker挂载volume的用户权限问题,理解docker容器的uid
docker挂载volume的用户权限问题,理解docker容器的uid 在刚开始使用docker volume挂载数据卷的时候,经常出现没有权限的问题. 这里通过遇到的问题来理解docker容器用户 ...
- win10专业版Hyper-v下Docker挂载volume的方式使用Gitlab(汉化版)保存资料数据(使用外部redis)
目录 话题 (191) 笔记 (137) 资料区 (2) 评价 (33) 介绍 讨论区 话题 win10专业版Hyper-v下Docker挂载volume的方式使用Gitlab(汉化版)保存资料数据( ...
- 解Bug之路-记一次线上请求偶尔变慢的排查
解Bug之路-记一次线上请求偶尔变慢的排查 前言 最近解决了个比较棘手的问题,由于排查过程挺有意思,于是就以此为素材写出了本篇文章. Bug现场 这是一个偶发的性能问题.在每天几百万比交易请求中,平均 ...
- Java虚拟机性能管理神器 - VisualVM(7) 排查JAVA应用程序线程泄漏【转】
Java虚拟机性能管理神器 - VisualVM(7) 排查JAVA应用程序线程泄漏[转] 标签: javajvm线程泄漏 2015-03-11 19:47 1098人阅读 评论(0) 收藏 举报 ...
- Java虚拟机性能管理神器 - VisualVM(6) 排查JAVA应用程序内存泄漏【转】
Java虚拟机性能管理神器 - VisualVM(6) 排查JAVA应用程序内存泄漏[转] 标签: javajvm内存泄漏监控工具 2015-03-11 18:30 1870人阅读 评论(0) 收藏 ...
- Java虚拟机性能管理神器 - VisualVM(9) 排查JAVA应用程序线程死锁【转】
Java虚拟机性能管理神器 - VisualVM(9) 排查JAVA应用程序线程死锁[转] 标签: javajvm监控工具性能优化 2015-03-11 19:59 1948人阅读 评论(0) 收藏 ...
- Linux如何在虚拟机中挂载iso yum源
首先,将作为源的iso的挂载到系统上. 代码如下: mount -o loop /dev/cdrom /mnt/iso/ 或者 mount -o loop /xxx/xxx.iso /mnt/iso/ ...
- 怎样在VirtualBox 虚拟机中挂载共享目录
啊.好长时间没写博客了.近期有点忙~~ 不得不说 VirtualBox 对于一些不想装非常多个系统又非常想实验新系统的人来说确实是神器: 哈哈.个人还是比較爱玩这些个各种各样的Linux 发型版的,可 ...
随机推荐
- SmartWeatherAPI C#版
private string GetKey(string areaId, string type, string date, string appId, string privateKey) { va ...
- 《javascript设计模式》笔记之第九章:组合模式
之前一直都是按照书的结构顺序做总结,觉得好像不是很好,现在试着完全按照自己的理解做总结.例子还是书上的例子. 一:组合模式的作用: 在web开发中,主要用于创建嵌套的html结点,使得我们方便的把各种 ...
- Java命令行实用工具jps和jstat 专题
在Linux或其他UNIX和类UNIX环境下,ps命令想必大家都不陌生,我相信也有不少同学写过 ps aux | grep java | grep -v grep | awk '{print $2}' ...
- Electron 入门文档
https://www.kancloud.cn/wizardforcel/electron-doc/137765 https://segmentfault.com/a/1190000006207600 ...
- Nginx FastCGI PHP
We can see this comment in nginx.conf. # pass the PHP scripts to FastCGI server listening on 127.0.0 ...
- 数据分析R&Python-Rpy2包环境配置
Rpy2环境配置 最近想将R整合到以flask为后端框架的web系统中,在服务器端做数据统计分析.需要将R语言整合到Python中,发现Python中的Rpy2可以调用R语言,所以花了一些时间配置了一 ...
- Windows UEFI 安装策略的一个细节
在计算机已连接任何带Windows Boot Manager的硬盘的时候,系统自己不会创建EFI分区,而是用之前的
- 手写IOC框架
1.IOC框架的设计思路 ① 哪些类需要我们的容器进行管理 ②完成对象的别名和对应实例的映射装配 ③完成运行期对象所需要的依赖对象的依赖
- GIT分布式版本控制器的前后今生
Git的入门与安装 GIT基础操作 GIT的分支应用 GITLAB应用 gitlab与pycharm应用 GITHUB使用
- 原型模式 -- JavaScript语言的灵魂
原型模式就是将原型对象指向创建对象的类,使这些类共享原型对象的方法与属性.JS是基于原型链实现对象之间的继承,是对属性或者方法的共享,而不是对属性和方法的复制. // 图片轮播类 var LoopIm ...