1. 程式人生 > >openstack映象:Cloudbase-init的定製化實現

openstack映象:Cloudbase-init的定製化實現

在雲端計算openstack中,我們往往需要對建立的虛擬機器進行初始化以及特殊的定製過程。在Linux系統中,我們有Cloud-init,在Windows系統中,也有個類似的工具:Cloudbase-init
這裡的初始化和定製,更通俗的來說,就是在虛擬機器啟動尤其是首次啟動的時候,進行如主機名、網路、磁碟擴容、使用者和密碼等等的設定。在Cloudbase-init中是以外掛的形式來做的,在Linux的cloud-init中是以模組的形式來做的。

cloudbase-init的程式碼入口:
~cloudbaseinit.shell.main()

CONF = cloudbaseinit_conf.CONF

LOG = oslo_logging.getLogger(__name__)


def main():
    CONF(sys.argv[1:])
    logging.setup('cloudbaseinit')

    try:
        init.InitManager().configure_host()
    except Exception as exc:
        LOG.exception(exc)
        raise


if __name__ == "__main__":
    main()

這裡有一個init.InitManager()類,用於封裝對plugin的各種操作。我們的核心操作在這個類裡面的configure_host方法中。
這裡在讀取配置檔案採用了和nova相同的方法:通過呼叫oslo_config庫來讀取。
init.InitManager().configure_host()
對主要步驟進行註解

    def configure_host(self):
        service = None
        # 通過作業系統來判斷使用哪種util,windows是"WindowsUtils"
        osutils = osutils_factory.get_os_utils()
        # 如果是以模板啟動的虛擬機器可能會進行雜湊傳遞攻擊,這裡會重置服務密碼
        if CONF.reset_service_password and sys.platform == 'win32':
            self._reset_service_password_and_respawn(osutils)

        LOG.info('Cloudbase-Init version: %s', version.get_version())
        # 讀取Sysprep的登錄檔,數值為7為完成。
        osutils.wait_for_boot_completion()
        # 第一個stage,處理pre_networking 過程的外掛,貌似只有ntplientplugin,根據需要在配置中開啟或關閉。
        stage_success, reboot_required = self._handle_plugins_stage(
            osutils, None, None,
            plugins_base.PLUGIN_STAGE_PRE_NETWORKING)

        self._check_latest_version()

        if not (reboot_required and CONF.allow_reboot):
           # 第二個stage,處理pre_metadata_discovery中的外掛,貌似也只有一個plugin(mtuplugin)。
            stage_success, reboot_required = self._handle_plugins_stage(
                osutils, None, None,
                plugins_base.PLUGIN_STAGE_PRE_METADATA_DISCOVERY)

        if not (reboot_required and CONF.allow_reboot):
            try:
               # 根據配置獲取DataSource。
                service = metadata_factory.get_metadata_service()
            except exception.MetadaNotFoundException:
                LOG.error("No metadata service found")
        if service:
            LOG.info('Metadata service loaded: \'%s\'' %
                     service.get_name())

            if CONF.metadata_report_provisioning_started:
                LOG.info("Reporting provisioning started")
                service.provisioning_started()

            instance_id = service.get_instance_id()
            LOG.debug('Instance id: %s', instance_id)

            try:
               # 第3個Stage,在獲取DataSource之後,執行main部分的plugin,絕大部分的plugin都是在此部分進行的。
                stage_success, reboot_required = self._handle_plugins_stage(
                    osutils, service, instance_id,
                    plugins_base.PLUGIN_STAGE_MAIN)
            finally:
                service.cleanup()
.........後面的程式碼不是特別核心的操作了........

總結的話,就是cloudbase-init主要對plugin的操作有3個階段,如下:
pre-networking 階段:在傳送任何有效網路請求以前設定網路。(這一過程中應該只有ntpclient模組,可以設定開啟或不開啟)

pre-metadata-discovery 階段:在獲取DataSource之前做一些額外配置(這一過程應該也只有mtu模組),這個階段執行完成後會去獲取DataSource。

main 階段:在DataSource成功獲取之後,執行main階段的各個外掛來做初始化操作。

粗略的流程大概就是這個樣子,當然裡面還有很多的細節,比如,DataSource是如何獲取的,網路是怎麼配置的,configdrive和metadataservice的區別等等,後面我們可以詳細再看。