NOVA-API服務啓動流程

同時發佈於: http://leiqzhang.com/2014/01/2014-01-09-nova-api-service-initialization/


NOVA-API服務啓動流程

前提

  1. 對Nova的整體結構已經有所理解
  2. 基於stable/havana分支
  3. 基於Redhat的RDO庫進行的環境安裝,基於CentOS 6.4

內容

  1. openstack-nova-api服務啓動流程
  2. Paste、Deploy、WSGI等相關知識

執行結果

啓動API服務時的命令爲:

1
service openstack-nova-api start

啓動成功後,查看系統進程,發現實際執行結果爲一個nova-api父進程,同時其有三個nova-api子進程:

1
2
3
4
nova 3438 S 0:07 /usr/bin/python /usr/bin/nova-api --logfile /var/log/nova/api.log
nova 3446 S 0:00 \_ /usr/bin/python /usr/bin/nova-api --logfile /var/log/nova/api.log
nova 3447 S 0:00 \_ /usr/bin/python /usr/bin/nova-api --logfile /var/log/nova/api.log
nova 3448 S 0:00 \_ /usr/bin/python /usr/bin/nova-api --logfile /var/log/nova/api.log

查看監聽的端口,發現父進程nova-api同時監聽了三個端口:

1
2
3
tcp        0      0 0.0.0.0:8773                0.0.0.0:*                   LISTEN      3438/python         
tcp        0      0 0.0.0.0:8774                0.0.0.0:*                   LISTEN      3438/python         
tcp        0      0 0.0.0.0:8775                0.0.0.0:*                   LISTEN      3438/python

代碼路徑

主要路徑

服務啓動腳本爲/etc/init.d/openstack-nova-api,查看此腳本發現在啓動服務時實際執行的是/usr/bin/nova-api,而/usr/bin/nova-api是一個python腳本,實際執行的是nova.cmd.api.main

nova.cmd.api.main的主要代碼如下:

1
2
3
4
5
6
7
8
9
10
    launcher = service.process_launcher()
    for api in CONF.enabled_apis:
        should_use_ssl = api in CONF.enabled_ssl_apis
        if api == 'ec2':
            server = service.WSGIService(api, use_ssl=should_use_ssl,
                                         max_url_len=16384)
        else:
            server = service.WSGIService(api, use_ssl=should_use_ssl)
        launcher.launch_service(server, workers=server.workers or 1)
    launcher.wait()

首先生成一個nova.common.service.Processlauncher類型的launcher, 接着會根據配置中的enabled_apis列表值,依次生成相應的WSGIService:

1
server = service.WSGIService(...)

然後通過launcher的launch_service方法,將上述的WSGIService和workers數量作爲參數傳入。

在luanch_service方法中,會根據傳入的workers參數fork出相應個數的子進程,並在各個子進程中調用對應WSGIService的start方法,開始對外服務。

涉及的配置

根據上述的主要執行路徑,查看配置文件/etc/nova/nova.conf中的相關配置如下:

1
2
# a list of APIs to enable by default (list value)
#enabled_apis=ec2,osapi_compute,metadata

以及後面依次的ec2、osapi_compute和metadata相應的如下幾項配置:

1
2
3
4
5
6
7
8
# IP address for EC2 API to listen (string value)
#ec2_listen=0.0.0.0

# port for ec2 api to listen (integer value)
#ec2_listen_port=8773

# Number of workers for EC2 API service (integer value)
#ec2_workers=<None>

由此可見,在啓動nova-api服務時,會同時啓動ec2、osapi_compute和metadata三個API服務,各服務均有相應的監聽地址和監聽端口以及workers數量配置。

結合執行結果中看到的端口監聽中看到的三個端口均爲父進程進行監聽,應該是父進程會對請求進行轉發,由於nova-api是無狀態的,當具有多個worker時(也就會被launcher派生出多個子進程),父進程應該還會有LB的邏輯,這一點可後續再深究和驗證。

從日誌文件/var/log/nova/api.log中,也可以對上述過程進行驗證:

1
2
3
4
5
6
7
8
9
10
11
12
--
2014-01-08 18:41:18.091 3438 INFO nova.wsgi [-] ec2 listening on 0.0.0.0:8773
2014-01-08 18:41:18.091 3438 INFO nova.openstack.common.service [-] Starting 1 workers
2014-01-08 18:41:18.093 3438 INFO nova.openstack.common.service [-] Started child 3446
--
2014-01-08 18:41:18.793 3438 INFO nova.wsgi [-] osapi_compute listening on 0.0.0.0:8774
2014-01-08 18:41:18.793 3438 INFO nova.openstack.common.service [-] Starting 1 workers
2014-01-08 18:41:18.795 3438 INFO nova.openstack.common.service [-] Started child 3447
--
2014-01-08 18:41:18.802 3438 INFO nova.wsgi [-] metadata listening on 0.0.0.0:8775
2014-01-08 18:41:18.802 3438 INFO nova.openstack.common.service [-] Starting 1 workers
2014-01-08 18:41:18.804 3438 INFO nova.openstack.common.service [-] Started child 3448

WSGIService

所謂的WSGI,可參考參考資料中的內容。

