OpenStack Nova深入学习 -- 创建instance的过程之源码分析

来源:互联网 发布:数据库系统的基础是 编辑:程序博客网 时间:2024/04/27 22:39

Nova的核心组件有nova API, nova Conductor,nova Scheduler和nova compute。如下图所示:


nova主要组件的作用:


1). nova API -- 主要是接收HTTP请求(通常来自nova client),将其转换成命令,并通过oslo message和nova Conductor或者nova Compute交互。为了完成虚机的处理(比如创建、修改,删除等)操作,nova API还需要通过HTTP协议向Keystone, Neutron,  Glance发出请求。


2). nova Conductor -- 主要作为一个数据库代理存在,避免nova Compute直接操作数据库。


3). nova Compute -- 主要是操纵compute node上的hypervisor对instance进行创建和管理。


4). nova Scheduler -- 主要是用来判断新创建的instance应该被放在哪一个compute node上,它的配置在/etc/nova/nova.conf里完成,缺省配置如下:

scheduler_available_filters=nova.scheduler.filters.all_filters
scheduler_default_filters=RetryFilter,AvailabilityZoneFilter,RamFilter,ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter,ServerGroupAntiAffinityFilter,ServerGroupAffinityFilter

scheduler_driver=nova.scheduler.filter_scheduler.FilterScheduler

其中,scheduler_driver决定了nova用什么样的scheduler,scheduler_default_filters决定了在一个compute node被选中作为instance的宿主前,都需要过哪些检查关口,如下是这些检查关口的说明:

-- RetryFilter:找出还没有被尝试filter过的compute node

-- AvailabilityZoneFilter:必须在规定的availability zone里选compute node

-- RamFilter:compute node必须有足够的内存支持instance的创建

-- ComputeFilter:必须有compute node存在

-- ComputeCapabilitiesFilter:compute node必须满足instance创建需要的extra specs

-- ImagePropertiesFilter:compute node必须满足镜像里定义的属性,比如architecture是否是qcow2,是否支持KVM hyperviosr等。

-- ServerGroupAntiAffinityFilter:如果创建多个instance,需要让这些instance分布在不同的compute node上

-- ServerGroupAffinityFilter:如果创建多个instance,需要让这些instance分布在相同的compute node上


下面,通过nova的源码看一下一个新的instance被创建需要经过哪些过程,代码来自Liberty版本:


创建instance的入口代码在nova/api/openstack/compute/servers.py,方法是create(),如下:

   def create(self, req, body):            (instances, resv_id) = self.compute_api.create(context,                            inst_type,                            image_uuid,                            display_name=name,                            display_description=name,                            metadata=server_dict.get('metadata', {}),                            admin_password=password,                            requested_networks=requested_networks,                            check_server_group_quota=True,                            **create_kwargs)


compute_api对象来自compute.API类,如下。而compute.API来自nova/compute/__init__.py。

        self.compute_api = compute.API(skip_policy_check=True)


查看nova/compute/__init__.py,看到API()返回的就是nova.compute.api.API,如下。所以compute_api就是nova.compute.api.API。

CELL_TYPE_TO_CLS_NAME = {'api': 'nova.compute.cells_api.ComputeCellsAPI',                         'compute': 'nova.compute.api.API',                         None: 'nova.compute.api.API',                        }def _get_compute_api_class_name():    """Returns the name of compute API class."""    cell_type = nova.cells.opts.get_cell_type()    return CELL_TYPE_TO_CLS_NAME[cell_type]def API(*args, **kwargs):    class_name = _get_compute_api_class_name()    return importutils.import_object(class_name, *args, **kwargs)


查看nova/compute/api.py,看到create()方法调用了_create_instance(),如下:

    def create(self, context, instance_type,               image_href, kernel_id=None, ramdisk_id=None,               min_count=None, max_count=None,               display_name=None, display_description=None,…        return self._create_instance(                       context, instance_type,                       image_href, kernel_id, ramdisk_id,                       min_count, max_count,…


_create_instance()也在nova/compute/api.py中定义,它又调用了compute_task_api对象的build_instances()方法,如下:

    def _create_instance(self, context, instance_type,               image_href, kernel_id, ramdisk_id,               min_count, max_count,…        self.compute_task_api.build_instances(context,                instances=instances, image=boot_meta,                filter_properties=filter_properties,…


compute_task_api对象也在nova/compute/api.py中定义,来自conductor.ComputeTaskAPI对象,如下:

    def compute_task_api(self):        if self._compute_task_api is None:            # TODO(alaski): Remove calls into here from conductor manager so            # that this isn't necessary. #1180540            from nova import conductor            self._compute_task_api = conductor.ComputeTaskAPI()        return self._compute_task_api


ComputeTaskAPI对象在nova/conductor/__init__.py中定义,来自nova.conductor.api.ComputeTaskAPI,如下:

from nova.conductor import api as conductor_apidef ComputeTaskAPI(*args, **kwargs):    use_local = kwargs.pop('use_local', False)    if oslo_config.cfg.CONF.conductor.use_local or use_local:        api = conductor_api.LocalComputeTaskAPI    else:        api = conductor_api.ComputeTaskAPI    return api(*args, **kwargs)


查看nova/conductor/api.py,build_instances()方法调用了conductor_compute_rpcapi对象的build_instances()方法。conductor_compute_rpcapi对象来自nova/conductor/rpcapi.py中定义的ComputeTaskAPI类。

class ComputeTaskAPI(object):…    def __init__(self):        self.conductor_compute_rpcapi = rpcapi.ComputeTaskAPI()…    def build_instances(self, context, instances, image, filter_properties,            admin_password, injected_files, requested_networks,            security_groups, block_device_mapping, legacy_bdm=True):        self.conductor_compute_rpcapi.build_instances(context,                instances=instances, image=image,……



nova/conductor/rpcapi.py是专门处理nova组件之间的RPC调用的。因为这里定义的topic是conductor,根据http://www.cnblogs.com/littlebugfish/p/4090311.html中的描述的消息队列原理,这里将转到nova-conductor进程中进行处理。

    def build_instances(self, context, instances, image, filter_properties,            admin_password, injected_files, requested_networks,…        cctxt = self.client.prepare(version=version)        cctxt.cast(context, 'build_instances', **kw)


查看nova/conductor/manager.py,看到build_instances()方法会调用scheduler_client.select_destinations()和compute_rpcapi.build_and_run_instance()。前者会调用schedular的RPC API选择在哪些主机上创建instance,后者会通过RPC请求nova-compute服务去构建和运行instance。

class ComputeTaskManager(base.Base):…    def build_instances(self, context, instances, image, filter_properties,            admin_password, injected_files, requested_networks,……        try:…            hosts = self.scheduler_client.select_destinations(context,                    request_spec, filter_properties)…        for (instance, host) in itertools.izip(instances, hosts):…            self.compute_rpcapi.build_and_run_instance(context,                    instance=instance, host=host['host'], image=image,                    request_spec=request_spec,…


查看nova/compute/manager.py,整个的调用过程如下:

build_and_run_instance() --> _do_build_and_run_instance() --> _build_and_run_instance() --> driver.spawn()


driver对象是在nova/virt/driver.py里定义,调用load_compute_driver()方法获得并加载compute driver。compute driver的定义是在/etc/nova/nova.conf里由compute_driver的值确定。

def __init__(self, compute_driver=None, *args, **kwargs):        self.driver = driver.load_compute_driver(self.virtapi, compute_driver)def load_compute_driver(virtapi, compute_driver=None):    if not compute_driver:        compute_driver = CONF.compute_driver    if not compute_driver:        LOG.error(_LE("Compute driver option required, but not specified"))        sys.exit(1)    LOG.info(_LI("Loading compute driver '%s'"), compute_driver)    try:        driver = importutils.import_object_ns('nova.virt',                                              compute_driver,                                              virtapi)        return utils.check_isinstance(driver, ComputeDriver)



0 0