openstack nova后端使用ceph rbd(增加在线迁移live_migrate和快照snapshot功能)

感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正!

如有转载,请保留源作者博客信息。

Better Me的博客blog.csdn.net/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

virsh使用qemu+tcp访问远程libvirtd











拿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 valueDescription
[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
调试方法汇总:


命令测试:
在node31上面:
virsh -c qemu+tcp://node32/system


说到虚拟机的迁移,其实就是数据的转移,数据的转移就涉及数据的传输,数据的传输需要通过网络。libvirt提供了两种方案。

hypervisor native transport:
“本地”数据传输,相当于一种手动方式做的迁移。数据是否可以加密取决于hypervisor自身是否已实现。
libvirt tunnelled transport
隧道化的(tunnelled)数据传输支持很强的加密功能,这要归结于libvirt的RPC协议。不好的一方面是数据会在hypervisor和libvirtd之间的传输。

虚拟机的迁移需要两个主机之间的密切协调,同时应用程序(虚拟机管理平台)也将参与进来,此应用可以是在源主机、目的主机、甚至是第三台主机。

受管理的直接迁移(Managed direct migration):
直接管理迁移,libvirt客户端进程控制迁移的不同阶段。客户端应用程序必须连接以及获得在源主机和目的主机的libvirtd进程的认证。无需两个libvirtd进程间相互通信。如果客户端应用崩溃了,或者在迁移过程中失去了链接,一种办法就是强制终止迁移,重启源主机的guest CPU。
Migration direct, managed
管理的点对点迁移:(Managed peer to peer migrate)
对于点对点,libvirt客户端程序只是与在源主机的libvirtd进程通信,源主机libvirtd进程自己控制整个迁移的过程,直接连接到目的主机的libvirtd。如果客户端应用崩溃了或者与libvirtd失去连接,迁移过程无需中断直至迁移完成。需要注意的是源主机认证(通常是root)链接到目的主机,而不是通过客户端应用链接到源主机。

Migration peer-to-peer
不受管理的直接迁移:(Unmanaged direct migrate)
此迁移方式既不受libvirt客户端控制,也不受libvirtd控制,迁移的控制过程委托给基于hypervisor之上的管理服务来处理。libvirt 客户只需要通过hypervisor的管理层做一下初始化。不管是libvirt 客户端还是libvirtd崩溃了,迁移还是会照样进行直至完成。

Migration direct, unmanaged

迁移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?


vim /usr/local/libvirt/etc/libvirt/qemu.conf 

service libvirtd restart


问题木有解决,继续,重新编译libvirt:
./configure --prefix=/usr/local/libvirt/ --with-selinux=no

selinux问题解决了。again:

这次成功了,什么都不改变,后面不能成功了???


重新生成虚拟机测试:
重启libvirt报错:
 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


[ root@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


[ root@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

由上述可知: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

  1. openstack安装脚本openstack_init_env.sh中去掉libvirt的安装,当openstack_init_env.sh执行完之后,手动安装libvirt-1.1.2,安装完之后再执行后续的自动部署脚本。
  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


  1. 继续执行剩余的自动部署脚本。


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



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值