同時發佈於: http://leiqzhang.com/2014/01/2014-01-09-nova-api-service-initialization/
NOVA-API服務啓動流程
前提
- 對Nova的整體結構已經有所理解
- 基於stable/havana分支
- 基於Redhat的RDO庫進行的環境安裝,基於CentOS 6.4
內容
- openstack-nova-api服務啓動流程
- 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 ... |
參考資料
- Nova的Service、Manager和Driver
- Python Paste: WSGI middle and pipeline
- Python Deploy: Sample Project’s Explannation
- Python Deploy: Offical Document
- Python Deploy: Related Document
- Python WebOb