故障现象

使用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

rbd无法map(rbd feature disable)

记一次虚拟机无法挂载volume的怪异问题排查的更多相关文章

  1. nova挂载volume源码分析

    当nova volume-attach instance_uuid volume_uuid 执行后,主要流程如下: 使用的存储类型是lvm+iscis 1.nova client解析该命令行,通过re ...

  2. docker挂载volume的用户权限问题,理解docker容器的uid

    docker挂载volume的用户权限问题,理解docker容器的uid 在刚开始使用docker volume挂载数据卷的时候,经常出现没有权限的问题. 这里通过遇到的问题来理解docker容器用户 ...

  3. win10专业版Hyper-v下Docker挂载volume的方式使用Gitlab(汉化版)保存资料数据(使用外部redis)

    目录 话题 (191) 笔记 (137) 资料区 (2) 评价 (33) 介绍 讨论区 话题 win10专业版Hyper-v下Docker挂载volume的方式使用Gitlab(汉化版)保存资料数据( ...

  4. 解Bug之路-记一次线上请求偶尔变慢的排查

    解Bug之路-记一次线上请求偶尔变慢的排查 前言 最近解决了个比较棘手的问题,由于排查过程挺有意思,于是就以此为素材写出了本篇文章. Bug现场 这是一个偶发的性能问题.在每天几百万比交易请求中,平均 ...

  5. Java虚拟机性能管理神器 - VisualVM(7) 排查JAVA应用程序线程泄漏【转】

    Java虚拟机性能管理神器 - VisualVM(7) 排查JAVA应用程序线程泄漏[转] 标签: javajvm线程泄漏 2015-03-11 19:47 1098人阅读 评论(0) 收藏 举报   ...

  6. Java虚拟机性能管理神器 - VisualVM(6) 排查JAVA应用程序内存泄漏【转】

    Java虚拟机性能管理神器 - VisualVM(6) 排查JAVA应用程序内存泄漏[转] 标签: javajvm内存泄漏监控工具 2015-03-11 18:30 1870人阅读 评论(0) 收藏  ...

  7. Java虚拟机性能管理神器 - VisualVM(9) 排查JAVA应用程序线程死锁【转】

    Java虚拟机性能管理神器 - VisualVM(9) 排查JAVA应用程序线程死锁[转] 标签: javajvm监控工具性能优化 2015-03-11 19:59 1948人阅读 评论(0) 收藏  ...

  8. Linux如何在虚拟机中挂载iso yum源

    首先,将作为源的iso的挂载到系统上. 代码如下: mount -o loop /dev/cdrom /mnt/iso/ 或者 mount -o loop /xxx/xxx.iso /mnt/iso/ ...

  9. 怎样在VirtualBox 虚拟机中挂载共享目录

    啊.好长时间没写博客了.近期有点忙~~ 不得不说 VirtualBox 对于一些不想装非常多个系统又非常想实验新系统的人来说确实是神器: 哈哈.个人还是比較爱玩这些个各种各样的Linux 发型版的,可 ...

随机推荐

  1. I/O操做总结(四))

    前面已经把java io的主要操作讲完了 这一节我们来说说关于java io的其他内容 Serializable序列化 实例1:对象的序列化 1 2 3 4 5 6 7 8 9 10 11 12 13 ...

  2. Mac、Linux下两个Emacs共享一个配置文件

    Mac.Linux下两个Emacs共享一个配置文件 有些嵌入式的实验需要在Linux进行,就安装了RHEL6.4的虚拟机,下载并编译了Emacs. 在Linux的.emacs文件中加入以下语句,即可引 ...

  3. 解决Chrome浏览器自动记录用户名和密码的黄色背景问题和该解决方法与tab切换至下一个input冲突的问题。

    哈哈哈,是不是标题很长呀,不逗你们了.其实这么长的标题主要就说了两件事: 第一件:解决Chrome浏览器自动记录用户名和密码的黄色背景问题. 第二件:输入完用户名后按下tab键切换至下一个输入密码in ...

  4. 关于学习Lisp的一点思考

    以前读<黑客与画家>,其中对Lisp语言的赞美和推崇,让我燃起学习Lisp语言的强烈冲动,但很快发现在实际工作中应用的场景很少,出于功利心最终放弃了.直到上周未在家里读完了<大教堂与 ...

  5. 如何变更站点 AD 域服务器IP地址

    在 winserver 2012  单森林单域,多站点环境中,想把某一个站点AD 域服务器IP地址更改,要如何操作,才能保证客户端正常运行,不影响客户端的运行.有些朋友也经常提出类似问题. 想在不影响 ...

  6. [Eclipse] - 解决"Java was started but returned exit code = 13"问题

    最近遇到一个问题,打开Eclipse时会弹出如下对话框 在网上查找了相关资料后结合自己的问题,总结如下. 导致问题的原因: 1. 通常的原因是安装的Eclipse的版本或者Java JDK的版本不匹配 ...

  7. POJ 1185 炮兵阵地 (状压DP,轮廓线DP)

    题意: 给一个n*m的矩阵,每个格子中有'P'或者'H',分别表示平地和高原,平地可以摆放大炮,而大炮的攻击范围在4个方向都是2格(除了自身位置),攻击范围内不能有其他炮,问最多能放多少个炮?(n&l ...

  8. HDU 2639 Bone Collector II (01背包,第k解)

    题意: 数据是常规的01背包,但是求的不是最大容量限制下的最佳解,而是第k佳解. 思路: 有两种解法: 1)网上普遍用的O(V*K*N). 2)先用常规01背包的方法求出背包容量限制下能装的最大价值m ...

  9. 卓越管理的实践技巧(1)如何进行有效的指导 Guidelines for Effective Coaching

    Guidelines for Effective Coaching 前文卓越管理的秘密(Behind Closed Doors)最后一部分提到了总结的13条卓越管理的实践技巧并列出了所有实践技巧名称的 ...

  10. UVA11019 Matrix Matcher (AC自动机)

    二维的矩阵匹配,把模式矩阵按列拆开构造AC自动机,记录行号(为了缩点判断). 把T矩阵按行匹配,一旦匹配成功,在假想的子矩阵左上角位置加一.最后统计总数. 因为所有模式串长度一样,不用维护last数组 ...