博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
nova创建虚拟机的过程(二)
阅读量:6816 次
发布时间:2019-06-26

本文共 9299 字,大约阅读时间需要 30 分钟。

hot3.png

总体描述:

164342_AptC_553781.png

1.  创建实例接口

还是先看接口API

REQ:  curl \-i 'http://ubuntu80:8774/v2/0e962df9db3f4469b3d9bfbc5ffdaf7e/servers' \-X POST -H "Accept: application/json" \-H "Content-Type: application/json"   \ -H "User-Agent: python-novaclient"    \-H "X-Auth-Project-Id: admin"         \-H "X-Auth-Token: {SHA1}e87219521f61238b143fbb323b962930380ce022" \-d '{"server": {"name": "ubuntu_test", "imageRef": "cde1d850-65bb-48f6-8ee9-b990c7ccf158", "flavorRef": "2", "max_count": 1, "min_count": 1, "networks": [{"uuid": "cfa25cef-96c3-46f1-8522-d9518eb5a451"}]}}'

这里对应的依然是Controller

具体位置为:

nova.api.openstack.compute.servers.Controller.create

注意这个方法的装饰器有一个@wsgi.response(202),而根据HTTP协议状态码返回202表示服务器已接受请求,但尚未处理,表明这是一个异步任务。

最终此方法调用的self.compute_api.create(...)是由__init__(...)中的self.compute_api = compute.API()获取。

因此compute.API()对应到nova.compute.api.API.create(...),其内部又调用nova.compute.api.API._create_instance(...)

就在nova.compute.api.API._create_instance(...)里面重点来了。

2. 任务状态第一次变化为SCHEDULING

nova.compute.api.API._create_instance(...)里有一步调用:

instances = self._provision_instances(context, instance_type,                min_count, max_count, base_options, boot_meta, security_groups,                block_device_mapping, shutdown_terminate,                instance_group, check_server_group_quota)

这一方法的位置是nova.compute.api.API._provision_instances,其内部有如下调用:

instance = self.create_db_entry_for_new_instance(...)

而在nova.compute.api.API.create_db_entry_for_new_instance对应self.create_db_entry_for_new_instance(...)),有如下调用:

self._populate_instance_for_create(context, instance, image, index,                                           security_group, instance_type)

其对应的是nova.compute.api.API._populate_instance_for_create,内部第一次将任务状态置为调度:

instance.vm_state = vm_states.BUILDINGinstance.task_state = task_states.SCHEDULING

那么回到_provision_instances方法,主要是申请了配额。

3. 由nova-api到nova-conductor

nova.compute.api.API._create_instance(...)里有一步调用:

self.compute_task_api.build_instances(context,                instances=instances, image=boot_meta,                filter_properties=filter_properties,                admin_password=admin_password,                injected_files=injected_files,                requested_networks=requested_networks,                security_groups=security_groups,                block_device_mapping=block_device_mapping,                legacy_bdm=False)

从这一步开始离开nova-api,nova-api调用的是nova-conductor,nova-scheduler和nova-compute中的方法。

    @property    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

4. nova-conductor调用nova-scheduler和nova-compute

这边已经来到conductor部分,位置为nova.conductor.ComputeTaskAPI

def 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)

这里use_local是默认置为False,这里默认调用的是

api = conductor_api.LocalComputeTaskAPI

它的位置是nova.conductor.LocalComputeTaskAPI在它的构造函数(__init__(...))中有manager.ComputeTaskManager即nova.conductor.ComputeTaskManager

这个类的build_instances方法,位置(nova.conductor.ComputeTaskManager.build_instances(...)):

nova-conductor会在build_instances()中生成request_spec字典,

request_spec = scheduler_utils.build_request_spec(...)

其中包括了详细的虚拟机信息,nova-scheduler依据这些信息为虚拟机选择一个最佳的主机,

hosts = self.scheduler_client.select_destiation(... , request_spec, ...)

然后nova-conductor再通过RPC调用nova-compute创建虚拟机

            self.compute_rpcapi.build_and_run_instance(context,                    instance=instance, host=host['host'], image=image,                    request_spec=request_spec,                    filter_properties=local_filter_props,                    admin_password=admin_password,                    injected_files=injected_files,                    requested_networks=requested_networks,                    security_groups=security_groups,                    block_device_mapping=bdms, node=host['nodename'],                    limits=host['limits'])

这里调用的是nova.compute.rpcapi.ComputeAPI.build_and_run_instance

其中可以看到,调用的是'build_and_run_instance',而cctxt.cast(...)是异步远程调用(调用后不立即返回),详细可以搜索oslo.messaging模块的使用

        cctxt.cast(ctxt, 'build_and_run_instance', instance=instance,                image=image, request_spec=request_spec,                filter_properties=filter_properties,                admin_password=admin_password,                injected_files=injected_files,                requested_networks=requested_networks,                security_groups=security_groups,                block_device_mapping=block_device_mapping, node=node,                limits=limits)

调用对应的是nova.compute.manager.build_and_run_instance(...),其内部调用(注意:使用的是spawn方式调用)的是_do_build_and_run_instance(...)。

