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