混合云的做法,现在一般都是api适配得做法。比如nova或者cinder,都是在driver层增加一个对接aws或者vmware的driver来调公有云或者私有云的API,从而达到在私有云里管理公有云的目的。
现在有很多公司做混合云管理多个私有云或者公有云,那今天我讲的就是虚拟机创建镜像的一个优化操作。
测试环境:私有云openstack A,公有云openstack B,openstack为L版本,现在很多公司做的公有云都是用openstack做的,那我的测试环境就全部用openstack来测试。
写一个openstack driver,在nova.conf 配置一下driver为openstack driver,在私有云A中创建虚拟机,就会经过openstack driver调到公有云B上去创建虚拟机了。
优化前方案:
在优化创建镜像之前,创建镜像的流程是啥呢,如下图所示:
我们来看一下driver层的步骤,就当你已经看过nova制作镜像的代码了。
步骤:
1、调用novaclient接口create image 到公有云B上创建镜像
2、等待instance的task_state 为None,就说明虚拟机这边创建镜像完成。
3、等待image的status为active状态,说明在公有云B上镜像真正的创建完成
4、调用glance image download接口把镜像下载到私有云A本地,写入文件tmp.raw
5、调用 本地glance 接口upload到本地的glance服务上,删除临时文件tmp.raw
6、写入私有云镜像与公有云镜像的对应关系。
这样整个在私有云的glance上就会有你创建的镜像,如果你的私有云还管理其他的私有云或者公有云,也可以用你刚才制作的镜像了。
那问题来了,在第4步的步骤中,有一个download镜像和写入到本地文件的过程,那这个过程是否可以优化呢?
优化方案:
在调用glance image_download接口时,是直接返回的一个生成器,for循环把所有的数据读取上来存到文件中的,
上传镜像时,glance upload接口时会传入一个文件的fd,upload的时候for循环在文件中读取出文件信息发送到glance服务的。
那我的优化点就在这,download文件时,不写入临时文件,直接把生成器传入到upload接口中,从而达到一个proxy过程,这样就节省了写入文件与读取文件的操作了。
优化的整个流程图如下:
优化后的步骤:
1、调用novaclient接口create image 到公有云B上创建镜像
2、等待instance的task_state 为None,就说明虚拟机这边创建镜像完成。
3、等待image的status为active状态,说明在公有云B上镜像真正的创建完成
4、调用glance image download返回一个生成器 image_data,调用本地glance image upload接口把生成器image_data作为参数传入,直接下载并上载到本地glance中。
5、写入私有云镜像与公有云镜像的对应关系。
代码如下:
首先我们需要自己定义个生成器,我们有一个read接口,在upload的时候就是调用read接口来读取数据。
class DataFile(object):
"""An iterator wrapper with image.
:note: Use only with iterator that yield strings.
"""
def __init__(self, wrapped):
self._wrapped = wrapped
def __iter__(self):
return self
def next(self):
try:
data = six.next(self._wrapped)
return data
except StopIteration:
raise
def read(self, length):
return self.next()
def __len__(self):
return len(self._wrapped)
# In Python 3, __next__() has replaced next().
__next__ = next
下载接口如下,data返回的生成器,我们在用DataFile进行封装一层,如果你用的keystoneauth1的session来建立连接的,你一定要把debug日志关掉,否则镜像数据会打印到日志造成很大的延时。
def data(self, image_id):
py_logging.getLogger('keystoneauth1').setLevel(py_logging.WARNING)
image_data = self.client().images.data(image_id)
return DataFile(image_data)
下载与上传镜像的代码, image_data就是我们DataFile包装的生成器。
LOG.debug(" begin to download image(%s)",
provider_image_id)
image_data = self.os_glanceclient(context).data(
provider_image_id)
LOG.debug("+++hw, image length = %s", len(image_data))
self._image_api.update(context,
image_id,
metadata,
image_data)
未来可能优化的地方:
我们可以看到,在优化的方案中,nova driver还是会做一个中转器,中转镜像数据,有没有办法,可以给本地glance一个url,glance通过网络直接去下载呢?
未来可能优化的流程图如下:
这个方案可能需要修改一下公有云openstack的glance配置,配置项:
show_image_direct_url = True
show_multiple_locations = True
修改此连个选项之后,就可以返回direct_url,这个可能对glance后端为swift或者ceph做为存储的,有可能实现这个方案。
代码部分的实现:
image = self.os_glanceclient(context).get_image(
provider_image_id)
LOG.debug("+++hw, image = %s", image)
if hasattr(image, "direct_url"):
direct_url = image.direct_url
if direct_url.startswith("swift+http://") or \
direct_url.startswith("http://") or \
direct_url.startswith("https://"):
metadata["location"] = direct_url
self._image_api.update(context, image_id, metadata,
purge_props=False)
这个只是很小的优化,大家是否有更好的优化,希望你们给我留言,提出建议,谢谢。