_do_build_and_run_instance(...)内部主要的调用为_build_and_run_instance函数(nova.compute.manager._build_and_run_instance(...)):

5. 建立和运行实例 

定位到nova.compute.manager._build_and_run_instance(...)之后,看到如下代码:

    def _build_and_run_instance(self, context, instance, image, injected_files,            admin_password, requested_networks, security_groups,            block_device_mapping, node, limits, filter_properties):        image_name = image.get('name')        self._notify_about_instance_usage(context, instance, 'create.start',                extra_usage_info={'image_name': image_name})        try:            # 资源跟踪器            rt = self._get_resource_tracker(node)            with rt.instance_claim(context, instance, limits) as inst_claim:                # NOTE(russellb) It's important that this validation be done                # *after* the resource tracker instance claim, as that is where                # the host is set on the instance.                self._validate_instance_group_policy(context, instance,                        filter_properties)                # 分配资源,包括网络和存储,在内部                # 任务状态由task_states.SPAWNING变为task_states.NETWORKING再                # 变成task_states.BLOCK_DEVICE_MAPPING                with self._build_resources(context, instance,                        requested_networks, security_groups, image,                        block_device_mapping) as resources:                    instance.vm_state = vm_states.BUILDING                    # 任务状态变为孵化中                    instance.task_state = task_states.SPAWNING                    instance.numa_topology = inst_claim.claimed_numa_topology                    instance.save(expected_task_state=                            task_states.BLOCK_DEVICE_MAPPING)                    block_device_info = resources['block_device_info']                    network_info = resources['network_info']                    # 调用底层virt api孵化实例                    self.driver.spawn(context, instance, image,                                      injected_files, admin_password,                                      network_info=network_info,                                      block_device_info=block_device_info)        except ...:        # NOTE(alaski): This is only useful during reschedules, remove it now.        instance.system_metadata.pop('network_allocated', None)        # 查看实例电源状态        instance.power_state = self._get_power_state(context, instance)        # 开启实例电源(开机)        instance.vm_state = vm_states.ACTIVE        # 任务状态清空        instance.task_state = None        # 实例内部时间操作        instance.launched_at = timeutils.utcnow()        try:            instance.save(expected_task_state=task_states.SPAWNING)        except (exception.InstanceNotFound,                exception.UnexpectedDeletingTaskStateError) as e:            with excutils.save_and_reraise_exception():                self._notify_about_instance_usage(context, instance,                    'create.end', fault=e)        # 通知创建过程结束        self._notify_about_instance_usage(context, instance, 'create.end',                extra_usage_info={'message': _('Success')},                network_info=network_info)

第一步就是建立一个资源跟踪器(RT: Resource Tracker),注意,RT分为索要跟踪器(Claim RT)和周期跟踪器(Periodic RT),当然我们还可以自己扩展插件叫扩展跟踪器(Extensible RT)。

顾名思义,在_build_and_run_instance函数中建立的RT是索要(claim)跟踪器,对计算节点上的资源进行核实,如果资源分配失败,会抛出异常。

            rt = self._get_resource_tracker(node)            with rt.instance_claim(context, instance, limits) as inst_claim:

这里还要提到_build_resources函数,在这个函数里instance.task_state状态

task_states.SCHEDULING变为task_states.NETWORKING再变成task_states.BLOCK_DEVICE_MAPPING

self._build_resources(context, instance,                        requested_networks, security_groups, image,                        block_device_mapping)

待资源分配完成,任务状态由task_states.BLOCK_DEVICE_MAPPING转变为task_states.SPAWNING

instance.task_state = task_states.SPAWNING

当一切准备完毕时,调用self.driver.spawn孵化实例,底层则是Libvirt部分,启动孵化过程

                    self.driver.spawn(context, instance, image,                                      injected_files, admin_password,                                      network_info=network_info,                                      block_device_info=block_device_info)

之后做的就是开机,对时,通知创建过程结束,成功!

转载请保留出处,谢谢!

nova创建虚拟机的过程(一): 

nova创建虚拟机的过程(二):  

转载于:https://my.oschina.net/crooner/blog/632851

你可能感兴趣的文章
Javascript模板引擎handlebars使用实例及技巧
查看>>
GoldenGate测试(七)
查看>>
动态访问DetailsView内的控件
查看>>
[珠玑之椟]位向量/位图的定义和应用
查看>>
数据对齐
查看>>
linux设置 让oracle10g自启动
查看>>
用JQuery给图片添加鼠标移入移出事件
查看>>
ALTER TABLE & ALTER TYPES
查看>>
Hadoop-调优剖析
查看>>
Mac前端抓包小工具Charles4.0下载
查看>>
用AHP层次分析法挑选最佳结婚对象
查看>>
Subversion安装手记
查看>>
Linux 获取设备树源文件(DTS)里描述的资源【转】
查看>>
Effective C++ 阅读笔记(二)public继承与继承中的函数覆盖
查看>>
什么是UV?
查看>>
Stringbuffer与Stringbuilder源码学习和对比
查看>>
Centos 学习大纲
查看>>
解读固态磁盘性能发展之现状
查看>>
CFO职能扩张 CIO将面临更大数据压力
查看>>
区块链之路该怎么走?
查看>>