OpenStack創建虛擬機流程


雲主機創建流程圖:

 

dashboard發創建雲主機的請求是先到novaclient,再由novaclienthttp的形式發送到nova-api端,我們這里直接從nova端講起,通過wsgi映射匹配,API映射匹配可以看我的另一篇博客:OpenStack Restful API框架介紹

創建雲主機會首先調用到nova/api/openstack/compute/servers.py文件中的create()函數:

@wsgi.response(202)
@extensions.expected_errors((400, 403, 409))
@validation.schema(schema_server_create_v20, '2.0', '2.0')
@validation.schema(schema_server_create, '2.1', '2.18')
@validation.schema(schema_server_create_v219, '2.19', '2.31')
@validation.schema(schema_server_create_v232, '2.32', '2.36')
@validation.schema(schema_server_create_v237, '2.37', '2.41')
@validation.schema(schema_server_create_v242, '2.42')
def create(self, req, body):
    """Creates a new server for a given user."""
    ......
    # 前面的代碼主要是做了傳進參數的檢查、轉換和操作的權限檢查,同時獲取鏡像
    # id和flavor對象,這些處理完后會調用:
    (instances, resv_id) = self.compute_api.create(context,
                                inst_type,
                                image_uuid,
                                display_name=name,
                                display_description=description,
                                availability_zone=availability_zone,
                                forced_host=host, forced_node=node,
                                metadata=server_dict.get('metadata', {}),
                                admin_password=password,
                                requested_networks=requested_networks,
                                check_server_group_quota=True,
                                group_id=server_dict.get('group_id', None),
                                os_type=server_dict.get('os_type', None),
                                boot_type='legacy',
                                store_id=server_dict.get('store_id', None),
                                enable_ha=server_dict.get('enable_ha', None),
                                thinputer_extra=server_dict.get('thinputer_extra', None),
                                **create_kwargs)

 

這里是調用到了nova/compute/api.py文件中的create函數

該函數進行網絡是否有不合規操作,比如多個雲主機卻只指定了一個ip,檢查可用域,生成過濾字典,然后調用_create_instance方法

主要是初始化一些參數,檢查和檢驗參數和配額方面的檢查,生成instancesrequest_specsbuild_requests對象,request_specsbuild_requests對象用以調度選擇,instances用以返回給客戶端,值可看注解,接着函數調用:

self.compute_task_api.schedule_and_build_instances(
                context,
                build_requests=build_requests,
                request_spec=request_specs,
                image=boot_meta,
                admin_password=admin_password,
                injected_files=injected_files,
                requested_networks=requested_networks,
                block_device_mapping=block_device_mapping)

 

實現文件是在nova/conductor/api.py,該api.py其實是對同級下的rpcapi.py做了層封裝,真正實現在rpcapi.py文件。

api.py中的:

def schedule_and_build_instances(self, context, build_requests,
                                     request_spec, image,
                                     admin_password, injected_files,
                                     requested_networks, block_device_mapping):
        self.conductor_compute_rpcapi.schedule_and_build_instances(
            context, build_requests, request_spec, image,
            admin_password, injected_files, requested_networks,
            block_device_mapping)

 

這里調用了rpcapi.py中的schedule_and_build_instances方法:

def schedule_and_build_instances(self, context, build_requests,
                                      request_specs,
                                      image, admin_password, injected_files,
                                      requested_networks,
                                      block_device_mapping):
        version = '1.16'
        kw = {'build_requests': build_requests,
              'request_specs': request_specs,
              'image': jsonutils.to_primitive(image),
              'admin_password': admin_password,
              'injected_files': injected_files,
              'requested_networks': requested_networks,
              'block_device_mapping': block_device_mapping}

        cctxt = self.client.prepare(version=version)
        cctxt.cast(context, 'schedule_and_build_instances', **kw)

 

這里是遠程調用到了nova/conductor/manager.py中的schedule_and_build_instances函數:

def schedule_and_build_instances(self, context, build_requests,
                                     request_specs, image,
                                     admin_password, injected_files,
                                     requested_networks, block_device_mapping):
        legacy_spec = request_specs[0].to_legacy_request_spec_dict()
        try:
            hosts = self._schedule_instances(context, legacy_spec,
                        request_specs[0].to_legacy_filter_properties_dict())
            ..........

 

這個函數主要前面部分主要是先通過scheduler選擇合適的host,然后是將要創建的虛擬機的信息寫入到數據庫中,最后是調用build_and_run_instance函數,該函數實現是在nova/compute_rpcapi.py

def build_and_run_instance(self, ctxt, instance, host, 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):

        version = '4.0'
        cctxt = self.router.by_host(ctxt, host).prepare(
                server=host, version=version)
        cctxt.cast(ctxt, 'build_and_run_instance', instance=instance,
                image=image, request_spec=request_spec,
                filter_properties=filter_properties,
                admin_password=admin_password,
                injected_files=injected_files,
                requested_networks=requested_networks,
                security_groups=security_groups,
                block_device_mapping=block_device_mapping, node=node,
                limits=limits)

 

