nova-compute是管理和配置虚拟机的入口,在所有compute机器上都需要该服务来创建和管理虚拟机。

nova-compute服务的入口在 nova.cmd.compute:main ,其启动过程与其他nova服务类似。

简单看下它是如何启动的, binary='nova-compute', topic='nova.compute.rpcapi' ,  manager=nova.compute.manager.ComputeManager ,manager类在初始化的时候会创建与其他服务交互的api实例:

class ComputeManager(manager.Manager):
"""Manages the running instances from creation to destruction.""" target = messaging.Target(version='3.32') def __init__(self, compute_driver=None, *args, **kwargs):
"""Load configuration options and connect to the hypervisor."""
self.virtapi = ComputeVirtAPI(self)
self.network_api = network.API()
self.volume_api = volume.API()
self.image_api = image.API()
self._last_host_check = 0
self._last_bw_usage_poll = 0
self._bw_usage_supported = True
self._last_bw_usage_cell_update = 0
self.compute_api = compute.API()
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
self.conductor_api = conductor.API()
self.compute_task_api = conductor.ComputeTaskAPI()
self.is_neutron_security_groups = (
openstack_driver.is_neutron_security_groups())
self.consoleauth_rpcapi = consoleauth.rpcapi.ConsoleAuthAPI()
self.cells_rpcapi = cells_rpcapi.CellsAPI()
self.scheduler_rpcapi = scheduler_rpcapi.SchedulerAPI()
self._resource_tracker_dict = {}
self.instance_events = InstanceEvents() super(ComputeManager, self).__init__(service_name="compute",
*args, **kwargs) # NOTE(russellb) Load the driver last. It may call back into the
# compute manager via the virtapi, so we want it to be fully
# initialized before that happens.
self.driver = driver.load_compute_driver(self.virtapi, compute_driver) #libvirt.LibvirtDriver
self.use_legacy_block_device_info = \
self.driver.need_legacy_block_device_info

在service.start()中会初始化主机上的虚拟机和安全组,并开启RPC服务

    def start(self):
verstr = version.version_string_with_package()
LOG.audit(_('Starting %(topic)s node (version %(version)s)'),
{'topic': self.topic, 'version': verstr})
self.basic_config_check()
# Initialization for a standalone compute service
# init instances and iptables
self.manager.init_host()
self.model_disconnected = False
ctxt = context.get_admin_context()
try: # init conductor api
self.service_ref = self.conductor_api.service_get_by_args(ctxt,
self.host, self.binary)
self.service_id = self.service_ref['id']
except exception.NotFound:
try:
self.service_ref = self._create_service_ref(ctxt)
except (exception.ServiceTopicExists,
exception.ServiceBinaryExists):
# NOTE(danms): If we race to create a record with a sibling
# worker, don't fail here.
self.service_ref = self.conductor_api.service_get_by_args(ctxt,
self.host, self.binary) """After the service is initialized, but before we fully bring
the service up by listening on RPC queues, make sure to update
our available resources (and indirectly our available nodes).
"""
self.manager.pre_start_hook() if self.backdoor_port is not None:
self.manager.backdoor_port = self.backdoor_port LOG.debug("Creating RPC server for service %s", self.topic) # start rpc api
target = messaging.Target(topic=self.topic, server=self.host) endpoints = [
self.manager,
baserpc.BaseRPCAPI(self.manager.service_name, self.backdoor_port)
]
endpoints.extend(self.manager.additional_endpoints) serializer = objects_base.NovaObjectSerializer() self.rpcserver = rpc.get_server(target, endpoints, serializer)
self.rpcserver.start() self.manager.post_start_hook() LOG.debug("Join ServiceGroup membership for this service %s",
self.topic)
# Add service to the ServiceGroup membership group.
self.servicegroup_api.join(self.host, self.topic, self) if self.periodic_enable:
if self.periodic_fuzzy_delay:
initial_delay = random.randint(0, self.periodic_fuzzy_delay)
else:
initial_delay = None self.tg.add_dynamic_timer(self.periodic_tasks,
initial_delay=initial_delay,
periodic_interval_max=
self.periodic_interval_max)

这样,nova-compute服务就起来了,而之后接收到的请求都会到 nova.compute.manager.ComputeManager 类来处理。

最常使用的KVM虚拟化需要配置driver为libvirt.LibvirtDriver(所有支持的driver有 libvirt.LibvirtDriver, xenapi.XenAPIDriver, fake.FakeDriver, baremetal.BareMetalDriver, vmwareapi.VMwareVCDriver, hyperv.HyperVDriver).

