一個OpenStack訪問請求在各元件之間的呼叫過程
OpenStack 是一整套資源管理軟體的集合,也是當前最熱的開源虛擬化管理軟體之一,有一個全球139個國家將近兩萬開發者參與的開源社群(www.openstack.org)作為支援。OpenStack專案的目的是快速建設一個穩定可靠的公有云或私有云系統。整個專案涵蓋了計算,儲存,網路以及前端展現等關於雲管理的全部方面,包含了眾多子專案,其中主要的子專案有:
- OpenStack Compute (code-name Nova) 計算服務
- OpenStack Networking (code-name Neutron) 網路服務
- OpenStack Object Storage (code-name Swift) 物件儲存服務
- OpenStack Block Storage (code-name Cinder) 塊裝置儲存服務
- OpenStack Identity (code-name Keystone) 認證服務
- OpenStack Image Service (code-name Glance) 映象檔案服務
- OpenStack Dashboard (code-name Horizon) 儀表盤服務
- OpenStack Telemetry (code-name Ceilometer) 告警服務
- OpenStack Orchestration (code-name Heat) 流程服務
- OpenStack Database (code-name Trove) 資料庫服務
OpenStack的各個服務之間通過統一的REST風格的API呼叫,實現系統的鬆耦合。下圖是OpenStack各個服務之間API呼叫的概覽,其中實線代表client 的API呼叫,虛線代表各個元件之間通過rpc 呼叫進行通訊。鬆耦合架構的好處是,各個元件的開發人員可以只關注各自的領域,對各自領域的修改不會影響到其他開發人員。不過從另一方面來講,這種鬆耦合的架構也給整個系統的維護帶來了一定的困難,運維人員要掌握更多的系統相關的知識去調試出了問題的元件。所以無論對於開發還是維護人員,搞清楚各個元件之間的相互呼叫關係是怎樣的都是非常必要的。
從nova-client入手
nova-client是一個命令列的客戶端應用,終端使用者可以從nova-client發起一個api請求到nova-api,nova-api服務會轉發該請求到相應的元件上。同時,nova-api支援對cinder、neutron的請求轉發,也就是你可以在nova-client直接向cinder,neutron傳送請求。
我們可以在呼叫nova-client 增加--debug選項列印更多的debug訊息,通過這些debug資訊可以瞭解到如果我們需要發起一個完整的業務層面上請求,都需要跟那些服務打交道。
以 boot 一個新例項為例子,以下是執行程式碼以及debug輸出:
[[email protected] devstack]$ nova --debug boot t3 --flavor m1.nano --image 44c37b90-0ec3-460a-bdf2-bd8bb98c9fdf --nic net-id=b745b2c6-db16-40ab-8ad7-af6da0e5e699 … REQ: curl -i 'http://cloudcontroller:5000/v2.0/tokens' REQ: curl -i 'http://cloudcontroller:8774/v2/d7beb7f28e0b4f41901215000339361d/images/44c37b90-0ec3-460a-bdf2-bd8bb98c9fdf' REQ: curl -i 'http://cloudcontroller:8774/v2/d7beb7f28e0b4f41901215000339361d/flavors/m1.nano' REQ: curl -i 'http://cloudcontroller:8774/v2/d7beb7f28e0b4f41901215000339361d/servers' -X POST -H "Accept: application/json" -H "Content-Type: application/json" -H "User-Agent: python-novaclient" -H "X-Auth-Project-Id: admin" -H "X-Auth-Token: {SHA1}15d9e554b7456f1043732bb8df72d1521c5f6aa1" -d '{"server": {"name": "t3", "imageRef": "44c37b90-0ec3-460a-bdf2-bd8bb98c9fdf", "flavorRef": "42", "max_count": 1, "min_count": 1, "networks": [{"uuid": "b745b2c6-db16-40ab-8ad7-af6da0e5e699"}]}}'
從以上debug輸出我們可以清楚看到,執行一個boot新例項的操作需要傳送如下幾個api請求:
- 向keystone傳送請求,獲取租戶(d7beb7f28e0b4f41901215000339361d)的認證token
- 通過拿到的token,向nova-api服務傳送請求,驗證image是否存在
- 通過拿到的token,向nova-api服務傳送請求,驗證建立的favor是否存在
- 請求創健一個新的instance,需要的元資料資訊通過包含在請求body中
nova-client幫我們把需要的全部請求放到一起,而最重要的就是4。如果使用者想自己通過rest api 直接傳送http請求的話,可以直接使用4,當然,前提是先通過呼叫keystone服務得到認證token。
下面結合程式碼重點敘述一下4的請求資料流動在整個stack中的過程。
圖1建立新例項時的請求在OpenStack中各元件之間的呼叫
上圖是一個全域性的流程圖,圖中每個服務是一個單獨的程序例項,他們之間通過rpc呼叫(廣播或者呼叫)另一個服務。nova-api服務是一個wsgi服務例項,建立新instance的入口程式碼是在nova /api/openstack/compute/servers.py,處理函式為:
def create(self, req, body): """Creates a new server for a given user.""" … (instances, resv_id) = self.compute_api.create(context,...
做一些引數驗證之後,呼叫compute api的create 函式(程式碼在nova/compute/api.py中):
@hooks.add_hook("create_instance") def create(self, context, instance_type, ... return self._create_instance(...
建立instance物件例項,_create_instance會呼叫compute_task api 的build_instances 方法對剛建立的instances例項進行構建:
self.compute_task_api.build_instances(context, ...
compute_task api是一個nova-conductor 服務的rpc api請求,處理程式碼在nova/conductor/manager.py中:
def build_instances(self, context, instances, image, filter_properties, ... hosts = self.scheduler_rpcapi.select_destinations(context, ... self.compute_rpcapi.build_and_run_instance(context, ...
它做了兩件事情:呼叫scheduler的rpc api選擇在那些主機上建立新例項,並最終通過rpc請求nova-compute 服務去構建和執行新例項。
處理函式在nova/compute/manager.py中:
def build_and_run_instance(self, context, instance, image, request_spec, filter_properties, admin_password=None, injected_files=None, requested_networks=None, security_groups=None, block_device_mapping=None, node=None, limits=None):
最終呼叫配置檔案中配置的hypervisor型別進行虛擬機器的建立和執行,一個例項就這樣構建好了。
以下是上面涉及到的服務的主要功能:
- nova-api:接受http請求,並響應請求,當然還包括請求資訊的驗證
- nova-conductor:與資料庫互動,提高對資料庫訪問的安全性
- nova-scheduler:排程服務,決定最終例項要在哪個服務上建立。遷移,重建等都需要通過這個服務
- nova-compute:呼叫虛擬機器管理程式,完成虛擬機器的建立和執行以及控制
以上基本包含nova專案的全部服務,但一個請求有的時候並不需要經過全部的服務。繼續看shelve一個例項的過程。
[[email protected] devstack]$ nova --debug shelve t2 REQ: curl -i 'http://cloudcontroller:5000/v2.0/tokens' … REQ: curl -i 'http://cloudcontroller:8774/v2/d7beb7f28e0b4f41901215000339361d/servers'… REQ: curl -i 'http://cloudcontroller:8774/v2/d7beb7f28e0b4f41901215000339361d/servers/r'… … REQ: curl -i 'http://cloudcontroller:8774/v2/d7beb7f28e0b4f41901215000339361d/servers/ 00be783d-bef5-46b1-bfdc-316618c76e92/action' -X POST -H "Accept: application/json" -H "Content-Type: application/json" -H "User-Agent: python-novaclient" -H "X-Auth-Project-Id: admin" -H "X-Auth-Token: {SHA1}0634ea0ef1c3994e1f496c5d8890d32610cf11e9" -d '{"shelve": null}'…
- 向keystone傳送請求,獲取租戶(d7beb7f28e0b4f41901215000339361d)的認證token
- 通過拿到的token,向nova-api服務傳送請求,顯示該租戶的全部服務例項
- 通過拿到的token,向nova-api服務傳送請求,查詢準備shelve的例項uuid的詳細資訊
- 請求一個server操作action,執行shelve操作(request body為‘{“shelve”: null}’)
nova-api返回http 202,成功接受請求,轉為後臺進行非同步執行。
RESP: [202] CaseInsensitiveDict({'date': 'Thu, 18 Sep 2014 04:03:09 GMT', 'content-length': '0', 'content-type': 'text/html; charset=UTF-8', 'x-compute-request-id': ' req-4be7dc9a-21da-4050-9310-3ee58ca93569'}) RESP BODY: null
上面4中的shelve 操作程式碼在nova/api/openstack/compute/contrib/shelve.py :
@wsgi.action('shelve') def _shelve(self, req, id, body): """Move an instance into shelved mode.""" context = req.environ["nova.context"] auth_shelve(context) instance = self._get_instance(context, id) try: self.compute_api.shelve(context, instance) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message())
從程式碼可以看出,nova-api服務直接呼叫了compute_api,程式碼位於nova/compute/api.py
if not self.is_volume_backed_instance(context, instance): name = '%s-shelved' % instance['display_name'] image_meta = self._create_image(context, instance, name, 'snapshot') image_id = image_meta['id'] self.compute_rpcapi.shelve_instance(context, instance=instance, image_id=image_id) else: self.compute_rpcapi.shelve_offload_instance(context, instance=instance)
comput_api直接呼叫rpc訊息請求,所以,直接將訊息傳送給了nova-compute服務,所以最終各個元件之間的呼叫關係如下:
結論
本文介紹了OpenStack專案的所有元件以及元件之間的呼叫關係,並從nova-client 入手,結合程式碼分析了兩個具體例項,從例項的debug訊息分析得出如果我們需要完成一個完整的業務請求,需要呼叫那些api請求;從程式碼分析,可以得出api呼叫的大致關係。rpc請求用於實現一個元件內部的各個服務,如nova元件中的nova-api、nova-compute、nova-conductor、nova-scheduler等。而不同元件之間的呼叫則是通過rest api請求實現,如nova元件的某一服務需要呼叫cinder服務,則是在nova元件引入改cinder服務的client api,實現rest-api請求。