NOVA 创建虚拟机流程

当用户通过身份验证后,需要一个客户端发送创建请求,openstack现在提供两种客户端:

(1)      网页交互界面horizon,通过勾选等方式选择参数后,点击启动按钮进行创建:

(2) 通过CLI命令行指令nova,以及添加一些自定义参数,进行启动:

nova boot  vm_name  --image image_id  --flavor  flavor_id

         其实不论用什么方法,都会转化符合RESTful 的请求api进行请求。

         首先,需要客户端需要先构造一个包含username +password的body,然后通过 HTTP请求(urlhttp://localhost:5000/v2.0/tokens)到keystone中去验证身份。身份验证通过后,返回给客户端一个token_id 和serviceCatalog。至此,客户端才可以向nova-api发起创建请求。当然,客户端向nova-api发送满足REST API 的HTTP创建请求,需要有url请求地址,这个url地址需要通过keystone验证后,通过serviceCatalog 中返回给客户端。

其次,如果nova-pai想要接收发送过来的满足REST的HTTP 的请求,肯定需要有一个HTTP服务器的,那么这个服务器是怎么实现的呢?接下来我们来看一下openstack是如何实现的服务器创建并对外发布服务的呢?我们看下:

         首先程序会找到nova.cmd下的api.py的main()并执行启动。在启动HTTP服务前,会先创建一个WSGIService对象。

defmain():
      ... ...
   
for apiin CONF.enabled_apis:
        should_use_ssl = api
in CONF.enabled_ssl_apis
       
if api =='ec2':
            server =service.WSGIService(api
, use_ssl=should_use_ssl,
                                        
max_url_len=16384)
       
else:
            server =service.WSGIService(api
, use_ssl=should_use_ssl)
         ......
    launcher.wait()

它是基于WSGI标准的服务器类,在启动服务时,启动服务时,需要会将这个WSGIService对象当做参数传过去。

launcher.launch_service(server, workers=server.workers or 1)

那么这个WSGIService中又引用了那些类,实现了那些功能的呢?

WSGIService在构造函数中,通过paste.deploy解析paste.ini配置文件并根据参数name(例如osapi_compute),经过一系列的middleware(fliter)中间件进行处理,最终走到一个application,并将这个加载的app以及一些host、port作为创建 nova.wsgi.py的Server类的参数,最终nova就是通过这个server类以协程方式来对外提供服务。

那么这个application是怎么来的呢?nova.api.openstack.compute.APIRouter.factory()返回 的一个APIRouter实例,这个实例调用其父类的父类nova.wsgi.APIRouter中的成员变量mapper来实现url与controller的映射。根据http请求中的地址找到对应的controller,并实现继承了这个Controller类的子类实例,这个子类实例就是我们要找的具体的application。

到这里我们已经准备好了由server接收HTTP 请求后, 交给这个application去处理。根据请求url我们能找到具体的controller中的具体处理方法,例如我们要实现创建虚拟机,那么就会根据接收过来的请求命令,http://localhost:8774/v2/project_id/servers 。根据/v2 以及paste.ini 配置文件:

[composite:osapi_compute]
use = call:nova.api.openstack.urlmap:urlmap_factory
/: oscomputeversions
/v1.1: openstack_compute_api_v2
/v2: openstack_compute_api_v2
/v3: openstack_compute_api_v3

找到对应的composite:

[composite:openstack_compute_api_v2]
use = call:nova.api.auth:pipeline_factory
noauth = faultwrap sizelimit noauth ratelimit osapi_compute_app_v2
keystone = faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2
keystone_nolimit = faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2

这里是根据nova.api.auth.pipeline_factory() 并经过一系列的filtermiddleware)进行处理后,最后找到wsgi app osapi_compute_app_v2

[app:osapi_compute_app_v2]
paste.app_factory = nova.api.openstack.compute:APIRouter.factory

根据配置返回一个APIRouter实例,这个实例会通过其父类(nova.api.openstack.APIRouter)的父类(nova,wsgi.APIRouter)的成员变量mapper来维护url到controller的映射。最终找到会根据url找到nova.api.openstack.compute.servers.

Controller()类的create()方法。到这里开始正式对创建虚拟机进行处理。

 

nova-api处理模块:

 

1       nova.api.openstack.compute.servers.pyController.create()

主要任务是从传递过的req中获取各种创建虚拟机所需要的参数信息,并做验证,然后将获取的一系列参数(image_uuid,name,insts_type等)作为nova/compute/api.py中的API类的create()方法参数,进行下一步处理。

2        nova.compute.api.py:API.create():

主要任务是对check policiescheck quota、创建db记录,创建下一步中schedule所需要的调度规则信息filter_properties,将部分参数整合,然后将创建请求发送到nova/conductor/api.py中,进行下一步处理。

3       nova.conductor.api.py:ComputeTaskAPI.bulid_instance()

接收有上一步的命令,转发的rpcapi,进行下一步:

nova.conductor.rpcapi.py:ComputeTaskAPI. ComputeTaskAPI()

创建rabbitmq消息队列的client对象,以cast方式发送rpc消息到conductor.manager如何实现发送需细化)进行下一步:

cctxt = self.client.prepare(version='1.5')
cctxt.cast(context, 'build_instances',
           instances=instances, image=image_p ...)

 

nova.conductor.manager.ComputeTaskManager. build_instances()

1) 创建request_spec,供下一步schedule中使用。(request_spec包含虚拟机的类型、数量、uuid等信息)

2) 调用nova/scheduler/rpcapi.pyrun_instance()方法,将请求发送至scheduler中。

 

nova-schduler处理模块:

      

1   nova.scheduler.rpcapi.py:SchedulerAPI.run_instance()

接收到请求后,创建rabbitmq消息队列的client对象,以cast方式发送rpc消息到scheduler.manager,进行进一步处理:

cctxt = self.client.prepare(version=version)
return cctxt.cast(ctxt, 'run_instance', **msg_kwargs)

 

2   nova.schduler.manager.py : SchedulerManager.run_instance()

              收到当SchedulerManager实例化的时候,会根据取得的配置文件取得相应的调度器,默认是FilterScheduler调度器。这个调度器是nova.scheduler.filter_scheduler.

FilterScheduler类的实例。

3       nova.scheduler.filter_scheduler.py:FilterScheduler._scheduler()

1)    通过self.schedule(),经过过滤和权重筛选,最终得到满足条件可以创建出虚拟机的所有host集合--weighted_hosts

 weighed_hosts = self._schedule(context, request_spec,
                                       filter_properties, instance_uuids)

2)      通过self._provision_resource()来进行数据库的更新操作,并通过调用nova/compute/rpcapi.py的run_instance()进行进一步处理

nova-compute处理模块:

1 nova.compute.rpcapi:ComputeAPI.run_instance():

         创建rabbitmq消息队列的client对象,以cast方式发送rpc消息到compute.manager进行下一步处理。

2 nova.compute.manager.py:ComputeManager.run_instance()

根据context中的想信息找到_prebuild_instance()方法中得到image信息。

image_meta =self._prebuild_instance(context,instance)

_prebuild_instance中的

image_meta= _get_image_meta(context,instance['image_ref'])

_get_image_meta():

def_get_image_meta(context,image_ref):
    image_service
, image_id = glance.get_remote_image_service(context,
                                                             
image_ref)
   
return image_service.show(context,image_id)

创建glanceClient对象,通过http call到glance中请求镜像并下载到本地。

获取网络信息:(这里是通过nova-network方式获取网络信息,到neutron请求类似于glance)

         通过调用self._run_instance()中的_build_instance()获取instance和网络信息network_info。

instance, network_info = self._build_instance(context,
        request_spec, filter_properties, requested_networks,
        injected_files, admin_password, is_first_time, node,
        instance, image_meta, legacy_bdm_in_spec)

         在build_instance()通过调用_allocate_network()获得网络信息network_info

network_info = self._allocate_network(context, instance,
        requested_networks, macs, security_groups,
        dhcp_options)

         通过调用self._spawn()并将network_info当做参数,进行虚拟机创建

下面看下如何在_spawn()方法中创建instance:

self.driver = driver.load_compute_driver(self.virtapi, compute_driver)

首先会根据虚拟技术(KVM docker vmware等),先获得对应的driver,这里我们是选择kvm,所以driver会找到nova/virt/libvirt/dirver.py

self.driver.spawn(context, instance, image_meta,
                  injected_files, admin_password,
                   … …)

nova-driver处理模块:

3        nova.virt.libvirt.driver.py:LibvirtDriver.spawn()

1)  获取磁盘相关信息

disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, instance,...

2)  创建实例镜像

self._create_image(context, instance,...

3)  为新建的实例参数获取配置数据conf,并把conf 的配置信息文件转化成所需xml格式的文件。

xml = self.to_xml(context, instance, network_info ,...

4)  获取网络和域等相关信息

elf._create_domain_and_network(context, xml, instance, network_info,...

5)_wait_for_boot函数等待libvirt进行虚拟机启动操作。



参考文档:

http://blog.csdn.net/xuriwuyun/article/details/16845601?utm_source=tuicool&utm_medium=referral

http://blog.csdn.net/xuriwuyun/article/details/37497619

http://www.cnblogs.com/popsuper1982/p/3927390.html

http://blog.csdn.net/xuriwuyun/article/details/16845601

http://www.cnblogs.com/juandx/p/4953191.html

http://blog.csdn.net/bingxx11/article/details/19110101


附官方流程:




1. dashboard 或是 CLI 从用户处获得认证信息(用户名及密码),然后转成REST 的API 发送给 Keystone,并等待返回结果。Keystone会返回一个token, 然后用于后续的操作。

2. dashboard 或是 CLI 使用上步的token发送基于REST的创建Instance的命令给nova-api。

3. nova-api 使用token对操作的API进行权限认证。

4. nova-api 根据当前参数和数据据进行比较,检查冲突项。并且会在数据库中 建立一条记录

5. nova-api 发送RPC请求到queue, 交给调度器(Scheduler)处理

6. 调度器从queue里把消息取出来

7. 调度器根据各种Filter来进行筛选,从有效的主机中选出一个可用的主机。并且发送RPC请求到queue中。

8. 本地的主机从queue中取出RCP请求消息

9. nova-computer发送RPC请求给nova-conductor获取host相关的信息,并且更新数据库中instance的状态

10. nova-conductor取出消息

11. nova-conductor从数据库中取出信息并且返回给nova-computer

12. nova-computer发送REST请求给Glance, 用以获取Image的信息并且从Image的存储设备上下载对应的Image

13. Glance通过token去Kenstone进行认证,并且下载Image到Host

14. nova-computer发送REST请求给Neutron获取网络相关信息

15. Neutron通过token去Kenstone进行认证,并返回相关信息

16. nova-computer发送REST请求Cinder获取硬盘相关的信息

17. Cinder通过token去Kenstone进行认证,并返回相关信息

18. nova-computer生成相关的信息,然后调用Hyervisor去启动Instance



猜你喜欢

转载自blog.csdn.net/u014007037/article/details/50453893