下面来看看libvirt是如何创建虚拟机的:

   def spawn(self, context, instance, image_meta, injected_files,
admin_password, network_info=None, block_device_info=None):
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
instance,
block_device_info,
image_meta)
# 获取镜像信息
self._create_image(context, instance,
disk_info['mapping'],
network_info=network_info,
block_device_info=block_device_info,
files=injected_files,
admin_pass=admin_password)
# 生成libvirt配置文件格式的XML
xml = self._get_guest_xml(context, instance, network_info,
disk_info, image_meta,
block_device_info=block_device_info,
write_to_disk=True)
# 创建卷、网络,并创建虚拟机
self._create_domain_and_network(context, xml, instance, network_info,
block_device_info)
LOG.debug("Instance is running", instance=instance) def _wait_for_boot():
"""Called at an interval until the VM is running."""
state = self.get_info(instance)['state'] if state == power_state.RUNNING:
LOG.info(_LI("Instance spawned successfully."),
instance=instance)
raise loopingcall.LoopingCallDone()
# 等待虚拟机状态变为RUNNING
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_boot)
timer.start(interval=0.5).wait()
_create_domain_and_network为实际的创建设备和创建虚拟机函数
   def _create_domain_and_network(self, context, xml, instance, network_info,
block_device_info=None, power_on=True,
reboot=False, vifs_already_plugged=False): """Do required network setup and create domain."""
# 查询卷的映射关系
block_device_mapping = driver.block_device_info_get_mapping(
block_device_info)
# 挂载卷
for vol in block_device_mapping:
connection_info = vol['connection_info']
disk_info = blockinfo.get_info_from_bdm(
CONF.libvirt.virt_type, vol)
# 根据volume类型,调用其connect_volume方法挂载卷
# 支持的类型包括:
# [
# 'iscsi=nova.virt.libvirt.volume.LibvirtISCSIVolumeDriver',
# 'iser=nova.virt.libvirt.volume.LibvirtISERVolumeDriver',
# 'local=nova.virt.libvirt.volume.LibvirtVolumeDriver',
# 'fake=nova.virt.libvirt.volume.LibvirtFakeVolumeDriver',
# 'rbd=nova.virt.libvirt.volume.LibvirtNetVolumeDriver',
# 'sheepdog=nova.virt.libvirt.volume.LibvirtNetVolumeDriver',
# 'nfs=nova.virt.libvirt.volume.LibvirtNFSVolumeDriver',
# 'aoe=nova.virt.libvirt.volume.LibvirtAOEVolumeDriver',
# 'glusterfs='nova.virt.libvirt.volume.LibvirtGlusterfsVolumeDriver',
# 'fibre_channel=nova.virt.libvirt.volume.LibvirtFibreChannelVolumeDriver',
# 'scality=nova.virt.libvirt.volume.LibvirtScalityVolumeDriver',
# ]
conf = self._connect_volume(connection_info, disk_info) # cache device_path in connection_info -- required by encryptors
if 'data' in connection_info:
connection_info['data']['device_path'] = conf.source_path
vol['connection_info'] = connection_info
vol.save(context) # 如果是加密卷,需要attach到encryptor
if (not reboot and 'data' in connection_info and
'volume_id' in connection_info['data']):
volume_id = connection_info['data']['volume_id']
encryption = encryptors.get_encryption_metadata(
context, self._volume_api, volume_id, connection_info) if encryption:
encryptor = self._get_volume_encryptor(connection_info,
encryption)
encryptor.attach_volume(context, **encryption) timeout = CONF.vif_plugging_timeout
if (self._conn_supports_start_paused and
utils.is_neutron() and not
vifs_already_plugged and power_on and timeout):
events = self._get_neutron_events(network_info)
else:
events = [] launch_flags = events and libvirt.VIR_DOMAIN_START_PAUSED or 0
domain = None
try:
with self.virtapi.wait_for_instance_event(
instance, events, deadline=timeout,
error_callback=self._neutron_failed_callback):
# Plug VIFs into networks using vif_driver
self.plug_vifs(instance, network_info)
# Init iptables using firewall_driver
self.firewall_driver.setup_basic_filtering(instance,
network_info)
self.firewall_driver.prepare_instance_filter(instance,
network_info)
# 调用libvirt库提供的方法创建虚拟机
# if xml:
# err = _LE('Error defining a domain with XML: %s') % xml
# domain = self._conn.defineXML(xml) # if power_on:
# err = _LE('Error launching a defined domain with XML: %s') \
# % domain.XMLDesc(0)
# domain.createWithFlags(launch_flags)
domain = self._create_domain(
xml, instance=instance,
launch_flags=launch_flags,
power_on=power_on) self.firewall_driver.apply_instance_filter(instance,
network_info)
except exception.VirtualInterfaceCreateException:
# Neutron reported failure and we didn't swallow it, so
# bail here
with excutils.save_and_reraise_exception():
if domain:
domain.destroy()
self.cleanup(context, instance, network_info=network_info,
block_device_info=block_device_info)
except eventlet.timeout.Timeout:
# We never heard from Neutron
LOG.warn(_LW('Timeout waiting for vif plugging callback for '
'instance %(uuid)s'), {'uuid': instance['uuid']})
if CONF.vif_plugging_is_fatal:
if domain:
domain.destroy()
self.cleanup(context, instance, network_info=network_info,
block_device_info=block_device_info)
raise exception.VirtualInterfaceCreateException() # Resume only if domain has been paused
if launch_flags & libvirt.VIR_DOMAIN_START_PAUSED:
domain.resume()
return domain
 

