您的位置:首页 > 运维架构

openstack 虚拟机迁移过程总结

2014-07-15 17:44 537 查看
虚机的迁移主要分为一下三个阶段:预迁移 pre_live_migration 迁移 live_migration 迁移后 post_live_migration。
另外,迁移失败后,有rollback操作

1,迁移接口

迁移一个虚机会通过消息队列,最终调用到compute服务中的live_migration接口

def live_migration(self, context, dest, instance,
                       block_migration=False, migrate_data=None):
        migrate_data = dict(migrate_data or {})
        try:
            if block_migration:
                disk = self.driver.get_instance_disk_info(instance['name'])
            else:
                disk = None

            pre_migration_data = self.compute_rpcapi.pre_live_migration(
                context, instance,
                block_migration, disk, dest, migrate_data)
            migrate_data['pre_live_migration_result'] = pre_migration_data
			
		# 以上是预迁移阶段,获取虚机的迁移信息,即告知目标主机做好迁移准备,并返回相关数据

        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.exception(_('Pre live migration failed at %s'),
                              dest, instance=instance)
                self._rollback_live_migration(context, instance, dest,
                                              block_migration, migrate_data)
		#否则就回滚刚才的操作,同样也是通知目标主机此次迁移失败,销毁相关数据

        self.driver.live_migration(context, instance, dest,
                                   self._post_live_migration,
                                   self._rollback_live_migration,
                                   block_migration, migrate_data)
		#  执行迁移动作,同时传递了两个方法:
		#  _post_live_migration     迁移成功后,应该执行的操作
		#  _rollback_live_migration 迁移失败后,回滚操作


2,pre_live_migration

(注,这个是在目标主机上的操作)
    def pre_live_migration(self, context, instance,
                           block_migration=False, disk=None,
                           migrate_data=None):
        block_device_info = self._get_instance_volume_block_device_info(
                            context, instance, refresh_conn_info=True)
		#查看虚机的块设备
		
        network_info = self._get_instance_nw_info(context, instance)  
		#获取虚机的网络信息
		
        pre_live_migration_data = self.driver.pre_live_migration(context,
                                       instance,
                                       block_device_info,
                                       network_info,
                                       disk,
                                       migrate_data)
        #执行预迁移的一些操作
		
        self.network_api.setup_networks_on_host(context, instance,self.host)
        self.driver.ensure_filtering_rules_for_instance(instance,network_info)
		#在目标主机上建立网络和防火墙

        return pre_live_migration_data
    
	###############################
	self.driver.pre_live_migration
	###############################
	    def pre_live_migration(self, context, instance, block_device_info,
                           network_info, disk_info, migrate_data=None):
        is_shared_storage = True
        is_volume_backed = False
        is_block_migration = True
        instance_relative_path = None
        if migrate_data:
            is_shared_storage = migrate_data.get('is_shared_storage', True)
            is_volume_backed = migrate_data.get('is_volume_backed', False)
            is_block_migration = migrate_data.get('block_migration', True)
            instance_relative_path = migrate_data.get('instance_relative_path')

        if not is_shared_storage:
            if instance_relative_path:
                instance_dir = os.path.join(CONF.instances_path,
                                            instance_relative_path)
            else:
                instance_dir = libvirt_utils.get_instance_path(instance)

            if os.path.exists(instance_dir):
                raise exception.DestinationDiskExists(path=instance_dir)
            os.mkdir(instance_dir)

            # Ensure images and backing files are present.
            self._create_images_and_backing(context, instance, instance_dir,
                                            disk_info)

        if is_volume_backed and not (is_block_migration or is_shared_storage):
            console_file = self._get_console_log_path(instance)
            libvirt_utils.file_open(console_file, 'a').close()

            self._fetch_instance_kernel_ramdisk(context, instance)

        # Establishing connection to volume server.
        block_device_mapping = driver.block_device_info_get_mapping(
            block_device_info)
        for vol in block_device_mapping:
            connection_info = vol['connection_info']
            disk_dev = vol['mount_device'].rpartition("/")[2]
            disk_info = blockinfo.get_info_from_bdm(CONF.libvirt_type, vol)
            self.volume_driver_method('connect_volume',
                                      connection_info,
                                      disk_info)

        max_retry = CONF.live_migration_retry_count
        for cnt in range(max_retry):
            try:
                self.plug_vifs(instance, network_info)
                break
            except processutils.ProcessExecutionError:
                if cnt == max_retry - 1:
                    raise
                else:
                    LOG.warn(_('plug_vifs() failed %(cnt)d. Retry up to '
                               '%(max_retry)d.'),
                             {'cnt': cnt,
                              'max_retry': max_retry},
                             instance=instance)
                    greenthread.sleep(1)


3,迁移

driver.live_migration()
def _live_migration(self, context, instance, dest, post_method,
                        recover_method, block_migration=False,
                        migrate_data=None):
        try:
            if block_migration:
                flaglist = CONF.block_migration_flag.split(',')
            else:
                flaglist = CONF.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"])
            dom.migrateToURI(CONF.live_migration_uri % dest,
                             logical_sum,
                             None,
                             CONF.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)
        #如果迁移失败,则执行回滚操作,即传递的rollback_live_miration方法
		
        # Waiting for completion of live_migration.
        timer = loopingcall.FixedIntervalLoopingCall(f=None)

        def wait_for_live_migration():
            try:
                self.get_info(instance)['state']
            except exception.InstanceNotFound:
                timer.stop()
                post_method(context, instance, dest, block_migration,
                            migrate_data)
        timer.f = wait_for_live_migration
        timer.start(interval=0.5).wait()
		#执行post_live_migration


4,post_live_migration

分为两部分,一部分是在源主机上的操作,一部分是在目标主机上的操作
@wrap_exception()
    def _post_live_migration(self, ctxt, instance_ref,
                            dest, block_migration=False, migrate_data=None):
        # 在源主机上执行live_migration操作
        block_device_info = self._get_instance_volume_block_device_info(
                            ctxt, instance_ref)
        self.driver.post_live_migration(ctxt, instance_ref, block_device_info)
	
        # 卸载虚机上的现有volumes
        connector = self.driver.get_volume_connector(instance_ref)
        for bdm in self._get_instance_volume_bdms(ctxt, instance_ref):
            self.volume_api.terminate_connection(ctxt, bdm['volume_id'],
                                                 connector)
        
		#获取源主机上虚机的网络信息,删除
        network_info = self._get_instance_nw_info(ctxt, instance_ref)
        self.driver.unfilter_instance(instance_ref,
                                      network_info)

		#在数据库中标示下:开始迁移
        migration = {'source_compute': self.host,
                     'dest_compute': dest, }
        self.conductor_api.network_migrate_instance_start(ctxt,
                                                          instance_ref,
                                                          migration)
													

        # 发送请求至消息队列,在目标主机上执行post_live_migration_at_destination
        self.compute_rpcapi.post_live_migration_at_destination(ctxt,
                instance_ref, block_migration, dest)

        is_shared_storage = True
        if migrate_data:
            is_shared_storage = migrate_data.get('is_shared_storage', True)
        if block_migration or not is_shared_storage:
            self.driver.destroy(instance_ref, network_info)
        else:
            self.driver.unplug_vifs(instance_ref, network_info)
        self.network_api.setup_networks_on_host(ctxt, instance_ref,self.host, teardown=True)

        if CONF.vnc_enabled or CONF.spice.enabled:
            if CONF.cells.enable:
                self.cells_rpcapi.consoleauth_delete_tokens(ctxt,
                        instance_ref['uuid'])
            else:
                self.consoleauth_rpcapi.delete_tokens_for_instance(ctxt,
                        instance_ref['uuid'])
	    #删除源主机上的一些桌面连接验证信息

	#############################################################	
	源主机上的post_live_migration::driver.post_live_migration
	#############################################################
	    def post_live_migration(self, context, instance, block_device_info):
        # Disconnect from volume server
        block_device_mapping = driver.block_device_info_get_mapping(
                block_device_info)
        for vol in block_device_mapping:
            connection_info = vol['connection_info']
            disk_dev = vol['mount_device'].rpartition("/")[2]
            self.volume_driver_method('disconnect_volume',
                                      connection_info,
                                      disk_dev)
									  
	#############################################################	
	目标主机上的post_live_migration:
	#####
	manager.post_live_migration_at_destination
	def post_live_migration_at_destination(self, context, instance,
                                           block_migration=False):
        self.network_api.setup_networks_on_host(context, instance,
                                                         self.host)
        migration = {'source_compute': instance['host'],
                     'dest_compute': self.host, }
        self.conductor_api.network_migrate_instance_finish(context,
                                                           instance,
                                                           migration)

        network_info = self._get_instance_nw_info(context, instance)
        self._notify_about_instance_usage(
                     context, instance, "live_migration.post.dest.start",
                     network_info=network_info)
        block_device_info = self._get_instance_volume_block_device_info(
                            context, instance)

        self.driver.post_live_migration_at_destination(context, instance,
                                            network_info,
                                            block_migration, block_device_info)
        current_power_state = self._get_power_state(context, instance)
        node_name = None
        try:
            compute_node = self._get_compute_info(context, self.host)
            node_name = compute_node['hypervisor_hostname']
        except exception.NotFound:
            LOG.exception(_('Failed to get compute_info for %s') % self.host)
        finally:
            instance = self._instance_update(context, instance['uuid'],
                    host=self.host, power_state=current_power_state,
                    vm_state=vm_states.ACTIVE, task_state=None,
                    expected_task_state=task_states.MIGRATING,
                    node=node_name)

        # NOTE(vish): this is necessary to update dhcp
        self.network_api.setup_networks_on_host(context, instance, self.host)
        self._notify_about_instance_usage(
                     context, instance, "live_migration.post.dest.end",
                     network_info=network_info)
	#####
	:driver.post_live_migration_at_destination
	#####
	    def post_live_migration_at_destination(self, context,
                                           instance,
                                           network_info,
                                           block_migration,
                                           block_device_info=None):
        # Define instances
        dom_list = self._conn.listDefinedDomains()
        if instance["name"] not in dom_list:
            disk_info = blockinfo.get_disk_info(
                CONF.libvirt_type, instance, block_device_info)
            self.to_xml(context, instance, network_info, disk_info,
                        block_device_info=block_device_info,
                        write_to_disk=True)
            dom = self._lookup_by_name(instance["name"])
            self._conn.defineXML(dom.XMLDesc(0))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: