OpenStack源碼解析系列 -- 5、服務啓動流程 以nova-computer爲例

  先看一下整體架構

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
  從圖中,可以知道幾個點:

  交互

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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章