在Ceph中创建虚拟机流程改进之分析(转)
来源:互联网 发布:银行业数据治理的问题 编辑:程序博客网 时间:2024/05/22 12:53
作为个人学习笔记分享,有任何问题欢迎交流!
最近在Gerrit中看到一个change:https://review.openstack.org/#/c/94295/ , 它主要是对当前在Ceph中创建虚拟机的流程的改进。如果glance的backend是ceph, 则nova创建虚拟机到RBD的流程是这样的:
通过glance从ceph中下载image --> 本地 --> 复制image到rbd
这个change的目的就是:不需要下载到本地,直接在rbd中复制image,以提高虚拟机创建的速度。
以前只知道nova从glance下载image,作为虚拟机的base,却没有仔细的了解过这个过程,正好借这个机会,看一看nova创建虚拟机到rbd过程中关于image的部分。
1 nova创建VM时image的流程
经过nova-scheduler选择节点后,创建VM的请求到达了nova-compute,即nova/compute/manager.py:ComputeManager._run_instance():
- def _run_instance(self, context, request_spec,
- filter_properties, requested_networks, injected_files,
- admin_password, is_first_time, node, instance,
- legacy_bdm_in_spec):
关于镜像的元数据就保存在request_spec,
- image_meta = request_spec['image']
取得元数据后就开始build_instance()了,但是下面的过程与image没太大关系,所以从简带过。
- def _build_instance(self, context, request_spec, filter_properties,
- requested_networks, injected_files, admin_password, is_first_time,
- node, instance, image_meta, legacy_bdm_in_spec)
- ---->
- def _spawn(self, context, instance, image_meta, network_info,
- block_device_info, injected_files, admin_password,
- set_access_ip=False)
- ---->
- self.driver.spawn(context, instance, image_meta,
- injected_files, admin_password,
- network_info,
- block_device_info)
这里的driver就是你用的Hypervioser, 我用的是KVM,所以这个driver.spawn=nova/virt/libvirt/driver.py:LibvirtDriver.spawn():
- def spawn(self, context, instance, image_meta, injected_files,
- admin_password,network_info=None, block_device_info=None):
- disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
- instance,
- block_device_info,
- image_meta)
- self._create_image(context, instance,
- disk_info['mapping'],
- network_info=network_info,
- block_device_info=block_device_info,
- files=injected_files,
- admin_pass=admin_password)
那么这个disk_info['mapping']是什么呢?这里有一个方法,我们可以从test_libvirt_blockinfo.py里找到答案,所以结合测试用例来看代码真的很有用。在Nova/tests/virt/libvirt/test_libvirt_blockinfo.py:
LibvirtBlockInfoTest.test_get_disk_mapping_simple_swap()里可以看到:
- expect = {
- 'disk': {'bus': 'virtio', 'dev': 'vda',
- 'type': 'disk', 'boot_index': '1'},
- 'disk.local': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
- 'root': {'bus': 'virtio', 'dev': 'vda',
- 'type': 'disk', 'boot_index': '1'}
- }
Expect就是期望disk_info['mapping']的样子。
下面就开始创建VM的image了:
- def _create_image(self, context, instance,
- disk_mapping, suffix='',
- disk_images=None, network_info=None,
- block_device_info=None, files=None,
- admin_pass=None, inject_files=True):
- #下面这个函数就是返回VM image格式的相关类,位于 #libvirt/imagebackend.py中,这里image是rbd, 返回的就是Rbd #类。
- def image(fname, image_type=CONF.libvirt.images_type):
- return self.image_backend.image(instance,
- fname + suffix, image_type)
- ......
- if not booted_from_volume:
- root_fname = imagecache.get_cache_fname(disk_images, 'image_id')#以image id作为文件名
- size = instance['root_gb'] * units.Gi
- if size == 0 or suffix == '.rescue':
- size = None
- #这里有点复杂,用到了回调函数fetch_image,这里的cache是Rbd的父类#Image类的cache(),主要功能是从模板,也就是glance的image, 为VM创建一个image.
- image('disk').cache(fetch_func=libvirt_utils.fetch_image,
- context=context,
- filename=root_fname,
- size=size,
- image_id=disk_images['image_id'],
- user_id=instance['user_id'],
- project_id=instance['project_id'])
- #可以在cache()中看到:
- if not self.check_image_exists() or not os.path.exists(base):
- self.create_image(fetch_func_sync, base, size,
- *args, **kwargs)
那么现在到class Rbd下可以找到create_image():
- def create_image(self, prepare_template, base, size, *args, **kwargs):
- if self.rbd is None:
- raise RuntimeError(_('rbd python libraries not found'))
- if not os.path.exists(base):
- prepare_template(target=base, max_size=size, *args, **kwargs)##这里的prepare_temple()就是 libvirt_utils.fetch_image啦。
libvirt_utils.fetch_image=nova/virt/libvirt/utils.fetch_image():
- def fetch_image(context, target, image_id, user_id, project_id, max_size=0):
- """Grab image."""
- images.fetch_to_raw(context, image_id, target, user_id, project_id,
- max_size=max_size)
- --->
- def fetch_to_raw(context, image_href, path, user_id, project_id, max_size=0):
- path_tmp = "%s.part" % path
- fetch(context, image_href, path_tmp, user_id, project_id,
- max_size=max_size)
- ---->
- def fetch(context, image_href, path, _user_id, _project_id, max_size=0):
- (image_service, image_id) = glance.get_remote_image_service(
- context, image_href)#从glance获取image
- with fileutils.remove_path_on_error(path):
- #这里就是把image_id的数据download到path了。Download()位于 #nova/image/glance.py。
- image_service.download(context, image_id, dst_path=path)
回到class Rbd的create_image()中,
libvirt_utils.import_rbd_image(*args)把path的image数据写入rbd,至此,整个流程就到这里结束了。
2 Change中的改进
现在回到文章开始中提到的那个change, 看看它是怎么实现的。
首先它在fetch_to_raw中加入了一个判断。
- def fetch_to_raw(context, image_href, path, user_id, project_id, max_size=0):
- #判断backend是否具有‘direct_fetch’的属性,如果有,则直接返回#direct_fetch()
- if backend and hasattr(backend, 'direct_fetch'):
- try:
- return backend.direct_fetch(context, image_href)
- except exception.ImageUnacceptable:
- LOG.debug(_('could not fetch directly, falling back to download'))
给Rbd类添加了一个属性:
- def direct_fetch(self, context, image_href):
- #判断driver是否支持layering(分层
- #http://ceph.com/docs/firefly/dev/rbd-layering/ ,指的是块设备
- #的cow克隆,支持快速创建image)
- if not self.driver.supports_layering():
- reason = _('installed version of librbd does not support cloning')
- raise exception.ImageUnacceptable(image_id=image_href,
- reason=reason)
- image_meta, locations = images.get_meta(context, image_href)
- LOG.debug(_('Image locations are: %(locs)s') % {'locs': locations})
- if image_meta.get('disk_format') not in ['raw', 'iso']:
- reason = _('Image is not raw format')
- raise exception.ImageUnacceptable(image_id=image_href,
- reason=reason)
- #克隆镜像(http://ceph.com/docs/master/rbd/librbdpy/)
- for location in locations:
- if self.driver.is_cloneable(location, image_meta):
- return self.driver.clone(location, self.rbd_name)
- reason = _('No image locations are accessible')
- raise exception.ImageUnacceptable(image_id=image_href, reason=reason)
这样就不需要想1中的那样先把image下载到local, 在写到rbd中,直接在rbd中克隆,从而提高了虚拟机的创建速度。
3总结
借这个机会既熟悉了创建VM时的image流程,又熟悉了ceph的用法,同时学习了高手们是怎么实现一个功能的,看来review的益处大大的呀。:)
- 在Ceph中创建虚拟机流程改进之分析
- 在Ceph中创建虚拟机流程改进之分析(转)
- openstack之虚拟机创建流程分析
- ceph的pool创建流程--代码分析
- ceph源码分析之读写操作流程(1)
- ceph源码分析之读写操作流程(2)
- openstack Nova分析之 创建虚拟机流程(4)
- ceph写流程分析
- [Ceph分析]Fuse流程分析
- OpenStack Nova 虚拟机创建流程分析
- ceph存储 ceph中pglog处理流程
- 在Azure中创建虚拟机
- Ceph浅析(中):结构、工作原理及流程
- OpenStack之Nova分析——创建虚拟机(一)
- OpenStack之Nova分析——创建虚拟机(二)
- OpenStack之Nova分析——创建虚拟机(三)
- OpenStack之Nova分析——创建虚拟机(四)
- OpenStack之Nova分析——创建虚拟机(五)
- unreachable remote address [akka.tcp://sparkMaster@localhost:7077]解决方法
- 设计模式--构造者模式
- Office2010 下载
- CAS、Spring Security、Ldap配置整合(资料整合)
- 安全管理入门 七大CSO必备秘方收藏
- 在Ceph中创建虚拟机流程改进之分析(转)
- 直接将ppt转换成pdf格式的方法
- [Android][Error] ADB server 無法連接
- Recovery代码分析之一
- Xcode6中如何添加pch文件
- Java连接Sql Server的过程及遇到的问题(极端新手向)
- isNotEmpty,isNotBlank ,isEmpty ,isBlank 字符串空判断
- PI 的BDS阶段
- Ambari-整体介绍