|
感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正!
如有转载,请保留源作者博客信息。
Better
Me的博客:blog.iyunv.com/tantexian
如需交流,欢迎大家博客留言。
声明:本文记录的都是一些开发调试的过程,由于时间关系没有整理成文。
附上报错信息:
附上代码:判断冷迁移还是热迁移逻辑:
if live and not rebuild and not flavor:
self._live_migrate(context, instance, scheduler_hint,
block_migration, disk_over_commit)
elif not live and not rebuild and flavor:
instance_uuid = instance['uuid']
with compute_utils.EventReporter(context, self.db,
'cold_migrate', instance_uuid):
self._cold_migrate(context, instance, flavor,
scheduler_hint['filter_properties'],
reservations)
conductor调用conpute的代码:
virsh -c qemu+tcp://node32/system
http://www.chenyudong.com/archives/libvirt-connect-to-libvirtd-with-tcp-qemu.html
virsh使用qemu+tcp访问远程libvirtd
http://libvirt.org/remote.html#Remote_libvirtd_configuration
官网配置:http://docs.ceph.com/docs/giant/rbd/rbd-openstack/
拿fule代码直接替换:
注:在测试过程中,假若没有成功,下次则会提示目录已经存在,则再目的迁移地址将
/var/lib/nova/instances下面相应文件夹删除掉
ntpdate 192.168.18.85
openvswich开启:/etc/init.d/openvswitch restart
配置libvirt的监听端口:
修改文件
vim /usr/local/libvirt/etc/sysconfig/libvirtd
用来启用tcp的端口(本环境中由于libvirt升级过,配置文件目录不一致,默认为/etc/sysconfig/libvirtd)
1
2
3
LIBVIRTD_CONFIG=/usr/local/libvirt/etc/libvirt/libvirtd.conf
LIBVIRTD_ARGS="--listen"
修改文件
vim /usr/local/libvirt/etc/libvirt/libvirtd.conf
1
2
3
4
5
6
7
8
9
listen_tls = 0
listen_tcp = 1
tcp_port = "16509"
listen_addr = "0.0.0.0"
auth_tcp = "none"
运行 libvirtd
1
service libvirtd restart
报secret错误,则将每个计算节点的uuid设置为一样:
rbd_secret_uuid=c245e1ef-d340-4d02-9dcf-fd091cd1fe47
配置nova。conf
Table 4.6. Description of live migration configuration options
Configuration option = Default value
Description
[DEFAULT]
live_migration_retry_count = 30
(IntOpt) Number of 1 second retries needed in live_migration
[libvirt]
live_migration_bandwidth = 0
(IntOpt) Maximum bandwidth to be used during migration, in Mbps
live_migration_flag = VIR_MIGRATE_UNDEFINE_SOURCE, VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_LIVE, VIR_MIGRATE_TUNNELLED
(StrOpt) Migration flags to be set for live migration
live_migration_uri = qemu+tcp://%s/system
(StrOpt) Migration target URI (any included "%s" is replaced with the migration target hostname)
发现两个key不一致,因此ceph的key配置有问题
重新配置正确的key值,保证所有计算节点key值相同。重新配置后,需要将之前创建的虚拟机删除,重新生成
错误报在migrateToURI函数,打印输出参数:
vim /usr/lib/python2.6/site-packages/nova/virt/libvirt/driver.py
def _live_migration(self, context, instance, dest, post_method,
recover_method, block_migration=False,
migrate_data=None):
"""Do live migration.
:param context: security context
:param instance:
nova.db.sqlalchemy.models.Instance object
instance object that is migrated.
:param dest: destination host
:param post_method:
post operation method.
expected nova.compute.manager.post_live_migration.
:param recover_method:
recovery method when any exception occurs.
expected nova.compute.manager.recover_live_migration.
:param block_migration: if true, do block migration.
:param migrate_data: implementation specific params
"""
# Do live migration.
try:
if block_migration:
flaglist = CONF.libvirt.block_migration_flag.split(',')
else:
flaglist = CONF.libvirt.live_migration_flag.split(',')
flagvals = [getattr(libvirt, x.strip()) for x in flaglist]
logical_sum = reduce(lambda x, y: x | y, flagvals)
dom = self._lookup_by_name(instance["name"])
LOG.error('1-start------------------------------------------')
LOG.error('dom==%s' % dom)
LOG.error('live_migration_uri==%s' % CONF.libvirt.live_migration_uri)
LOG.error('dest==%s' %dest)
LOG.error('logical_sum==%s' % logical_sum)
LOG.error('live_migration_bandwidth==%s' % CONF.libvirt.live_migration_bandwidth)
LOG.error('1-end------------------------------------------')
dom.migrateToURI(CONF.libvirt.live_migration_uri % dest,
logical_sum,
None,
CONF.libvirt.live_migration_bandwidth)
except Exception as e:
with excutils.save_and_reraise_exception():
LOG.error(_("Live Migration failure: %s"), e,
instance=instance)
recover_method(context, instance, dest, block_migration)
查看下虚拟机实例在node31情况:
从上述打印日志可以看出dom值为libvirt.virtDomain对象:
/usr/lib64/python2.6/site-packages/libvirt.py
在能正常迁移的fule节点上面打印上述日志:
再迁移目标主机上建立文件夹:
mkdir /var/lib/nova/instances/022d1291-3967-4363-ab48-fb9713802e42/
libvirt debug模式:
LIBVIRT_DEBUG=1 virsh list --all
调试方法汇总:
http://fedoraproject.org/wiki/Category:Debugging
命令测试:
在node31上面:
virsh -c qemu+tcp://node32/system
http://libvirt.org/migration.html
说到虚拟机的迁移,其实就是数据的转移,数据的转移就涉及数据的传输,数据的传输需要通过网络。libvirt提供了两种方案。
hypervisor native transport:
“本地”数据传输,相当于一种手动方式做的迁移。数据是否可以加密取决于hypervisor自身是否已实现。
libvirt tunnelled transport
隧道化的(tunnelled)数据传输支持很强的加密功能,这要归结于libvirt的RPC协议。不好的一方面是数据会在hypervisor和libvirtd之间的传输。
虚拟机的迁移需要两个主机之间的密切协调,同时应用程序(虚拟机管理平台)也将参与进来,此应用可以是在源主机、目的主机、甚至是第三台主机。
受管理的直接迁移(Managed direct migration):
直接管理迁移,libvirt客户端进程控制迁移的不同阶段。客户端应用程序必须连接以及获得在源主机和目的主机的libvirtd进程的认证。无需两个libvirtd进程间相互通信。如果客户端应用崩溃了,或者在迁移过程中失去了链接,一种办法就是强制终止迁移,重启源主机的guest CPU。
受管理的点对点迁移:(Managed peer to peer migrate)
对于点对点,libvirt客户端程序只是与在源主机的libvirtd进程通信,源主机libvirtd进程自己控制整个迁移的过程,直接连接到目的主机的libvirtd。如果客户端应用崩溃了或者与libvirtd失去连接,迁移过程无需中断直至迁移完成。需要注意的是源主机认证(通常是root)链接到目的主机,而不是通过客户端应用链接到源主机。
不受管理的直接迁移:(Unmanaged direct migrate)
此迁移方式既不受libvirt客户端控制,也不受libvirtd控制,迁移的控制过程委托给基于hypervisor之上的管理服务来处理。libvirt 客户只需要通过hypervisor的管理层做一下初始化。不管是libvirt 客户端还是libvirtd崩溃了,迁移还是会照样进行直至完成。
迁移URI:
虚拟机迁移时,客户端应用程序需要准备的URI可达三个,具体取决于控制流如何选择或者API如何调用。第一个URI就是应用程序到运行着虚拟机的源主机的连接,第二个URI就是目的主机到应用程序之间的连接(在点对点的迁移中,这个连接是来自源主机,而不是客户端应用程序)。第三个URI就是hypervisor指定的用来控制以何种方式迁移的连接。在任何一种受管理的迁移中,前两个URI是必不可少的,第三个是可选的。而在不受管理的直接迁移中,第一个和第三个是必须的,第二个并不会使用。
通常管理应用程序只需关心前两个URI。二者都是普通的libvirt 连接URI格式。libvirt会通过查找目的主机的配置文件中的hostname自动确定hypervisor指定的URI(第三个URI)。
应用程序获取第三个URI时可能会出现的如下几种情况:
1、hostname的配置不正确,或者DNS不正确,如果主机的hostname不能正确的解析到IP地址的化就会生成一个错误的URI,这刚好时文章开头出现的问题。此时需要明确指定IP地址或者使用正确的hostname。
2、主机有多个网络接口,此时需要用IP明确指定来关联某个具体的网卡。
3、防火墙限制端口的使用,当libvirt自动生扯功能的端口需要防火墙对其端口是开放的。
virsh migrate --live --verbose --direct --p2p 5 qemu+tcp://node32/system
virsh migrate source_vm qemu+ssh://ip:port/system --live --storage-all?
http://comments.gmane.org/gmane.comp.emulators.libvirt/93943
vim /usr/local/libvirt/etc/libvirt/qemu.conf
service libvirtd restart
问题木有解决,继续,重新编译libvirt:
./configure --prefix=/usr/local/libvirt/ --with-selinux=no

