文章目录
先看一下整体架构
从图中,可以知道几个点:
交互
1)、 终端用户(DevOps, Developers 和其他的 OpenStack 组件)通过和nova-api对话来与OpenStack Compute交互。
2)、 OpenStack Compute守护进程(nova-api守护进程)之间通过队列(行为)和数据库(信息)来交换信息,以执行API请求。
3)、 OpenStack Glance基本上是独立的基础架构,OpenStack Compute通过Glance API来和它交互。
各个进程的作用
1)、nova-api守护进程是OpenStack Compute的核心。为所有的API提供端点
2)、nova-compute是虚拟机实例操作的Worker守护进程,虚拟机实例操作过程很复杂。但是nova-compute原理很简单:就是从队列中接收行为,然后更新数据库状态,然后执行一系列的系统命令来执行他们
3)、nova-volume管理映射到计算机实例的卷的创建、附加和取消。这些卷可以来自很多提供商,比如,ISCSI和AoE。
4)、Nova-network worker,它从队列中接收网络任务,然后执行任务以操控网络,比如创建bridging interfaces或改变iptables rules。
5)、Queue提供中心hub,为守护进程传递消息。当前用RabbitMQ实现。但是理论上能是python ampqlib支持的任何AMPQ消息队列。
6)、 SQL database存储云基础架构中的绝大多数编译时和运行时状态。这包括了可用的实例类型,在用的实例,可用的网络和项目。理论上,OpenStack Compute能支持SQL-Alchemy支持的任何数据库,但是当前广泛使用的数据库是sqlite3(仅适合测试和开发工作),MySQL和PostgreSQL。
7)、 OpenStack Glance,是一个单独的项目,镜像管理。
8) 、最后,user dashboard是另一个可选的项目。OpenStack Dashboard提供了一个OpenStack Compute界面来给应用开发者和devops staff类似API的功能。当前它是作为Django web Application来实现的。当然,也有其他可用的Web前端。
nova-compute的启动流程
项目结构
启动函数在项目的/cmd目录下,nova为例的话:/nova/cmd
源码解析nova-compute启动过程
1、compute.py
位置:/nova/cmd/compute.py
def main():
# 解析参数
config.parse_args(sys.argv)
# 设置日志
logging.setup(CONF, 'nova')
# 定义特权上下文
priv_context.init(root_helper=shlex.split(utils.get_root_helper()))
objects.register_all()
# 配置gmr_opts
gmr_opts.set_defaults(CONF)
# Ensure os-vif objects are registered and plugins loaded
# 网络虚拟插件
os_vif.initialize()
# 启动进程监视
gmr.TextGuruMeditation.setup_autorun(version, conf=CONF)
# 阻塞等待数据库连接
cmd_common.block_db_access('nova-compute')
# conductor api实例化:实例时重点在获取rabbitmq中conductor队列的操作封装(RPCClient)
objects_base.NovaObject.indirection_api = conductor_rpcapi.ConductorAPI()
objects.Service.enable_min_version_cache()
# rpc服务器的信息进行封装
server = service.Service.create(binary='nova-compute',
topic=compute_rpcapi.RPC_TOPIC)
# 将rpc服务器信息记录并将其加入service列表,开一个协程启动service(nova-compute)
service.serve(server)
service.wait()
可以看出重点在于service.server(server, workers=None)这个函数
2、service.server(server, workers=None)函数
位置:/nova/volume/service.py
def serve(server, workers=None):
global _launcher
if _launcher:
raise RuntimeError(_('serve() can only be called once'))
_launcher = service.launch(CONF, server, workers=workers,
restart_method='mutate')
直接追踪到service.launch(conf, service, workers=1, restart_method=‘reload’)中去
3、service.launch(conf, service, workers=1, restart_method=‘reload’)
def launch(conf, service, workers=1, restart_method='reload'):
"""Launch a service with a given number of workers.
:param conf: an instance of ConfigOpts
:param service: a service to launch, must be an instance of
:class:`oslo_service.service.ServiceBase`
:param workers: a number of processes in which a service will be running,
type should be int.
:param restart_method: Passed to the constructed launcher. If 'reload', the
launcher will call reload_config_files on SIGHUP. If 'mutate', it will
call mutate_config_files on SIGHUP. Other values produce a ValueError.
:returns: instance of a launcher that was used to launch the service
"""
if workers is not None and not isinstance(workers, six.integer_types):
raise TypeError(_("Type of workers should be int!"))
if workers is not None and workers <= 0:
raise ValueError(_("Number of workers should be positive!"))
if workers is None or workers == 1:
launcher = ServiceLauncher(conf, restart_method=restart_method)
else:
launcher = ProcessLauncher(conf, restart_method=restart_method)
launcher.launch_service(service, workers=workers)
return launcher
这里可看到launcher为ServiceLauncher或ProcessLauncher,那看一下这个类究竟是什么吧
揭开launch的面纱
位置:oslo_service下的service.py
class Launcher(object):
"""启动一个或多个服务,等待它们完成"""
def __init__(self, conf, restart_method='reload'):
"""Initialize the service launcher.
:parm conf: ConfigOpts的实例
:param restart_method: 如果为'reload',则在SIGHUP上调用 reload_config_files;如果为'mutate',则在SIGHUP上调用mutate_config_files。其他值会产生ValueError
:returns: None
"""
self.conf = conf
conf.register_opts(_options.service_opts)
self.services = Services(restart_method=restart_method)
self.backdoor_port = (
eventlet_backdoor.initialize_if_enabled(self.conf))
self.restart_method = restart_method
看看一看launch_service()方法
def launch_service(self, service, workers=1):
"""Load and start the given service.
:param service: The service you would like to start, must be an
instance of :class:`oslo_service.service.ServiceBase`
:param workers: This param makes this method compatible with
ProcessLauncher.launch_service. It must be None, 1 or
omitted.
:returns: None
"""
if workers is not None and workers != 1:
raise ValueError(_("Launcher asked to start multiple workers"))
_check_service_base(service)
service.backdoor_port = self.backdoor_port
self.services.add(service)