openstack 虚拟机迁移过程总结
2014-07-15 17:44
537 查看
虚机的迁移主要分为一下三个阶段:预迁移 pre_live_migration 迁移 live_migration 迁移后 post_live_migration。
另外,迁移失败后,有rollback操作
另外,迁移失败后,有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))
相关文章推荐
- openstack在线迁移需要做的配置并整理成脚本以及在线迁移过程系统自动修改的内容总结
- 总结:虚拟机上添加一块新硬盘,并创建lvm裸设备给oracle使用的过程
- 安装Xen、创建Xen虚拟机、使用Xen虚拟机过程中经常出现的错误总结
- Openstack部署虚拟机的过程中,网络的参与过程。
- 虚拟机迁移过程中网络状况测试的测试程序
- 从代码看OpenStack启动虚拟机的过程
- 安装Xen、创建Xen虚拟机、使用Xen虚拟机过程中经常出现的错误总结
- OPENSTACK ICEHOUSE 迁移虚拟机
- 在windows 7 虚拟机上安装windows xp系统全过程总结
- OpenStack虚拟机创建过程中镜像格式的的变化过程
- OpenStack虚拟机创建过程中镜像格式的的变化过程
- 使用virt-p2v工具将物理机迁移到Openstack虚拟机中
- 虚拟机在线迁移技术论文总结
- OpenStack虚拟机创建过程中镜像格式的的变化过程
- openstack虚拟机迁移live-migration中libvirt配置
- openstack-虚拟机在线迁移失败问题及解决办法
- 安装Xen、创建Xen虚拟机、使用Xen虚拟机过程中经常出现的错误总结
- openstack 虚拟机迁移时应注意的问题
- 虚拟机Ubuntu 13.04 在Easy Install 下安装vmware tools 过程及遇到的问题总结
- 基于OpenStack的虚拟机在线迁移