selinux问题解决了。again:

这次成功了,什么都不改变,后面不能成功了???
重新生成虚拟机测试:
重启libvirt报错:

https://answers.launchpad.net/nova/+question/215994

yum install pm-utils
重启libvirt没有出现错误:



编译升级libvirt到1.2.3:
./configure --with-storage-rbd=yes --with-selinux=no
make && make install
启动virsh list all
error: Failed to connect socket to '/usr/local/var/run/libvirt/libvirt-sock': No such file or directory
ln -s /usr/local/libvirt/var/run/libvirt/libvirt-sock /usr/local/var/run/libvirt/libvirt-sock
[iyunv@node31 ~]# virsh migrate 7 qemu+tcp://node32/system --live --verbose
error: Cannot get interface MTU on 'qbrbc05fd4a-43': No such device
在目标主机上:brctl addbr qbrbc05fd4a-43
[iyunv@node31 86da6dff-d943-4065-889a-4ed281390be9]# virsh migrate 7 qemu+tcp://node32/system --live --verbose
error: Timed out during operation: cannot acquire state change lock

kill掉libvirt重启(两个节点都重启)
virsh migrate 7 qemu+tcp://node32/system --live --verbose --p2p --direct

 

上图中的volume-backed是指的xml等文件也共享呢?但是nfs也是共享了的。。。疑惑ing~~~~



如果是nfs那么/var/lib/nova/instance文件夹是共享的,里面的xml文件也共享,
那么如果是nfs的迁移则不需要迁移xml文件(因为各个节点共享)。
但如果是ceph-backed,则需要将libvirt的xml等文件迁移复制过去。

上述问题通过将vnc_listen设置为0.0.0.0即可以全部节点访问



用1.1.2版本热迁移和快照都成功。(直接无语)
但是有个bug是,迁移完虚拟机后,/var/lib/nova/instance的配置文件继续保存着,
这样就会导致下次再迁移回来时候,则不能继续迁移了。
继续测试:


63compute日志:

找到文件:
/usr/lib/python2.6/site-packages/nova/virt/libvirt/driver.py", line 4255, in check_can_live_migrate_source
https://blueprints.launchpad.net/nova/+spec/live-migration-to-conductor

由上述可知:live_migrate的执行流程为:dashboard->novaclient->nova-api->nova-conductor->nova-compute->virt.libvirt.driver.py.


从上图打印的值,可以看出is_volume_backed:False,似乎有bug,继续跟踪下去。
查看fule对应处的输出:

上述两处的差别在于,fuel代码中传递了image_type==rbd参数。(其实,在nova.conf配置文件中会配置,images_type=rbd项,因此不需要传递参数,自己根据配置文件修改即可。)
原始代码:

修改后代码:

再次实验:


迁移成功。
继续将该虚拟机从63->64:

图2:虚拟机配置文件及相关metedate:

出现上述错误的原因是:
因为迁移走的是rbd,不是共享存储(共享存储不需要拷贝上图2的文件,因此各个node都共享)。rbd的话需要将上图2中的文件拷贝过去。所以每次迁移时候就得先copy该文件夹过去。然后再拷贝内存,然后调用libvirt接口(例如virsh define XXX/libvirt.xml)再目标主机启动虚拟机,迁移即成功。但是有个bug在里面,就是迁移成功后,没有将目标主机的相应文件夹给删除,这样导致再次迁移回来时候报上述错误。
解决办法:
在迁移成功后,删除该文件夹。
解决办法很简单,但是由于迁移的复杂性,难免会出现迁移不成功的情况,因此删除文件夹必须在100%确认已经迁移成功之后。(注:假若迁移没有成功,openstack自身提供了回滚机制,请自行参考相关代码(在conductor模块有rollback函数))
所以还得继续跟踪源码:


根进到driver.live_migration()


步骤10:修复bug

重点关注此处代码:
def wait_for_live_migration():
"""waiting for live migration completion."""
try:
self.get_info(instance)['state'] #此处一直获取实例状态,当实例被迁移走了,就会出现异常,说明迁移成功
except exception.InstanceNotFound:
timer.stop()
post_method(context, instance, dest, block_migration,
migrate_data)
因此删除文件夹,比较好的地方在此处。

原生代码:


日志说明是在 dom.migrateToURI函数执行后异常错误(即调用libvirt出异常)。
打印fuel代码:

日志打印一致,则说明在之前步骤中,原生nova没有pre-create文件夹。
用fule代码:



说明在 dom.migrateToURI()之前自动创建了文件夹。
再来看原生代码:


说明原生代码没有pre-create实例相应的文件夹。
查看代码driver.py代码:pre_live_migration()

这里if语句说明只有当is_shared_instance_path没有共享时候,才回去目的路径建立文件夹。
测试:

63的compute.log日志:可以看出为True,因此63不会自己创建保存实例的文件夹:

修复bug:
修改前:

修复后:

if (not is_shared_storage) or (CONF.libvirt.images_type == 'rbd') :
再次测试:

此时可以看到e95d7c8b-e8b7-44a0-8880-323e6720b435文件夹被创建了。
测试:

迁移成功:

看后台目录:


从上面可以看出虚拟机虽然从64迁移到63了,但是64上面虚拟机的文件还存在。这样就会导致虚拟机迁移回来时候,回报文件以及存在错误。(fuel的bug)
修复bug:
回到上述:步骤10:修复bug分析:
def wait_for_live_migration():
"""waiting for live migration completion."""
try:
self.get_info(instance)['state'] #此处一直获取实例状态,当实例被迁移走了,就会出现异常,说明迁移成功
except exception.InstanceNotFound:
timer.stop()
post_method(context, instance, dest, block_migration,
migrate_data)
调试:

继续测试从64将vm迁移到63:,看打印日志:
64日志:

63日志(没有输出日志):

结论和“步骤10:修复bug分析”分析一致
修复bug:

def wait_for_live_migration():
"""waiting for live migration completion."""
try:
self.get_info(instance)['state']
except exception.InstanceNotFound:
#add by ttx 2014-10-30
if (CONF.libvirt.images_type == 'rbd' and os.path.exists(inst_base)):
utils.execute('rm', '-rf', inst_base)
timer.stop()
post_method(context, instance, dest, block_migration,
migrate_data)
timer.f = wait_for_live_migration
timer.start(interval=0.5).wait()
继续测试:



继续迁移回来:


成功。
所有问题全部解决完成。
最后附上基础配置:
1 安装libvirt1.1.2
- openstack安装脚本openstack_init_env.sh中去掉libvirt的安装,当openstack_init_env.sh执行完之后,手动安装libvirt-1.1.2,安装完之后再执行后续的自动部署脚本。
- 安装libvirt-1.1.2:
解压libvirt-1.1.2源码安装包,进入源码目录
yum install -y libpciaccess-devel device-mapper-devel libnl-devel yajl-devel yajl
./configure --prefix=/usr/local/libvirt/
make
make install
mkdir -p /var/run/libvirt
mkdir -p /usr/local/libvirt/var/lock/subsys
cp -rf /usr/local/libvirt/bin/* /usr/bin/
cp -rf /usr/local/libvirt/sbin/* /usr/sbin/
cp -rf /usr/local/libvirt/libexec/* /usr/libexec/
cp -rf /usr/local/libvirt/etc/rc.d/init.d/* /etc/rc.d/init.d/
cp -rf /etc/init.d/functions /usr/local/libvirt/etc/rc.d/init.d/
cp -rf /usr/local/libvirt/lib64/python2.6/site-packages/* /usr/lib64/python2.6/site-packages/
cp -rf /usr/local/libvirt/etc/sysconfig/* /etc/sysconfig/
cp -rf /usr/local/libvirt/var/run/libvirt/* /var/run/libvirt
check_file_exist "/usr/local/libvirt/etc/libvirt/libvirtd.conf"
sed -i "/^[[:blank:]]*#[[:blank:]]*unix_sock_group/s/#unix_sock_group/unix_sock_group/g" /usr/local/libvirt/etc/libvirt/libvirtd.conf
sed -i "/^[[:blank:]]*#[[:blank:]]*unix_sock_ro_perms/s/#unix_sock_ro_perms/unix_sock_ro_perms/g" /usr/local/libvirt/etc/libvirt/libvirtd.conf
sed -i "/^[[:blank:]]*#[[:blank:]]*unix_sock_rw_perms/s/#unix_sock_rw_perms/unix_sock_rw_perms/g" /usr/local/libvirt/etc/libvirt/libvirtd.conf
sed -i "/^[[:blank:]]*#[[:blank:]]*auth_unix_ro/s/#auth_unix_ro/auth_unix_ro/g" /usr/local/libvirt/etc/libvirt/libvirtd.conf
sed -i "/^[[:blank:]]*#[[:blank:]]*auth_unix_rw/s/#auth_unix_rw/auth_unix_rw/g" /usr/local/libvirt/etc/libvirt/libvirtd.conf
groupadd libvirt
service libvirtd start
2、 配置libvirt1.1.2
修改文件
vim /usr/local/libvirt/etc/sysconfig/libvirtd
用来启用tcp的端口(本环境中由于libvirt升级过,配置文件目录不一致,默认为/etc/sysconfig/libvirtd)
1
2
3
LIBVIRTD_CONFIG=/usr/local/libvirt/etc/libvirt/libvirtd.conf
LIBVIRTD_ARGS="--listen"
修改文件
vim /usr/local/libvirt/etc/libvirt/libvirtd.conf
1
2
3
4
5
6
7
8
9
listen_tls = 0
listen_tcp = 1
tcp_port = "16509"
listen_addr = "0.0.0.0"
auth_tcp = "none"
运行 libvirtd
1
service libvirtd restart
版权声明:欢迎大家转载,转载请注明出处blog.iyunv.com/tantexian。 |
|