先粗略了解一下nova创建虚拟机的四个核心模块
- api服务:负责处理客户端发送的http请求,路由到具体调用函数(包括一些中间件处理,如鉴权)
- conductor服务:主要用于数据库的访问,为数据库访问提供安全保障,同时使compute服务与数据库解耦,目前compute服务所有的访问数据库的操作都要交给conductor完成,conductor服务和compute服务也最好要分开部署在不同服务器上,以保证数据库的安全性。同时也抽离出原本compute服务中的TaskAPI任务(主要包含比较耗时的任务),比如创建虚拟机,迁移虚拟机等操作。
- scheduler服务:挑选合适的虚拟机。可以有多种调度器,但是只能选择一种调度器,需要在/etc/nova/nova.conf中通过 scheduler_driver指定,默认使用FilterScheduler(包含filters和weighting两个步骤,filters依据指定条件过滤不合格主机,再通过weighting对筛选后的主机列表进行权重排序找出最优主机)
- compute服务:管理虚拟机的生命周期。
源代码(liberty版本):
def build_instances(self, context, instances, image, filter_properties,
admin_password, injected_files, requested_networks,
security_groups, block_device_mapping=None, legacy_bdm=True):
# TODO(ndipanov): Remove block_device_mapping and legacy_bdm in version
# 2.0 of the RPC API.
request_spec = scheduler_utils.build_request_spec(context, image,
instances)
# TODO(danms): Remove this in version 2.0 of the RPC API
if (requested_networks and
not isinstance(requested_networks,
objects.NetworkRequestList)):
requested_networks = objects.NetworkRequestList(
objects=[objects.NetworkRequest.from_tuple(t)
for t in requested_networks])
# TODO(melwitt): Remove this in version 2.0 of the RPC API
flavor = filter_properties.get('instance_type')
if flavor and not isinstance(flavor, objects.Flavor):
# Code downstream may expect extra_specs to be populated since it
# is receiving an object, so lookup the flavor to ensure this.
flavor = objects.Flavor.get_by_id(context, flavor['id'])
filter_properties = dict(filter_properties, instance_type=flavor)
try:
scheduler_utils.setup_instance_group(context, request_spec,
filter_properties)
# check retry policy. Rather ugly use of instances[0]...
# but if we've exceeded max retries... then we really only
# have a single instance.
scheduler_utils.populate_retry(filter_properties,
instances[0].uuid)
hosts = self.scheduler_client.select_destinations(context,
request_spec, filter_properties)
except Exception as exc:
updates = {'vm_state': vm_states.ERROR, 'task_state': None}
for instance in instances:
self._set_vm_state_and_notify(
context, instance.uuid, 'build_instances', updates,
exc, request_spec)
return
for (instance, host) in itertools.izip(instances, hosts):
try:
instance.refresh()
except (exception.InstanceNotFound,
exception.InstanceInfoCacheNotFound):
LOG.debug('Instance deleted during build', instance=instance)
continue
local_filter_props = copy.deepcopy(filter_properties)
scheduler_utils.populate_filter_properties(local_filter_props,
host)
# The block_device_mapping passed from the api doesn't contain
# instance specific information
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
context, instance.uuid)
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'])
创建流程:
1,nova-api接到客户端的创建请求
2,nova-api通过RPC cast方式调用conductor的build_instances方法
3,conductor的build_instances通过RPC call调用scheduler的select_destinations方法选择合适的目标主机
4,通过scheduler返回的主机信息,通过RPC cast调用compute的build_and_run_instance方法,完成虚拟机的创建
附:
1,[rpc client调用方式]rpc server会在服务启动时注册 ,cast和call是rpcclient的两种调用方法,区别在于cast相当于一种异步形式,call同步,所以耗时长的一般采用cast方法(实现于oslo_messaging中)
调用方式:
cctxt = self.client.prepare(server=_compute_host(None, instance),
version=version)
return cctxt.call(ctxt, 'get_serial_console',
instance=instance, console_type=console_type)
call的第二个参数为rpc调用函数名,后面的为该调用函数的参数。