openstack镜像:Cloudbase-init的定制化实现

宗政安歌
2023-12-01

在云计算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的区别等等,后面我们可以详细再看。

 类似资料: