本文試圖具體地描寫敘述openstack建立虛擬機的完整過程。從用戶發起請求到虛擬機成功執行,包含client請求的發出、keystone身份驗證、nova-api接收請求、nova-scheduler調度、nova-computer建立、nova-network分配網絡。對於每一個模塊在建立虛擬機的過程當中所負責的功能和執行的操做,進行較爲具體描寫敘述和討論。爲了方便描寫敘述,本文若是所有的服務ip地址爲localhost。port使用服務的默認設置port。openstack爲O版。下圖爲建立虛擬機的一個大概流程圖,粗糙地表示下。接下來將對每一個模塊進行具體介紹。若有錯誤,歡迎拍磚!html
clientnode
建立虛擬機的第一步是需要client調用nova-api,發送建立虛擬機請求。眼下openstack提供兩種client:python
1 命令行指令nova,經過指定命令行參數。就可以請求nova-api建立虛擬機,一個最簡單的建立虛擬機指令例如如下:web
nova boot vm_name --flavor flavor_id --image image_uuid --nic net-id = network_id
eg:nova boot --flavor m1.nano --image cirros \
--security-groups default --key-name mykey --nic net-id=a31d6a9a-a73f-4a19-a252-10d0b7e64d1d \
test2算法
2 網頁交互頁面horizon,這是經過web操做頁面來調用nova-api建立虛擬機,比較簡單易用。選定相關參數後。點擊create就可以了。shell
這兩種client除了UI不同之外,功能方面基本都是同樣。數據庫
就建立虛擬機來說。它們需要完畢:api
{"auth": { "passwordCredentials": {"username": self.user, "password": self.password}} "tenantName": "admin" }向keystone發送HTTP請求(keystone的服務地址:nova命令通常經過環境變量OS_AUTH_URL設置,horizon則經過openstack_dashboard.local.local_settings.OPENSTACK_KEYSTONE_URL設置),url爲http://localhost:5000/v2.0/tokens 。假設驗證經過,keystone則返回token_id和serviceCatalog。身份驗證經過後。client纔可對nova-api發送建立請求。
因爲client只配置了keystone的服務地址和port,對於nova-api的服務地址它是不知道的。因此需要先經過keystone驗證,而後由keystone將nova-api的服務地址放在serviceCatalog中返回給它。事實上serviceCatalog中不僅包括nova-api的服務地址,還有glance-api、cinder-api等服務的地址,這些地址在之後的鏡像下載、塊存儲請求時會用到。token_id被放在請求nova-api的headers中。用做nova-api驗證。網絡
對於nova boot,flavor_id和image_uuid需要經過命令行參數指定,novaclient.v1_1.shell._boot()分別向nova-api的"http://localhost:8774/v2/project_id/flavors/flavor_id"和"http://localhost:8774/v2/project_id/images/image_id"發送HTTP請求,驗證資源是否存在。對於horizon,它首先運行horizon.api.nova.flavor_list()和horizon.api.glance.image_list_detailed(),獲取所有可用的flavor ids和image ids,建立虛擬機時僅僅能從這些可用的id中選擇。框架
注意這裏nova boot和horizon對於image的驗證有些不一樣,nova boot是請求nova-api,nova-api再請求glance-api以驗證image uuid,而horizon是直接請求glance-api獲取所有的image ids。
關於body的模樣,可看看novaclient.v1_1.BootingManagerWithFind._boot() 。以上面的nova boot命令爲例,body內容例如如下:
{'server': {'flavorRef': '1', 'hypervisor_type': 'QEMU', 'imageRef': 'd3670457-16f5-4c70-913f-6fc7b76706e4', 'max_count': 1, 'min_count': 1, 'name': 'test-ic'}}這裏的flavorRef相應的是數據庫instance_types的flavorid字段(非id字段),上面命令行傳入的flavor_id也是指數據庫的flavorid字段。向nova-api的http://localhost:8774/v2/project_id/flavors/flavorid請求時,它經過nova.api.openstack.compute.views.flavors.ViewBuilder,將數據庫的id字段做爲instance_type_id。將flavorid做爲id進行返回的。
可以看出,無論nova boot仍是horizon,最後都是經過novaclient向nova-api發送請求的。
novaclient是針對nova-api作了一層封裝,如獲取驗證token-id,以特定的格式構造HTTP請求headers和body,解析請求的結果等。事實上可以不用nova boot命令行和horizon,甚至novaclient都不需要,咱們全然可以設定好HTTP請求的headers和body,直接請求nova-api。只是這三個工具將這些繁瑣的工做替咱們作了。咱們僅僅需要填寫參數就可以了。最後注意下。nova命令事實上僅僅是novaclient的一個entry point:novaclient.shell.main()。而nova boot實際上調用的是novaclient.v1_1.shell.do_boot()。
keystone
由上可知,在client發起建立虛擬機請求時,keystone需要對client的username和password進行驗證。keystone-all與nova-api同樣,api的公佈沒有採用不論什麼框架,而是使用router、paste類庫。從頭寫的,實現風格上又與nova-api有點差別。
keystone-all服務會監聽兩個port:localhost:5000,即publicURL。通常用戶使用password可以訪問;localhost:35357。即adminURL,僅僅能使用admin帳戶和password訪問。
在建立虛擬機流程中,調用的keystone的api有兩個(事實上,每次請求基本都會調用這兩個api):
1 http://localhost:5000/v2.0/tokens,請求該api來獲取token_id和serviceCatalog,由client調用。keystone會將該api的請求交給keystone.TokenController.authenticate()處理。該函數主要完畢:
2 http://localhost:35357/v2.0/tokens/token_id,對請求的token_id進行驗證。由nova-api調用。nova-api接收到請求後。首先使用請求攜帶的token_id來訪問該api,以驗證請求是否經過驗證。
固然nova-api需要在body里加上admin的帳戶和password信息,這些信息需要在api-paste.ini中配置。還有keystone的服務地址,因爲在驗證沒經過以前。不能使用client傳過來的endpoints。glance-api、cinder-api等在接收到client請求後。都會調用該api對client的token_id進行驗證。
該api的請求交給keystone.TokenController.validate_token()處理,事實上就是使用請求的token_id進行一次數據庫查詢。
nova-api
nova-api是一個統稱,它是一類服務的集合。如openstack之nova-api服務流程分析所說,在默認配置下,它包括ec2(與EC2兼容的API)。osapi_compute(openstack compute本身風格的API),osapi_volume(openstack volume服務API)。metadata(metadata 服務API)等api服務。每個服務提供不一樣的api,只是儘管ec2和osapi_compute的api不一樣。但功能是一樣的。這裏,建立虛擬機請求的api是:
http://localhost:8774/v2/project_id/servers。由osapi_compute服務公佈。該api是RESTFUL的,以POST方法請求該api。通過幾層middleware處理後,終於交給nova.api.openstack.compute.servers.Controller.create()處理。
它們主要完畢下面功能:
如。檢查虛擬機name是否符合命名規範。flavor_id是否在數據庫中存在,image_uuid是不是正確的uuid格式等。
每個project擁有的資源都是有限的,如建立虛擬機的個數,vcpu個數,內存大小。volume個數等。
默認狀況下。所有project的擁有的資源數量相等,由quota_instances、quota_cores、quota_ram、quota_volumes等配置項指定。使用admin帳戶。以PUT方法請求http://localhost:8774/v2/admin_project/os-quota-sets/project_id。可爲特定的project設置配額。
普通狀況下,該參數也爲空,由network本身主動分配。
並推斷flavor是否知足該image的最小配置需求,如內存,虛擬磁盤是否知足image的最小值。
經過rpc call,將所有參數傳給nova-scheduler的nova.scheduler.manager.SchedulerManager.run_instance()。由它運行虛擬機調度。
在token_id驗證經過的狀況下。nova-api的主要任務是資源配額和參數檢查,並建立數據庫。
假設你使用dashboard,此時你在頁面上將會看到虛擬機處於scheduling狀態。只是該狀態持續時間很是短,差點兒察覺不到,除非nova-scheduler出問題了。
nova-scheduler
與nova-api提供外部服務不一樣。nova各組件之間相互調用,使用的是以rabbitmq做爲消息隊列的RPC調用。這裏忽略RPC的實現細節。僅僅需知道rcp call調用哪一個的節點的哪一個服務就可以了。nova-scheduler的run_instance()從nova-api接收到的參數中僅僅使用到了request_spec和filter_properties,其他參數將直接傳遞給nova-compute去建立虛擬機。request_spec包括虛擬機的type、number、uuids等信息,在調度中需要用這些信息做爲參考。
filter_properties包括指定調度規則信息,如force_hosts指定調度到特定的節點,ignore_hosts不調度到某些節點等。nova-scheduler在接收到nova-api的請求後。由nova.scheduler.filter_scheduler.FilterScheduler.scheduler_run_instances(),它主要完畢下面任務:
後面的版本號可能認爲使用Weigher。又使用WeigherHander。僅僅是對內存大小作排序。有點小題大作了,在2012.2.4中用一個函數nova.scheduler.least_cost.weighted_sum()就實現排序。但在2013.2中又回到原來的結構了。
nova-scheduler相對而言,邏輯比較簡單。代碼也不難。只是需要注意在node-scheduler運行過程當中,不會改變虛擬機的vm_state和tast_state。
因此在horizon上也不會有變化。
nova-compute
nova-scheduler選定host後,隨即經過rpc調用,調用host的nova-compute服務的nova.compute.manager.ComputeManager.run_instance()。
由它運行真正的建立虛擬機操做。只是在介紹以前,需要簡單說起一下nova-compute的兩個定時任務:
而後從數據庫中查找到執行在該節點上的所有虛擬機信息,統計出這些虛擬機所使用的vcpu個數、內存大小、磁盤大小。並將計算節點的總資源數量減去虛擬機使用的數量,獲得空暇內存大小和空暇磁盤大小。而後更新數據庫compute_node信息。這裏需要注意從數據庫中獲取的虛擬機使用資源數量並不是必定是計算節點消耗的資源數量,如1)虛擬機使用磁盤鏡像爲qcow2格式時,它的大小要小於或等於實際分配的大小。2)也有可能因爲數據不一樣步,使得統計的數據與實際的資源使用不一致。
該任務是用於定時更新當前計算節點的capabilities信息,相同也是經過LibvirtDriver來獲取資源數據的,只是在計算已使用資源方面,是直接使用經過調用multiprocessing、libvirt、os等返回的cpu個數、內存、磁盤使用狀況。並附加上host_ip信息。並由定時任務_publish_service_capabilities經過rpc call轉發到nova.scheduler.host_manager.HostManager.service_states中。
這兩個定時任務爲nova-scheduler提供了實時的host信息。因此才幹實現準確調度。由於capabilities信息與compute_node表中信息有很是大的類似度,因此調度過程當中很是少用到。
nova-scheduler調度到nova-compute的run_instance()主要完畢什麼功能呢:
對於image,通常採用qcow2格式,做爲qemu-img的backing_file新建一個image使用,這樣可以節約空間。
原理比較簡單,將下載的image使用mount命令進行掛載,而後將要寫入的內容下到特定的位置。
這裏network採用 FlatDHCP模式,multihost=True。查看代碼可知 FlatDHCPManager繼承RPCAllocateFixedIP, FloatingIP, NetworkManager三個class,依據python屬性訪問流程(參考python對象之屬性訪問流程)可知,調用FlatDHCPManger.allocate_for_instance()首先運行FloatingIP.allocate_for_instance(),再由它調用NetworkManger.allocate_for_instance()。主要完畢任務例如如下:
這樣就可以經過floating ip從外部訪問虛擬機了。