nova分析(8)—— nova-compute的更多相关文章

  1. nova分析(10)—— nova-rootwrap

    一.nova-rootwrap的作用 部署玩过openstack的都应该知道,它会生成一个nova用户来管理所有服务.nova身份在linux中属于普通用户级别,避免了一些需要root身份运行的操作, ...

  2. 在Openstack H版部署Nova Cell 时 ,终端输入nova service-list 和 nova host-list 命令将报错

    关于Cell的基本介绍,可以参考贤哥的一篇文章: [OpenStack]G版中关于Nova的Cell  http://blog.csdn.net/lynn_kong/article/details/8 ...

  3. KVM 介绍(8):使用 libvirt 迁移 QEMU/KVM 虚机和 Nova 虚机 [Nova Libvirt QEMU/KVM Live Migration]

    学习 KVM 的系列文章: (1)介绍和安装 (2)CPU 和 内存虚拟化 (3)I/O QEMU 全虚拟化和准虚拟化(Para-virtulizaiton) (4)I/O PCI/PCIe设备直接分 ...

  4. nova创建虚拟机源码分析系列之八 compute创建虚机

    /conductor/api.py _build_instance()  /conductor/rpcapi.py  _build_instance() 1 构造一些数据类型2 修改一些api版本信息 ...

  5. nova分析(7)—— nova-scheduler

    Nova-Scheduler主要完成虚拟机实例的调度分配任务,创建虚拟机时,虚拟机该调度到哪台物理机上,迁移时若没有指定主机,也需要经过scheduler.资源调度是云平台中的一个很关键问题,如何做到 ...

  6. nova分析(5)—— nova-conductor

    nova-conductor是nova-compute之上的一个服务,这个服务比较简单,主要封装了DB访问和动态迁移相关的代码.转来一篇文章看看它是如何工作的. 更新记录:1. 2013.4.19   ...

  7. nova分析(6)—— nova service启动过程

    Nova project下面具有多个service,api,compute,sceduler等等,他们的启动过程都几乎类似,这一篇博客就详细记录nova-sceduler的启动过程.文章中贴出的源码都 ...

  8. nova分析(3)—— nova-api

    nova-api是nova对外提供Restful API的服务,Horizon.novaclient等均通过该api与nova进行通信. nova其实对外提供了多个api服务,包括下面这些服务: no ...

  9. Nova分析(1)——整体架构

    Conceptual Diagram Logical diagram Nova is the most complicated and distributed component of OpenSta ...

随机推荐

  1. MySQL 添加列,修改列,删除列

    创建后表的修改 alter table 语句用于创建后对表的修改, 基础用法如下: 添加列 基本形式: alter table 表名 add 列名 列数据类型 [after 插入位置]; 示例: 在表 ...

  2. dedecms 列表每隔6行输出一个空li

    {dede:list pagesize='33'} <li class="hang"><a href="[field:arcurl/]" ta ...

  3. java 中的几种 "通用方法“

    前言 Java中,除了基本的数值类型,其他所有数据类型(包括数组)都是对象. 而Object这个类是所有类的超类,它提供的方法,自然能够使用于它的所有子类(所有非基本数值类型). 本文介绍了Objec ...

  4. Codeforces Round #301 (Div. 2) B. School Marks

    其实是很水的一道bfs题,昨晚比赛的时候没看清题意,漏了一个条件. #include<cstdio> #include<cstring> #include<iostrea ...

  5. javascript 火狐event.keyCode不能使用event is not defined

    在项目中,登录时需要enter按钮提交页面所以需要监听键盘输出 但是在火狐中不支持 event.code 所以换了中写法 1:form中加入时间传入event <form id="fr ...

  6. Linux 安装挂载时注意事项

    Linux系统下使用的是目录树系统,所以安装的时候要规划磁盘分区与目录树的挂载.实际上,在Linux系统安装的时候已经提供了相当多的默认模式让你选择分割的方式了,不过无论如何,分割的结果可能都不是能符 ...

  7. twisted 初体验

    前言: 最近帮朋友review其模块服务代码, 使用的是python的twisted网络框架. 鉴于之前并没有使用过, 于是决定好好研究一番. 个人接触最早的高性能网络编程框架是Mina, 所谓先入为 ...

  8. ajax 轮循

    使用 AJAX 进行异步加载轮询操作.简单代码如下: <script> // 执行ajax轮循操作 function polling(){ var xmlhttp; // 判断浏览器--创 ...

  9. c 函数及指针学习 4

    1数组和指针声明的差别 声明数组:为数组分配内存,为数组名分配内存(指针常量 4个字节) 指针:为指针分配内存(指针变量 4个字节) 1 2 3 4 5 6 7 8 9 10 #include < ...

  10. 虚拟化_KVM

    一.KVM介绍 1.KVM全称kernel vitual machine,是针对包含虚拟化扩展(InterVT或AMD-V)的x86硬件上的完全原生的虚拟化解决方案 2.KVM是以色列Qumranet ...