通過host參數遠程調用指定宿主機的build_and_run_instance方法,實現文件在nova/compute/manage.py

@wrap_exception()
@reverts_task_state
@wrap_instance_fault
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):

    @utils.synchronized(instance.uuid)
    def _locked_do_build_and_run_instance(*args, **kwargs):
        # NOTE(danms): We grab the semaphore with the instance uuid
        # locked because we could wait in line to build this instance
        # for a while and we want to make sure that nothing else tries
        # to do anything with this instance while we wait.
        with self._build_semaphore:
            self._do_build_and_run_instance(*args, **kwargs)

    # NOTE(danms): We spawn here to return the RPC worker thread back to
    # the pool. Since what follows could take a really long time, we don't
    # want to tie up RPC workers.
    utils.spawn_n(_locked_do_build_and_run_instance,
                  context, instance, image, request_spec,
                  filter_properties, admin_password, injected_files,
                  requested_networks, security_groups,
                  block_device_mapping, node, limits)

 

這里的關鍵點是調用到了_do_build_and_run_instance函數,該函數的關鍵代碼是調用了_build_and_run_instance函數來創建:

def _build_and_run_instance(self, context, instance, image, injected_files,
            admin_password, requested_networks, security_groups,
            block_device_mapping, node, limits, filter_properties):
    ..........

    # 這個函數的主要功能有進行事件通知、獲取所需資源、創建好網絡設備和磁盤設備,最
    # 后是通過配置文件的driver選定以哪種虛擬化方式實現虛擬機的生成,這里調用的函數是:
    self.driver.spawn(context, instance, image_meta,
                                              injected_files, admin_password,
                                              network_info=network_info,
                                              block_device_info=block_device_info)

 

對應的函數實現在nova/virt/libvirt/driver.py

def spawn(self, context, instance, image_meta, injected_files,
              admin_password, network_info=None, block_device_info=None):
        disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
                                            instance,
                                            image_meta,
                                            block_device_info)
        injection_info = InjectionInfo(network_info=network_info,
                                       files=injected_files,
                                       admin_pass=admin_password)
        gen_confdrive = functools.partial(self._create_configdrive,
                                          context, instance,
                                          injection_info)
        self._create_image(context, instance, disk_info['mapping'],
                           injection_info=injection_info,
                           block_device_info=block_device_info)

        # Required by Quobyte CI
        self._ensure_console_log_for_instance(instance)

        # 生成libvirt所需的xml文件
        xml = self._get_guest_xml(context, instance, network_info,
                                  disk_info, image_meta,
                                  block_device_info=block_device_info)
        self._create_domain_and_network(
            context, xml, instance, network_info, disk_info,
            block_device_info=block_device_info,
            post_xml_callback=gen_confdrive,
            destroy_disks_on_failure=True,
            power_on=False)
        LOG.debug("Instance is running", instance=instance)

 

在該函數中主要的功能是生成鏡像、生成xml信息,最后調用_create_domain_and_network函數進行掛載上磁盤、網絡初始化和虛擬機域生成。

虛擬機域生成通過調用了_create_domain函數來實現

 

總結下,虛擬機的創建流程如下:
(1)用戶首先通過Restful Api向keystone組件獲取認證信息
(2)然后向nova-api進程發送一個創建虛擬機的請求,並攜帶獲取的認證信息和創建虛擬機的參數
(3)nova-api將認證信息發送到keystone里認證是否是有效的認證信息
(4)通過認證后且nova-api檢查權限通過后向數據庫寫入新建虛擬機的數據庫記錄
(5)nova-api通過發消息到消息隊列讓nova-conductor去創建虛擬機
(6)nova-conductor通過發消息到消息隊列讓nova-scheduler篩選和選擇可創建虛擬機的節點
(7)nova-scheduler返回經過篩選的可用宿主機給nova-conductor
(8)nova-conductor通過發消息到消息隊列請求讓目標節點nova-compute服務創建虛擬機
(9)nova-compute服務發消息到消息隊列讓控制節點上的nova-conductor服務獲取要新建的虛擬機的元數據信息,比如內存、cpu等信息
(10)nova-compute獲取到新建虛擬機的元數據信息后,為虛擬機分配資源,比如cpu、內存資源
(11)請求鏡像服務獲取新建虛擬機的鏡像信息和創建鏡像文件
(12)如果有網卡和數據盤創建請求,則會分別向neutron和cinder服務請求創建對應的資源
(13)虛擬機域的生成,如果是libvirt的driver,定義好虛擬機的XML信息
(14)初始化虛擬網絡設備並啟動虛擬機
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM