一個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輸出:

[tagett@stack-01 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請求:

  1. 向keystone發送請求,獲取租戶(d7beb7f28e0b4f41901215000339361d)的認證token
  2. 通過拿到的token,向nova-api服務發送請求,驗證image是否存在
  3. 通過拿到的token,向nova-api服務發送請求,驗證創建的favor是否存在
  4. 請求創健一個新的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類型進行虛擬機的創建和運行,一個實例就這樣構建好了。

以下是上面涉及到的服務的主要功能:

  1. nova-api:接受http請求,並響應請求,當然還包括請求信息的驗證
  2. nova-conductor:與數據庫交互,提高對數據庫訪問的安全性
  3. nova-scheduler:調度服務,決定最終實例要在哪個服務上創建。遷移,重建等都需要通過這個服務
  4. nova-compute:調用虛擬機管理程序,完成虛擬機的創建和運行以及控制

以上基本包含nova項目的全部服務,但一個請求有的時候並不需要經過全部的服務。繼續看shelve一個實例的過程。

[tagett@stack-01 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}'…
  1. 向keystone發送請求,獲取租戶(d7beb7f28e0b4f41901215000339361d)的認證token
  2. 通過拿到的token,向nova-api服務發送請求,顯示該租戶的全部服務實例
  3. 通過拿到的token,向nova-api服務發送請求,查詢準備shelve的實例uuid的詳細信息
  4. 請求一個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請求。

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