设为首页 收藏本站
查看: 3789|回复: 0

[经验分享] openstack nova后端使用ceph rbd(增加在线迁移live_migrate和快照snapshot功能)

[复制链接]

尚未签到

发表于 2015-10-10 14:26:54 | 显示全部楼层 |阅读模式


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


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



Better
Me的博客
:blog.iyunv.com/tantexian

如需交流,欢迎大家博客留言。






声明:本文记录的都是一些开发调试的过程,由于时间关系没有整理成文。


附上报错信息:
DSC0000.jpg






DSC0001.jpg
DSC0002.jpg
DSC0003.jpg
DSC0004.jpg
DSC0005.jpg
DSC0006.jpg
DSC0007.jpg
DSC0008.jpg
DSC0009.jpg
DSC00010.jpg DSC00011.jpg
附上代码:判断冷迁移还是热迁移逻辑:

        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)



DSC00012.jpg




conductor调用conpute的代码:
DSC00013.jpg
DSC00014.jpg


DSC00015.jpg
DSC00016.jpg DSC00017.jpg DSC00018.jpg


DSC00019.jpg


virsh -c qemu+tcp://node32/system
DSC00020.jpg


http://www.chenyudong.com/archives/libvirt-connect-to-libvirtd-with-tcp-qemu.html

virsh使用qemu+tcp访问远程libvirtd




DSC00021.jpg


http://libvirt.org/remote.html#Remote_libvirtd_configuration


DSC00022.jpg




DSC00023.jpg




官网配置:http://docs.ceph.com/docs/giant/rbd/rbd-openstack/


DSC00024.jpg




拿fule代码直接替换:
DSC00025.jpg








注:在测试过程中,假若没有成功,下次则会提示目录已经存在,则再目的迁移地址将
/var/lib/nova/instances下面相应文件夹删除掉
ntpdate 192.168.18.85
openvswich开启:/etc/init.d/openvswitch restart
DSC00026.jpg


配置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)





DSC00027.jpg
DSC00028.jpg


发现两个key不一致,因此ceph的key配置有问题


DSC00029.jpg


重新配置正确的key值,保证所有计算节点key值相同。重新配置后,需要将之前创建的虚拟机删除,重新生成




DSC00030.jpg


错误报在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)

DSC00031.jpg


DSC00032.jpg


查看下虚拟机实例在node31情况:
DSC00033.jpg
DSC00034.jpg
DSC00035.jpg
DSC00036.jpg
从上述打印日志可以看出dom值为libvirt.virtDomain对象:
DSC00037.jpg


/usr/lib64/python2.6/site-packages/libvirt.py
DSC00038.jpg
DSC00039.jpg


DSC00040.jpg




在能正常迁移的fule节点上面打印上述日志:






DSC00041.jpg
再迁移目标主机上建立文件夹:
mkdir /var/lib/nova/instances/022d1291-3967-4363-ab48-fb9713802e42/


libvirt debug模式:
LIBVIRT_DEBUG=1 virsh list --all
DSC00042.jpg
调试方法汇总:
http://fedoraproject.org/wiki/Category:Debugging
DSC00043.jpg




命令测试:
在node31上面:

virsh -c qemu+tcp://node32/system

DSC00044.jpg


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。
DSC00045.jpg
管理的点对点迁移:(Managed peer to peer migrate)
对于点对点,libvirt客户端程序只是与在源主机的libvirtd进程通信,源主机libvirtd进程自己控制整个迁移的过程,直接连接到目的主机的libvirtd。如果客户端应用崩溃了或者与libvirtd失去连接,迁移过程无需中断直至迁移完成。需要注意的是源主机认证(通常是root)链接到目的主机,而不是通过客户端应用链接到源主机。


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


DSC00047.jpg


迁移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自动生扯功能的端口需要防火墙对其端口是开放的。




DSC00048.jpg




virsh migrate --live --verbose --direct --p2p 5 qemu+tcp://node32/system


virsh migrate source_vm qemu+ssh://ip:port/system --live --storage-all?
DSC00049.jpg
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。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-125181-1-1.html 上篇帖子: Ceph v0.80.8.5 发布,分布式文件系统 下篇帖子: Openstack I版 结合 Ceph 分布式存储 部署安装(一)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表