簡單來說就是分爲Server和APP兩層,Server負責接受Request,設置相應的Environment,並轉發到相應的APP進行處理,並返回Response。

如前所述,在服務啓動過程中,主要涉及WSGIService的初始化(init)和啓動(start)方法,下面分別進行分析。

init方法

方法主體如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
self.name = name
        self.manager = self._get_manager()
        self.loader = loader or wsgi.Loader()
        self.app = self.loader.load_app(name)
        self.host = getattr(CONF, '%s_listen' % name, "0.0.0.0")
        self.port = getattr(CONF, '%s_listen_port' % name, 0)
        self.workers = getattr(CONF, '%s_workers' % name, None)
        self.use_ssl = use_ssl
        self.server = wsgi.Server(name,
                                  self.app,
                                  host=self.host,
                                  port=self.port,
                                  use_ssl=self.use_ssl,
                                  max_url_len=max_url_len)
        # Pull back actual port used
        self.port = self.server.port
        self.backdoor_port = None

其中name就是前文提到的api_name,也即ec2、osapi_compute或metadata。

第2行的_get_manager方法,會從配置中尋找{self.name}_manager對應的類,並加載進來。關於OpenStack Nova中劃分的Manager的角色和作用可參考 這裏

查看nova配置文件(/etc/nova/nova.conf),對於ec2、osapi_compute和metadata,默認情況下只有metadata_manager:

1
2
# OpenStack metadata service manager (string value)
#metadata_manager=nova.api.manager.MetadataManager

後面的邏輯,首先會通過wsgiLoader來load_app,這裏涉及到Paste和Deploy的相關處理。參考最後一節。

最後會使用相應的參數初始化一個wsgiServer, 此Server對應的app就是上面使用wsgiLoader加載進來的APP。

start方法

主要邏輯是調用了上述wsgiServer的start方法,開始對外服務。對於metadata API來說,還需要其manager介入在start前後進行相應的處理。

1
2
3
4
5
6
7
8
if self.manager:
            self.manager.init_host()
            self.manager.pre_start_hook()
        if self.backdoor_port is not None:
            self.manager.backdoor_port = self.backdoor_port
        self.server.start()
        if self.manager:
            self.manager.post_start_hook()

Paste & Deploy

關於Paste和Deploy可查看參考資料部分中相應的內容。

簡單來說,Paste主要提供的是WSGI middleware,各middleware對WSGI的server來說是一個APP,但對於WSGI的APP來說是一個Server,且可以將多個middleware疊加,從而可實現類似Linux中pipeline的效果。在pipeline中,可以實現諸如壓縮、解壓縮、加密、解密、鑑權等各種預處理和後處理操作。Deploy是根據paste配置文件來發現和加載WSGI APP和Middleware的模塊。

這裏針對上節中的wsgiLoader進行詳細分析

1
2
        self.loader = loader or wsgi.Loader()
        self.app = self.loader.load_app(name)

第一行初始化Loader,期間會根據配置項api_paste_config來locate到相應的paste配置文件,默認是/etc/nova/api-paste.ini。

第二行的load_app(name),最終會使用Deploy模塊加載name對應的APP,這裏的name就是上述的ec2、osapi_compute或metadata。

在/etc/nova/api-paste.ini中,針對上述的三種name,均會有對應的[composite:{name}] section,並根據Paste的規則,配置相應的pipeline。其中osapi_compute的部分默認配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[composite:osapi_compute]
use = call:nova.api.openstack.urlmap:urlmap_factory
/: oscomputeversions
/v1.1: openstack_compute_api_v2
/v2: openstack_compute_api_v2
/v3: openstack_compute_api_v3

[composite:openstack_compute_api_v2]
use = call:nova.api.auth:pipeline_factory
noauth = faultwrap sizelimit noauth ratelimit osapi_compute_app_v2
keystone = faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2
keystone_nolimit = faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2

[composite:openstack_compute_api_v3]
use = call:nova.api.auth:pipeline_factory
noauth = faultwrap sizelimit noauth_v3 ratelimit_v3 osapi_compute_app_v3
keystone = faultwrap sizelimit authtoken keystonecontext ratelimit_v3 osapi_compute_app_v3
keystone_nolimit = faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v3

[filter:faultwrap]
paste.filter_factory = nova.api.openstack:FaultWrapper.factory

[filter:noauth]
...

在配置OpenStack環境時,我們一般均會修改此paste配置文件,增加或修改如下authtoken的filter的內容。如上述composite:osapi_compute的內容,各API的keystone argument中指定的filter列表中均包含了下面的keystonecontext和authtoken。這樣就將keystone的認證過程通過filter的方式附加到了API請求處理的pipeline中了。

1
2
3
4
5
6
7
8
9
10
11
12
13
[filter:keystonecontext]
paste.filter_factory = nova.api.auth:NovaKeystoneContext.factory

[filter:authtoken]
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
auth_host = controller
auth_port = 35357
auth_protocol = http
auth_uri = http://controller:5000/v2.0
admin_user = nova
admin_tenant_name = service
admin_password = nova
    ...

參考資料


發佈了35 篇原創文章 · 獲贊 3 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章