一.nova架构
nova是openstack最核心的服务,负责维护和管理云环境的计算资源。因此,云主机的整个生命周期都是由nova负责的。
1.1 nova-api
负责接收和相应客户的API调用。
1.2 compute core
nova-schedule
负责决定在哪个计算节点运行虚拟机。
nova-compute
通过调用Hypervisor实现虚拟机生命周期的管理。一般运行在计算节点。
hypervisor
对虚拟机进行硬件虚拟化的管理软件,比如KVM和VMWare等。
nova-conductor
由于nova-compute需要不断对数据库进行更新,比如更新虚拟机状态,为了安全性和伸缩性的考虑,通过nova-conductor间接实现数据库的访问。
1.3 database
一般使用MYSQL,安装在控制节点上,因为nova有一些数据需要存储在database中。
1.4 Message Queue
用于nova各个子服务之间的通讯,一般使用的是RabbitMQ,从而解耦各个子服务。
二.nova创建主机源码剖析
1.nova-api进程执行过程:
a. nova:api:openstack:compute:servers.py:ServersController:create():
通过用户发送的api数据中的req和body信息来解析需要的有关云主机的数据,比如云主机类型(inst_type),镜像id(image_uuid),主机聚合(availability_zone),强制使用的主机以及节点(forced_host,forced_node),元数据(metadata),连接的网络(requested_networks)等,然后调用nova:compute:api.py:API:create()来正式开始创建云主机,最后向用户返回响应结果。
def create(self, req, body):
"""Creates a new server for a given user."""
context = req.environ['nova.context']
server_dict = body['server']
password = self._get_server_admin_password(server_dict)
name = common.normalize_name(server_dict['name'])
description = name
if api_version_request.is_supported(req, min_version='2.19'):
description = server_dict.get('description')
# Arguments to be passed to instance create function
create_kwargs = {}
# TODO(alex_xu): This is for back-compatible with stevedore
# extension interface. But the final goal is that merging
# all of extended code into ServersController.
self._create_by_func_list(server_dict, create_kwargs, body)
availability_zone = server_dict.pop("availability_zone", None)
if api_version_request.is_supported(req, min_version='2.52'):
create_kwargs['tags'] = server_dict.get('tags')
helpers.translate_attributes(helpers.CREATE,
server_dict, create_kwargs)
target = {
'project_id': context.project_id,
'user_id': context.user_id,
'availability_zone': availability_zone}
context.can(server_policies.SERVERS % 'create', target)
# TODO(Shao He, Feng) move this policy check to os-availability-zone
# extension after refactor it.
parse_az = self.compute_api.parse_availability_zone
try:
availability_zone, host, node = parse_az(context,
availability_zone)
except exception.InvalidInput as err:
raise exc.HTTPBadRequest(explanation=six.text_type(err))
if host or node:
context.can(server_policies.SERVERS % 'create:forced_host', {})
# NOTE(danms): Don't require an answer from all cells here, as
# we assume that if a cell isn't reporting we won't schedule into
# it anyway. A bit of a gamble, but a reasonable one.
min_compute_version = service_obj.get_minimum_version_all_cells(
nova_context.get_admin_context(), ['nova-compute'])
supports_device_tagging = (min_compute_version >=
DEVICE_TAGGING_MIN_COMPUTE_VERSION)
block_device_mapping = create_kwargs.get("block_device_mapping")
# TODO(Shao He, Feng) move this policy check to os-block-device-mapping
# extension after refactor it.
if block_device_mapping:
context.can(server_policies.SERVERS % 'create:attach_volume',
target)
for bdm in block_device_mapping:
if bdm.get('tag', None) and not supports_device_tagging:
msg = _('Block device tags are not yet supported.')
raise exc.HTTPBadRequest(explanation=msg)
image_uuid = self._image_from_req_data(server_dict, create_kwargs)
# NOTE(cyeoh): Although upper layer can set the value of
# return_reservation_id in order to request that a reservation
# id be returned to the client instead of the newly created
# instance information we do not want to pass this parameter
# to the compute create call which always returns both. We use
# this flag after the instance create call to determine what
# to return to the client
return_reservation_id = create_kwargs.pop('return_reservation_id',
False)
req