目前,云硬盘创建镜像,调用cinder upload-to-image。处理流程:先缓存rbd image到本地(本地磁盘IO利用率高),再调用glance upload image 到glance(占用管理网络带宽),整体很耗时间。
官方的具体描述:https://specs.openstack.org/openstack/cinder-specs/specs/liberty/optimze-rbd-copy-volume-to-image.html
官方提供两种方案,具体描述如下:
前提:
- cinder和glance的存储后端在同一个ceph集群中
- 如果不是,仍然采用目前的方案,先将rbd image导入到cinder volume本地,然后再调用glance uoload api上传文件到glance 存储后端
- 如果是的话,可采用rbd.image.copy 方法,将volume 从一个volume pool 拷贝到image pool
方法1:采用copy
方法2:采用clone。具体如下:1. 创建一个volume 快照snap ,同时project 这个snap 2. 基于快照clone一个child image 3.Flatten 这个child image 4. unprotect 这个snap,然后删除它。
根据测试:方法1耗时更短。(具体可查看官网描述)
具体的代码修改,可参考如下(Liberty):
cinder.volume.drivers.rbd.py
def copy_volume_to_image(self,context, volume, image_service, image_meta):
#(offload rbd's copy_volume_to_imagefunction from host to ceph cluster)
if self.configuration.rbd_copy_volume_to_glance://cinder.conf中可控制是否采用copy方法
glance_rbd_ceph_fsid = self.configuration.glance_rbd_ceph_fsid
if self._get_fsid() ==glance_rbd_ceph_fsid://判断glance和cinder是否在同一个ceph集群
LOG.debug("Glance backend is in the same ceph cluster, "
"try to copy volume%s to glance.", volume['name'])
image_id = image_meta['id']
src_pool = self.configuration.rbd_pool
src_img_name = volume['name']
dst_pool = self.configuration.glance_rbd_pool
dst_img_name = image_id
self._copy(src_pool, src_img_name, dst_pool, dst_img_name)
# 可根据需要是否创建一个snapshot
""""""
return
else:
LOG.debug("Glance backend is in a different ceph cluster.")
# 'rbd_copy_volume_to_glance'is False or glance's ceph cluster is difference with cinder' ceph cluster
LOG.debug("Try to upload volume %sto glance.", volume['name'])
tmp_dir = self._image_conversion_dir()
tmp_file = os.path.join(tmp_dir,
volume['name'] +'-' + image_meta['id'])
withfileutils.remove_path_on_error(tmp_file):
args = ['rbd', 'export',
'--pool', self.configuration.rbd_pool,
volume['name'],tmp_file]
args.extend(self._ceph_args())
self._try_execute(*args)
image_utils.upload_volume(context, image_service,
image_meta,tmp_file)
os.unlink(tmp_file)
# 新增_cpye方法
def _copy(self, src_pool, src_img_name,dst_pool, dst_img_name):
"""
:param src_pool: source rbdimage's pool
src_img_name: source rbd image's name
dst_pool: dest rbd image's pool
dst_img_name: dest rbd image's name
"""
LOG.debug('copying %(pool)s/%(img)s to %(dst_pool)s/%(dst_img)s',
dict(pool=src_pool,img=src_img_name, dst_pool=dst_pool, dst_img=dst_img_name))
src_name = utils.convert_str(src_img_name)
dest_name = utils.convert_str(dst_img_name)
src_pool = utils.convert_str(src_pool)
dest_pool = utils.convert_str(dst_pool)
with RBDVolumeProxy(self, src_name, pool=src_pool, read_only=True) asvol:
with RADOSClient(self, dest_pool) as dest_client:
vol.copy(dest_client.ioctx,dest_name, features=vol.features())