本文试图具体地描写叙述openstack建立虚拟机的完整过程。从用户发起请求到虚拟机成功执行,包含client请求的发出、keystone身份验证、nova-api接收请求、nova-scheduler调度、nova-computer建立、nova-network分配网络。对于每一个模块在建立虚拟机的过程当中所负责的功能和执行的操做,进行较为具体描写叙述和讨论。为了方便描写叙述,本文若是所有的服务ip地址为localhost。port使用服务的默认设置port。openstack为O版。下图为建立虚拟机的一个大概流程图,粗糙地表示下。接下来将对每一个模块进行具体介绍。若有错误,欢迎拍砖!html
clientnode
建立虚拟机的第一步是需要client调用nova-api,发送建立虚拟机请求。眼下openstack提供两种client:python
1 命令行指令nova,经过指定命令行參数。就可以请求nova-api建立虚拟机,一个最简单的建立虚拟机指令例如如下:web
nova boot vm_name --flavor flavor_id --image image_uuid --nic net-id = network_id
eg:nova boot --flavor m1.nano --image cirros \
--security-groups default --key-name mykey --nic net-id=a31d6a9a-a73f-4a19-a252-10d0b7e64d1d \
test2算法
2 网页交互页面horizon,这是经过web操做页面来调用nova-api建立虚拟机,比較简单易用。选定相关參数后。点击create就可以了。shell
这两种client除了UI不同之外,功能方面基本都是同样。数据库
就建立虚拟机来说。它们需要完毕:api
{"auth": { "passwordCredentials": {"username": self.user, "password": self.password}} "tenantName": "admin" }向keystone发送HTTP请求(keystone的服务地址:nova命令通常经过环境变量OS_AUTH_URL设置,horizon则经过openstack_dashboard.local.local_settings.OPENSTACK_KEYSTONE_URL设置),url为http://localhost:5000/v2.0/tokens 。假设验证经过,keystone则返回token_id和serviceCatalog。身份验证经过后。client才可对nova-api发送建立请求。
因为client只配置了keystone的服务地址和port,对于nova-api的服务地址它是不知道的。因此需要先经过keystone验证,而后由keystone将nova-api的服务地址放在serviceCatalog中返回给它。事实上serviceCatalog中不仅包括nova-api的服务地址,还有glance-api、cinder-api等服务的地址,这些地址在之后的镜像下载、块存储请求时会用到。token_id被放在请求nova-api的headers中。用做nova-api验证。网络
对于nova boot,flavor_id和image_uuid需要经过命令行參数指定,novaclient.v1_1.shell._boot()分别向nova-api的"http://localhost:8774/v2/project_id/flavors/flavor_id"和"http://localhost:8774/v2/project_id/images/image_id"发送HTTP请求,验证资源是否存在。对于horizon,它首先运行horizon.api.nova.flavor_list()和horizon.api.glance.image_list_detailed(),获取所有可用的flavor ids和image ids,建立虚拟机时仅仅能从这些可用的id中选择。框架
注意这里nova boot和horizon对于image的验证有些不一样,nova boot是请求nova-api,nova-api再请求glance-api以验证image uuid,而horizon是直接请求glance-api获取所有的image ids。
关于body的模样,可看看novaclient.v1_1.BootingManagerWithFind._boot() 。以上面的nova boot命令为例,body内容例如如下:
{'server': {'flavorRef': '1', 'hypervisor_type': 'QEMU', 'imageRef': 'd3670457-16f5-4c70-913f-6fc7b76706e4', 'max_count': 1, 'min_count': 1, 'name': 'test-ic'}}这里的flavorRef相应的是数据库instance_types的flavorid字段(非id字段),上面命令行传入的flavor_id也是指数据库的flavorid字段。向nova-api的http://localhost:8774/v2/project_id/flavors/flavorid请求时,它经过nova.api.openstack.compute.views.flavors.ViewBuilder,将数据库的id字段做为instance_type_id。将flavorid做为id进行返回的。
可以看出,无论nova boot仍是horizon,最后都是经过novaclient向nova-api发送请求的。
novaclient是针对nova-api作了一层封装,如获取验证token-id,以特定的格式构造HTTP请求headers和body,解析请求的结果等。事实上可以不用nova boot命令行和horizon,甚至novaclient都不需要,咱们全然可以设定好HTTP请求的headers和body,直接请求nova-api。只是这三个工具将这些繁琐的工做替咱们作了。咱们仅仅需要填写參数就可以了。最后注意下。nova命令事实上仅仅是novaclient的一个entry point:novaclient.shell.main()。而nova boot实际上调用的是novaclient.v1_1.shell.do_boot()。
keystone
由上可知,在client发起建立虚拟机请求时,keystone需要对client的username和password进行验证。keystone-all与nova-api同样,api的公布没有採用不论什么框架,而是使用router、paste类库。从头写的,实现风格上又与nova-api有点差别。
keystone-all服务会监听两个port:localhost:5000,即publicURL。通常用户使用password可以訪问;localhost:35357。即adminURL,仅仅能使用admin帐户和password訪问。
在建立虚拟机流程中,调用的keystone的api有两个(事实上,每次请求基本都会调用这两个api):
1 http://localhost:5000/v2.0/tokens,请求该api来获取token_id和serviceCatalog,由client调用。keystone会将该api的请求交给keystone.TokenController.authenticate()处理。该函数主要完毕:
2 http://localhost:35357/v2.0/tokens/token_id,对请求的token_id进行验证。由nova-api调用。nova-api接收到请求后。首先使用请求携带的token_id来訪问该api,以验证请求是否经过验证。
固然nova-api需要在body里加上admin的帐户和password信息,这些信息需要在api-paste.ini中配置。还有keystone的服务地址,因为在验证没经过以前。不能使用client传过来的endpoints。glance-api、cinder-api等在接收到client请求后。都会调用该api对client的token_id进行验证。
该api的请求交给keystone.TokenController.validate_token()处理,事实上就是使用请求的token_id进行一次数据库查询。
nova-api
nova-api是一个统称,它是一类服务的集合。如openstack之nova-api服务流程分析所说,在默认配置下,它包括ec2(与EC2兼容的API)。osapi_compute(openstack compute本身风格的API),osapi_volume(openstack volume服务API)。metadata(metadata 服务API)等api服务。每个服务提供不一样的api,只是尽管ec2和osapi_compute的api不一样。但功能是一样的。这里,建立虚拟机请求的api是:
http://localhost:8774/v2/project_id/servers。由osapi_compute服务公布。该api是RESTFUL的,以POST方法请求该api。通过几层middleware处理后,终于交给nova.api.openstack.compute.servers.Controller.create()处理。
它们主要完毕下面功能:
如。检查虚拟机name是否符合命名规范。flavor_id是否在数据库中存在,image_uuid是不是正确的uuid格式等。
每个project拥有的资源都是有限的,如建立虚拟机的个数,vcpu个数,内存大小。volume个数等。
默认状况下。所有project的拥有的资源数量相等,由quota_instances、quota_cores、quota_ram、quota_volumes等配置项指定。使用admin帐户。以PUT方法请求http://localhost:8774/v2/admin_project/os-quota-sets/project_id。可为特定的project设置配额。
普通状况下,该參数也为空,由network本身主动分配。
并推断flavor是否知足该image的最小配置需求,如内存,虚拟磁盘是否知足image的最小值。
经过rpc call,将所有參数传给nova-scheduler的nova.scheduler.manager.SchedulerManager.run_instance()。由它运行虚拟机调度。
在token_id验证经过的状况下。nova-api的主要任务是资源配额和參数检查,并建立数据库。
假设你使用dashboard,此时你在页面上将会看到虚拟机处于scheduling状态。只是该状态持续时间很是短,差点儿察觉不到,除非nova-scheduler出问题了。
nova-scheduler
与nova-api提供外部服务不一样。nova各组件之间相互调用,使用的是以rabbitmq做为消息队列的RPC调用。这里忽略RPC的实现细节。仅仅需知道rcp call调用哪一个的节点的哪一个服务就可以了。nova-scheduler的run_instance()从nova-api接收到的參数中仅仅使用到了request_spec和filter_properties,其他參数将直接传递给nova-compute去建立虚拟机。request_spec包括虚拟机的type、number、uuids等信息,在调度中需要用这些信息做为參考。
filter_properties包括指定调度规则信息,如force_hosts指定调度到特定的节点,ignore_hosts不调度到某些节点等。nova-scheduler在接收到nova-api的请求后。由nova.scheduler.filter_scheduler.FilterScheduler.scheduler_run_instances(),它主要完毕下面任务:
后面的版本号可能认为使用Weigher。又使用WeigherHander。仅仅是对内存大小作排序。有点小题大作了,在2012.2.4中用一个函数nova.scheduler.least_cost.weighted_sum()就实现排序。但在2013.2中又回到原来的结构了。
nova-scheduler相对而言,逻辑比較简单。代码也不难。只是需要注意在node-scheduler运行过程当中,不会改变虚拟机的vm_state和tast_state。
因此在horizon上也不会有变化。
nova-compute
nova-scheduler选定host后,随即经过rpc调用,调用host的nova-compute服务的nova.compute.manager.ComputeManager.run_instance()。
由它运行真正的建立虚拟机操做。只是在介绍以前,需要简单说起一下nova-compute的两个定时任务:
而后从数据库中查找到执行在该节点上的所有虚拟机信息,统计出这些虚拟机所使用的vcpu个数、内存大小、磁盘大小。并将计算节点的总资源数量减去虚拟机使用的数量,获得空暇内存大小和空暇磁盘大小。而后更新数据库compute_node信息。这里需要注意从数据库中获取的虚拟机使用资源数量并不是必定是计算节点消耗的资源数量,如1)虚拟机使用磁盘镜像为qcow2格式时,它的大小要小于或等于实际分配的大小。2)也有可能因为数据不一样步,使得统计的数据与实际的资源使用不一致。
该任务是用于定时更新当前计算节点的capabilities信息,相同也是经过LibvirtDriver来获取资源数据的,只是在计算已使用资源方面,是直接使用经过调用multiprocessing、libvirt、os等返回的cpu个数、内存、磁盘使用状况。并附加上host_ip信息。并由定时任务_publish_service_capabilities经过rpc call转发到nova.scheduler.host_manager.HostManager.service_states中。
这两个定时任务为nova-scheduler提供了实时的host信息。因此才干实现准确调度。由于capabilities信息与compute_node表中信息有很是大的类似度,因此调度过程当中很是少用到。
nova-scheduler调度到nova-compute的run_instance()主要完毕什么功能呢:
对于image,通常採用qcow2格式,做为qemu-img的backing_file新建一个image使用,这样可以节约空间。
原理比較简单,将下载的image使用mount命令进行挂载,而后将要写入的内容下到特定的位置。
这里network採用 FlatDHCP模式,multihost=True。查看代码可知 FlatDHCPManager继承RPCAllocateFixedIP, FloatingIP, NetworkManager三个class,依据python属性訪问流程(參考python对象之属性訪问流程)可知,调用FlatDHCPManger.allocate_for_instance()首先运行FloatingIP.allocate_for_instance(),再由它调用NetworkManger.allocate_for_instance()。主要完毕任务例如如下:
这样就可以经过floating ip从外部訪问虚拟机了。