文章目錄
先看一下整體架構
從圖中,可以知道幾個點:
交互
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)